Merge branch 'main' into hugo/github-project-scopes

This commit is contained in:
hugocasa
2026-10-13 11:04:34 +02:00
committed by GitHub
1128 changed files with 57650 additions and 17374 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ ENV PATH="${PATH}:/usr/local/go/bin"
ENV GO_PATH=/usr/local/go/bin/go
# UV
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.11.24/uv-installer.sh | sh && mv /usr/local/cargo/bin/uv /usr/local/bin/uv
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.13.0/uv-installer.sh | sh && mv /usr/local/cargo/bin/uv /usr/local/bin/uv
ENV TZ=Etc/UTC
+43 -29
View File
@@ -1,25 +1,22 @@
name: AI Evals (scheduled)
# Full ai_evals suites on current models, posted to the AI evals dashboard in
# the windmill-prod workspace (f/ai/ai_evals_dashboard) so quality is tracked
# over time. Weekly, since one pass of every suite at --runs 3 costs about 50M
# tokens per model: every suite runs on MODELS, and global (the mode users get)
# also runs on GLOBAL_EXTRA_MODELS, one flagship per other provider. Run it by
# hand to measure a branch against main.
# The global (AI chat) and cli suites on current models, posted to the AI evals
# dashboard in the windmill-prod workspace (f/ai/ai_evals_dashboard) so quality is
# tracked over time. Weekly: one global pass at --runs 3 is about 45M tokens per
# model. Each mode and model is its own job, so a slow model neither delays nor
# shares a timeout with the others. Run it by hand to measure a branch against
# main, or to include the flow, app and script suites.
on:
schedule:
- cron: "0 3 * * 1"
workflow_dispatch:
inputs:
modes:
description: "Space-separated modes"
default: "global flow app script cli"
description: "Space-separated modes (global, cli, flow, app, script)"
default: "global cli"
models:
description: "Space-separated model aliases (bun run cli -- models)"
default: "sonnet-5.5"
global_extra_models:
description: "Extra model aliases for global mode only"
default: "gpt-6-astra gemini-3.8-flash"
description: "Space-separated model aliases (bun run cli -- models); cli skips those it has no agent for"
default: "sonnet-5.5 opus-5.5 gpt-6.1-sol gpt-6-astra deepseek-v4-pro"
runs:
description: "Runs per case"
default: "3"
@@ -31,8 +28,7 @@ concurrency:
group: ai-evals-scheduled-${{ github.ref }}
env:
MODELS: ${{ inputs.models || 'sonnet-5.5' }}
GLOBAL_EXTRA_MODELS: ${{ inputs.global_extra_models || 'gpt-6-astra gemini-3.8-flash' }}
MODELS: ${{ inputs.models || 'sonnet-5.5 opus-5.5 gpt-6.1-sol gpt-6-astra deepseek-v4-pro' }}
RUNS: ${{ inputs.runs || '3' }}
REASONING: ${{ inputs.reasoning }}
# Routes on the cloud instance are prefixed with their workspace.
@@ -42,14 +38,31 @@ jobs:
setup:
runs-on: ubuntu-latest
outputs:
modes: ${{ steps.modes.outputs.modes }}
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- id: modes
- uses: actions/checkout@v4
with:
sparse-checkout: ai_evals/core
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.0
- id: matrix
env:
MODES: ${{ inputs.modes || 'global flow app script cli' }}
MODES: ${{ inputs.modes || 'global cli' }}
# cli takes only the aliases with a `cli` entry in ai_evals/core/models.ts.
run: |
echo "modes=$(jq -cn --arg m "$MODES" '$m | split(" ")
| map(select(IN("global", "flow", "app", "script", "cli")))')" >> "$GITHUB_OUTPUT"
cli_models=$(bun -e '
import { EVAL_MODELS } from "./ai_evals/core/models.ts";
console.log(JSON.stringify(EVAL_MODELS.filter((m) => m.cli)
.flatMap((m) => [m.id, ...m.aliases]).map((a) => a.toLowerCase())));')
echo "matrix=$(jq -cn --arg modes "$MODES" --arg models "$MODELS" --argjson cli "$cli_models" '
def words: split(" ") | map(select(. != ""));
[ $modes | words[] | select(IN("global", "flow", "app", "script", "cli")) as $mode
| $models | words[]
| select($mode != "cli" or (ascii_downcase | IN($cli[])))
| {mode: $mode, model: .} ]')" >> "$GITHUB_OUTPUT"
evals:
needs: setup
@@ -58,7 +71,7 @@ jobs:
strategy:
fail-fast: false
matrix:
mode: ${{ fromJSON(needs.setup.outputs.modes) }}
include: ${{ fromJSON(needs.setup.outputs.matrix) }}
services:
postgres:
image: postgres:16
@@ -118,10 +131,15 @@ jobs:
working-directory: ./cli
run: bun install && ./gen_wm_client.sh && ./windmill-utils-internal/gen_wm_client.sh
- name: Run ${{ matrix.mode }} evals
- name: Install Codex CLI
if: matrix.mode == 'cli'
run: npm install --global @openai/codex@0.159.3
- name: Run ${{ matrix.mode }} evals on ${{ matrix.model }}
working-directory: ./ai_evals
env:
MODE: ${{ matrix.mode }}
MODEL: ${{ matrix.model }}
WMILL_AI_EVAL_BACKEND_URL: http://localhost:8000
WMILL_AI_EVAL_BACKEND_WORKSPACE: integration-tests
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -131,14 +149,10 @@ jobs:
run: |
bun install
mkdir -p results
models="$MODELS"
[ "$MODE" = global ] && models="$models $GLOBAL_EXTRA_MODELS"
reasoning=()
[ -n "$REASONING" ] && [ "$MODE" != cli ] && reasoning=(--reasoning "$REASONING")
for m in $models; do
bun run cli -- run "$MODE" --model "$m" --runs "$RUNS" "${reasoning[@]}" \
--output "$PWD/results/$MODE-$m.json" || echo "::warning::$MODE on $m errored"
done
bun run cli -- run "$MODE" --model "$MODEL" --runs "$RUNS" "${reasoning[@]}" \
--output "$PWD/results/$MODE-$MODEL.json" || echo "::warning::$MODE on $MODEL errored"
- name: Post results to the dashboard
if: always()
@@ -166,7 +180,7 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: ai-evals-${{ matrix.mode }}
name: ai-evals-${{ matrix.mode }}-${{ matrix.model }}
path: |
ai_evals/logs
ai_evals/results
+2 -2
View File
@@ -63,7 +63,7 @@ jobs:
- uses: denoland/setup-deno@v2
with:
# Pin to the Deno version shipped in the runtime image (Dockerfile) so CI
# Pin to the Deno version shipped in the full runtime image (docker/DockerfileFull) so CI
# tests what production runs, instead of floating on the latest v2.x.
deno-version: 2.2.1
@@ -81,7 +81,7 @@ jobs:
- uses: astral-sh/setup-uv@v7
with:
version: "0.11.24"
version: "0.13.0"
- uses: shivammathur/setup-php@v2
with:
+3 -3
View File
@@ -50,7 +50,7 @@ jobs:
dotnet-version: "9.0.x"
- uses: denoland/setup-deno@v2
with:
# Pin to the Deno version shipped in the runtime image (Dockerfile) so CI
# Pin to the Deno version shipped in the full runtime image (docker/DockerfileFull) so CI
# tests what production runs, instead of floating on the latest v2.x.
deno-version: 2.2.1
- uses: actions/setup-go@v7
@@ -64,7 +64,7 @@ jobs:
node-version: "24"
- uses: astral-sh/setup-uv@v7
with:
version: "0.11.24"
version: "0.13.0"
- uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
@@ -295,4 +295,4 @@ jobs:
# never reaches it. Pin the target dir (matching the cache step above) so
# its own tests run off this compile rather than a second bundled build.
(cd windmill-duckdb-ffi-internal && export CARGO_TARGET_DIR="$PWD/target" && ./build_dev.sh && cargo test --release -p windmill_duckdb_ffi_internal)
DENO_PATH=$(which deno) BUN_PATH=$(which bun) NODE_BIN_PATH=$(which node) GO_PATH=$(which go) UV_PATH=$(which uv) PHP_PATH=$(which php) COMPOSER_PATH=$(which composer) RUBY_PATH=$(which ruby) RUBY_BUNDLE_PATH=$(which bundle) RUBY_GEM_PATH=$(which gem) POWERSHELL_PATH=$(which pwsh) DOTNET_PATH=$(which dotnet) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private,private_registry_test,csharp,php,ruby,mysql,quickjs,mcp,run_inline,smtp,http_trigger --all -- --nocapture --test-threads=10
DENO_PATH=$(which deno) BUN_PATH=$(which bun) NODE_BIN_PATH=$(which node) GO_PATH=$(which go) UV_PATH=$(which uv) PHP_PATH=$(which php) COMPOSER_PATH=$(which composer) RUBY_PATH=$(which ruby) RUBY_BUNDLE_PATH=$(which bundle) RUBY_GEM_PATH=$(which gem) POWERSHELL_PATH=$(which pwsh) DOTNET_PATH=$(which dotnet) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private,private_registry_test,csharp,php,ruby,mysql,quickjs,mcp,run_inline,smtp,http_trigger,openidconnect --all -- --nocapture --test-threads=10
+14 -14
View File
@@ -27,7 +27,7 @@ jobs:
DATABASE_URL: postgres://postgres:changeme@postgres:5432/windmill
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always --health-interval 10s --health-timeout 5s
--health-retries 5 --health-cmd "curl
@@ -111,7 +111,7 @@ jobs:
DATABASE_URL: postgres://postgres:changeme@postgres:5432/windmill
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always --health-interval 10s --health-timeout 5s
--health-retries 5 --health-cmd "curl
@@ -125,7 +125,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -136,7 +136,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -147,7 +147,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -188,7 +188,7 @@ jobs:
DATABASE_URL: postgres://postgres:changeme@postgres:5432/windmill
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always --health-interval 10s --health-timeout 5s
--health-retries 5 --health-cmd "curl
@@ -202,7 +202,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -213,7 +213,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -224,7 +224,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -235,7 +235,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -246,7 +246,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -257,7 +257,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
@@ -268,7 +268,7 @@ jobs:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
MODE: worker
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always
steps:
@@ -309,7 +309,7 @@ jobs:
DATABASE_URL: postgres://postgres:changeme@postgres:5432/windmill
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
WORKER_GROUP: main
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
WORKER_TAGS: bun,go,python3,bash,dependency,flow,nativets
options: >-
--pull always --health-interval 10s --health-timeout 5s
--health-retries 5 --health-cmd "curl
+7 -4
View File
@@ -18,16 +18,19 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish_chat_sdk:
runs-on: ubicloud-standard-8
# Published by npm trusted publishing (OIDC), which npm accepts only from
# GitHub-hosted runners and npm >= 11.5.1: keep both, there is no token to fall back on.
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v7
with:
node-version: "20.x"
node-version: "24.x"
registry-url: "https://registry.npmjs.org"
- run: cd chat-sdk && npm ci && npm run build && npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish_cli:
runs-on: ubicloud-standard-8
steps:
+1 -1
View File
@@ -1,3 +1,3 @@
{
".": "1.821.0"
".": "1.830.0"
}
+12 -2
View File
@@ -33,12 +33,16 @@ Open-source platform for internal tools, workflows, API integrations, background
administers behind `external_instance` data tables and Ducklake catalogs: its invariants (one
lifecycle lock, managed-object markers, the setup gate, per-cluster roles, fork copy ownership)
and how to run one locally
- **Data table viewer roles**: `docs/datatable-viewer-roles.md`, on what a connection naming no
role holds: the default role as a floor, where the viewer comes from, why an admin's roles are
not the viewer's, the per-role-set logins and the order their rows and logins are written in
- **Enterprise**: `docs/enterprise.md` — EE file conventions and PR workflow
- **Operator write rights**: `docs/operator-write-rights.md` — which `operator_settings` flags are
enforced rather than cosmetic, and why a right that is granted-unless-withdrawn needs `Option`
fields and a jsonb merge rather than a serde default
- **Operator builder rights**: `docs/operator-builder-rights.md` — the workspace setting that lets
operators compose flows, what the composition check must cover, and why it costs a full seat
- **Operator builder rights**: `docs/operator-builder-rights.md` — the workspace settings that let
operators compose flows and full-code apps, what the composition check must cover, which
raw-app endpoint stays closed on purpose, and why either right costs a full seat
- **Auth surface**: `docs/auth-surface.md` — credential precedence, session/cache invalidation
scope, which token labels email their owner at expiry, how OAuth login matches `login_type`, and
that every superadmin route refuses `$WM_TOKEN`. Read before designing anything that creates
@@ -90,6 +94,12 @@ are for a plain checkout with nothing running.
- **Login**: `admin@windmill.dev` / `changeme`
- **Instance settings**: navigate to `/#superadmin-settings`
- **Migrations**: use `cargo sqlx migrate add -r <name>` from `backend/` to create new migrations (never generate timestamps manually)
- **Resource types ship through the hub, not migrations.** A new type, a provider's credential
included, is a `hub/<app>/<app>.resource_type.json` in `windmill-labs/windmill-integrations`
and reaches instances by hub sync; a product name its identifier misses (`typesafe` →
"TypeSafe") is that file's `display_name`, not a word in `resourceTypeDisplay.ts`'s map. Only a
type Windmill itself defines and reads as a product object (`ai_skill`, `ai_instruction`) is
also seeded by a migration, so the feature works before a sync. For local testing, insert the row.
### Per-worktree ports and database
+219
View File
@@ -1,5 +1,224 @@
# Changelog
## [1.830.0](https://github.com/windmill-labs/windmill/compare/v1.829.0...v1.830.0) (2026-10-09)
### Features
* add a jobs:run:dependencies token scope for lock generation ([#11643](https://github.com/windmill-labs/windmill/issues/11643)) ([1dc4ed5](https://github.com/windmill-labs/windmill/commit/1dc4ed5e7fb86c9658f1f877e7b92cd9dab5e283))
* let operators compose full-code apps when the workspace grants it ([#11229](https://github.com/windmill-labs/windmill/issues/11229)) ([02e4697](https://github.com/windmill-labs/windmill/commit/02e4697157112581e9e2a9303180077126db714b))
* operators get AI sessions ([#11443](https://github.com/windmill-labs/windmill/issues/11443)) ([338c4e9](https://github.com/windmill-labs/windmill/commit/338c4e921dc3185d886c8b040f253285adf20efb))
* replace the hub_sync script with an opt-in daily server sync ([#11624](https://github.com/windmill-labs/windmill/issues/11624)) ([2b55a8a](https://github.com/windmill-labs/windmill/commit/2b55a8afbc8a86c6cebe97b1cab02c313b986f22))
* retry transient AI provider failures before output reaches readers ([#11623](https://github.com/windmill-labs/windmill/issues/11623)) ([d3ddef0](https://github.com/windmill-labs/windmill/commit/d3ddef0b7ec4705aa578c4eca24b96e9152485bd))
* stop offering deno for new scripts, ship it only on full images ([#11648](https://github.com/windmill-labs/windmill/issues/11648)) ([cda7883](https://github.com/windmill-labs/windmill/commit/cda78830fde1b96bd3de2674e23c245b50e3c051))
### Bug Fixes
* **cli:** count superadmins as able to preserve ownership on push ([#11653](https://github.com/windmill-labs/windmill/issues/11653)) ([70db567](https://github.com/windmill-labs/windmill/commit/70db567a78b1e1bc9e2dcc9ff2139951d778117e))
* harden app secret validation ([#11655](https://github.com/windmill-labs/windmill/issues/11655)) ([8556a7b](https://github.com/windmill-labs/windmill/commit/8556a7bebe093e0bd61c33d67415fd553f0070ad))
* open the chat + menu without waiting on the skills and mcp fetches ([#11645](https://github.com/windmill-labs/windmill/issues/11645)) ([1fea1aa](https://github.com/windmill-labs/windmill/commit/1fea1aa6609d644e02bac8d16186f9a2dfcb63cd))
* say Running on a chat run card only once its job exists ([#11627](https://github.com/windmill-labs/windmill/issues/11627)) ([d046187](https://github.com/windmill-labs/windmill/commit/d046187e3edd01535240c6080b483afe154ae189))
## [1.829.0](https://github.com/windmill-labs/windmill/compare/v1.828.0...v1.829.0) (2026-10-09)
### Features
* add an api base url instance setting for displayed urls ([#11628](https://github.com/windmill-labs/windmill/issues/11628)) ([6acf185](https://github.com/windmill-labs/windmill/commit/6acf1858540e83b65b5218c50c98af692092d22e))
* add Pi template to the AI sandbox picker ([#11619](https://github.com/windmill-labs/windmill/issues/11619)) ([a85d0b7](https://github.com/windmill-labs/windmill/commit/a85d0b76cc494aaa4a484a273ec534bdc2958102))
* agent nits: multi-select, memory-off notice, agent step label ([#11622](https://github.com/windmill-labs/windmill/issues/11622)) ([c52ba2f](https://github.com/windmill-labs/windmill/commit/c52ba2fd30e19986522420ff02fae224a075b4f6))
* export worker cpu, memory and occupancy metrics ([#11629](https://github.com/windmill-labs/windmill/issues/11629)) ([5d90f96](https://github.com/windmill-labs/windmill/commit/5d90f96863b64e9bc88ed35429f8068a6a788d1e))
* let a job see that its worker is draining ([#11612](https://github.com/windmill-labs/windmill/issues/11612)) ([588d846](https://github.com/windmill-labs/windmill/commit/588d8463dfa1c8936b8753b5f0fd794ecb115203))
* let workspace admins delete other users' drafts ([#11644](https://github.com/windmill-labs/windmill/issues/11644)) ([68376fc](https://github.com/windmill-labs/windmill/commit/68376fc011ef6406a820c69217058316514d3f8d))
* per-script resource rollup and heaviest scripts table ([#11631](https://github.com/windmill-labs/windmill/issues/11631)) ([442357d](https://github.com/windmill-labs/windmill/commit/442357dbe8db0c52995572acd7385dedf4efdc42))
* pipeline editor: assets-only view, Fix actions and draft triggers ([#11440](https://github.com/windmill-labs/windmill/issues/11440)) ([3dae553](https://github.com/windmill-labs/windmill/commit/3dae553576ba23b2c1f56e4deac01305c4645c01))
### Bug Fixes
* advertise the actual signing algorithm in OIDC discovery ([#11637](https://github.com/windmill-labs/windmill/issues/11637)) ([98fc65a](https://github.com/windmill-labs/windmill/commit/98fc65a16bbe2bc9515cdd5443304053c4322274))
* ask a workspace for its session backups before pushing to it ([#11641](https://github.com/windmill-labs/windmill/issues/11641)) ([2ea846f](https://github.com/windmill-labs/windmill/commit/2ea846f563f5a77cbd3eae2eddee9e38a3700d00))
* keep instance settings users sub-tabs from being squashed ([#11633](https://github.com/windmill-labs/windmill/issues/11633)) ([fb22e5c](https://github.com/windmill-labs/windmill/commit/fb22e5ce368eba9146e0d51b8fdabb52ca9f68f0))
* keep raw app deploy panel settings shared with the editor ([#11616](https://github.com/windmill-labs/windmill/issues/11616)) ([0a95ea4](https://github.com/windmill-labs/windmill/commit/0a95ea47facaede2545cc4741d4a70c1c847e11a))
* load schedules once per page load, poll critical alerts every 30s ([#11639](https://github.com/windmill-labs/windmill/issues/11639)) ([1b4e686](https://github.com/windmill-labs/windmill/commit/1b4e686b2f5de3138df0c3b6ed627ea0fe0a2f7d))
* name the open workspace settings tab in the page header breadcrumb ([#11617](https://github.com/windmill-labs/windmill/issues/11617)) ([e233908](https://github.com/windmill-labs/windmill/commit/e233908c1e99a246dc7c94fa86ea82c5cbe9d6b3))
* **python:** add missing import-to-package mappings for common modules ([#11638](https://github.com/windmill-labs/windmill/issues/11638)) ([ab8606f](https://github.com/windmill-labs/windmill/commit/ab8606f37921913ef1410da735abb5742c025225))
* send hub script completions to the workspace handlers ([#11613](https://github.com/windmill-labs/windmill/issues/11613)) ([d685332](https://github.com/windmill-labs/windmill/commit/d685332771dcdfc718d7a2077fe1cdb3b323909b))
* set WM_END_USER_EMAIL on direct script and flow runs ([#11636](https://github.com/windmill-labs/windmill/issues/11636)) ([2bdeceb](https://github.com/windmill-labs/windmill/commit/2bdeceba7fb6815cf3150ecb856afb8eb3872e44))
* store a WAC parent's first start and wall duration ([#11625](https://github.com/windmill-labs/windmill/issues/11625)) ([8f28a58](https://github.com/windmill-labs/windmill/commit/8f28a5860595dbe558e6777a06bb97b6ec6a3e67))
* sync back volume files rewritten to the same size ([#11620](https://github.com/windmill-labs/windmill/issues/11620)) ([2758920](https://github.com/windmill-labs/windmill/commit/2758920f1182ddd12e6473a644a4a966a435522e))
* uniform decrypt error and clear stored credentials on logout ([#11632](https://github.com/windmill-labs/windmill/issues/11632)) ([987c321](https://github.com/windmill-labs/windmill/commit/987c321ebcd305df79fa945e941abc2b2e1d3e95))
## [1.828.0](https://github.com/windmill-labs/windmill/compare/v1.827.0...v1.828.0) (2026-10-08)
### Features
* add gpt-6.1-sol to the chat, agent steps and weekly ai evals ([#11584](https://github.com/windmill-labs/windmill/issues/11584)) ([8f7e0c7](https://github.com/windmill-labs/windmill/commit/8f7e0c72848b56fa97f6f0141d930c7d15044864))
* add wmill user list and document post-suspend approvers context ([#11600](https://github.com/windmill-labs/windmill/issues/11600)) ([1c2667c](https://github.com/windmill-labs/windmill/commit/1c2667cd5530925893cf69fd622938b6ffa55d1d))
* ask before minting the frontend sdk token in the raw app editor ([#11604](https://github.com/windmill-labs/windmill/issues/11604)) ([6e948b0](https://github.com/windmill-labs/windmill/commit/6e948b07d13b85e9251c3a200bf149f167649bc4))
* improve data table roles and grants UX ([#11562](https://github.com/windmill-labs/windmill/issues/11562)) ([d7d18f0](https://github.com/windmill-labs/windmill/commit/d7d18f00af4e2df8fcb1362c9439d2250d0ce4b6))
* one page header across routes, and one sidebar for operators and developers ([#11310](https://github.com/windmill-labs/windmill/issues/11310)) ([41162b2](https://github.com/windmill-labs/windmill/commit/41162b270c70ddac6a256bde9acf31a629990e24))
### Bug Fixes
* add retry to runScriptByPathAsync and runScriptByHashAsync ([#11485](https://github.com/windmill-labs/windmill/issues/11485)) ([3f3b1c2](https://github.com/windmill-labs/windmill/commit/3f3b1c2c308ddaba377db45308711e7c660d8775))
* describe exponential retry as multiplier × seconds^attempt ([#11546](https://github.com/windmill-labs/windmill/issues/11546)) ([a2e51cd](https://github.com/windmill-labs/windmill/commit/a2e51cdbaafb7d71b8e8bbd818e40c472098f9ba))
* keep capturing job logs after a non-UTF-8 output line ([#11595](https://github.com/windmill-labs/windmill/issues/11595)) ([0e7d974](https://github.com/windmill-labs/windmill/commit/0e7d974ce9b468353ecb6618dace710704690687))
### Performance Improvements
* load public raw apps without the loading screen ([#11608](https://github.com/windmill-labs/windmill/issues/11608)) ([c09764f](https://github.com/windmill-labs/windmill/commit/c09764fa6516badddbdbb520af32e5d1541cf996))
## [1.827.0](https://github.com/windmill-labs/windmill/compare/v1.826.0...v1.827.0) (2026-10-07)
### Features
* audit instance settings writes, stable audit OTel target ([#11593](https://github.com/windmill-labs/windmill/issues/11593)) ([0792332](https://github.com/windmill-labs/windmill/commit/0792332859a88b1359ea1be64250d38dd071a0a9))
* default new raw apps to react 19 and ask for the data setup ([#11586](https://github.com/windmill-labs/windmill/issues/11586)) ([818ddd5](https://github.com/windmill-labs/windmill/commit/818ddd5d31bd81507e274dd18022c1cdbd9be842))
* export queue delay as OTel and Prometheus metrics ([#11588](https://github.com/windmill-labs/windmill/issues/11588)) ([7565349](https://github.com/windmill-labs/windmill/commit/75653496e542550039cbe5c413d8fcb9d395cea8))
* pause a worker group without stopping its workers ([#11596](https://github.com/windmill-labs/windmill/issues/11596)) ([95c4b30](https://github.com/windmill-labs/windmill/commit/95c4b3096cf10c1fe59de7a1a6876dfb5f02c39f))
* run AI decision steps on OpenAI's Decisions API ([#11590](https://github.com/windmill-labs/windmill/issues/11590)) ([046df9e](https://github.com/windmill-labs/windmill/commit/046df9e44db2f2fae3059ccd7a3d6c6955ee8971))
### Bug Fixes
* avoid URLSearchParams.keys() so the frontend check passes ([#11599](https://github.com/windmill-labs/windmill/issues/11599)) ([fc6c84c](https://github.com/windmill-labs/windmill/commit/fc6c84c6974bba1850e90a088fad5460c8c93ba3))
* let recover: true from the error handler turn nested failures green ([#11559](https://github.com/windmill-labs/windmill/issues/11559)) ([03e484e](https://github.com/windmill-labs/windmill/commit/03e484e59757c0d4d6f74511d9aa5a1e2f94af67))
* run dependency resolution and build steps under nsjail ([#11609](https://github.com/windmill-labs/windmill/issues/11609)) ([a238d01](https://github.com/windmill-labs/windmill/commit/a238d01ef6a8c285aef6886c974904f24339f7a2))
* scope the python wheel cache to workspaces with their own registry ([#11597](https://github.com/windmill-labs/windmill/issues/11597)) ([14381ce](https://github.com/windmill-labs/windmill/commit/14381cefee6fb2b0ece52fbf0001c2ce61bde1a1))
* type snowflake columns in database manager insert and alter forms ([#11578](https://github.com/windmill-labs/windmill/issues/11578)) ([f2fb156](https://github.com/windmill-labs/windmill/commit/f2fb15603b2e0d11bd5d04dd675212a5e4a7b9d7))
## [1.826.0](https://github.com/windmill-labs/windmill/compare/v1.825.0...v1.826.0) (2026-10-07)
### Features
* count OIDC signatures and reuse server-side tokens ([#11556](https://github.com/windmill-labs/windmill/issues/11556)) ([e277735](https://github.com/windmill-labs/windmill/commit/e277735788c260239a063063459776ec01f7d907))
* isolate the raw-app editor preview when the app opts into sandboxing ([#11572](https://github.com/windmill-labs/windmill/issues/11572)) ([fa25397](https://github.com/windmill-labs/windmill/commit/fa253976e213c1053d1832c1d1fb7bedf7ce8c45))
* job_token_scopes OIDC claim ([#11551](https://github.com/windmill-labs/windmill/issues/11551)) ([d493eff](https://github.com/windmill-labs/windmill/commit/d493eff237f96a353fb6f5715a15bcad61d24433))
* set up a new app in one modal over its AI session, fix its deploy ([#11582](https://github.com/windmill-labs/windmill/issues/11582)) ([7190185](https://github.com/windmill-labs/windmill/commit/71901852fb3cc40515d6675a0a88cd158e942d56))
### Bug Fixes
* export getWorkspace and other client helpers as named exports ([#11581](https://github.com/windmill-labs/windmill/issues/11581)) ([bf201be](https://github.com/windmill-labs/windmill/commit/bf201be11e95f0fc3e12353531f25bb3ceb0f8f3))
* give the dbt workspace settings page a header like its siblings ([#11576](https://github.com/windmill-labs/windmill/issues/11576)) ([38aa4ea](https://github.com/windmill-labs/windmill/commit/38aa4eaa1200db52e67a18ef9a7c5dc4d60a4948))
* ignore schedule missed-run counters in workspace compare ([#11570](https://github.com/windmill-labs/windmill/issues/11570)) ([eab3dd5](https://github.com/windmill-labs/windmill/commit/eab3dd5a52bc8faf57bb84c85bd74eb20ebd8ec7))
* keep chat tool cards collapsed the way the user left them ([#11575](https://github.com/windmill-labs/windmill/issues/11575)) ([c71ecad](https://github.com/windmill-labs/windmill/commit/c71ecad6f9cf3727a305b5f9038dcbe6a54398b8))
* keep run status buttons from selecting the flow input node ([#11579](https://github.com/windmill-labs/windmill/issues/11579)) ([8661797](https://github.com/windmill-labs/windmill/commit/866179730a9798346d3950f27dd625c3358e690a))
* make every trigger and schedule editor control respect read-only mode ([#11569](https://github.com/windmill-labs/windmill/issues/11569)) ([52a99c3](https://github.com/windmill-labs/windmill/commit/52a99c3047e1add477e36919b15a745f7d2604a0))
* strip NUL from ai agent output and job args before jsonb writes ([#11568](https://github.com/windmill-labs/windmill/issues/11568)) ([cf4bec6](https://github.com/windmill-labs/windmill/commit/cf4bec611f6df8a45b238afe5b8da3e3a5748bf9))
## [1.825.0](https://github.com/windmill-labs/windmill/compare/v1.824.1...v1.825.0) (2026-10-06)
### Features
* choose build with AI or code when creating a raw app ([#11560](https://github.com/windmill-labs/windmill/issues/11560)) ([431f861](https://github.com/windmill-labs/windmill/commit/431f86138815fce432e282e8ac495953c5ecf98a))
* confine jobs:read to the runnable paths it names ([#11550](https://github.com/windmill-labs/windmill/issues/11550)) ([b371af3](https://github.com/windmill-labs/windmill/commit/b371af31c96e6890fe9223233d2c6e53ddea67d4))
* open a run as a pushed page on the narrow runs page ([#11541](https://github.com/windmill-labs/windmill/issues/11541)) ([fd8de45](https://github.com/windmill-labs/windmill/commit/fd8de45cc7cfcba2c374dd86f87f4d3e8aec6ded))
* say a canceled team plan is canceled, not past due ([#11539](https://github.com/windmill-labs/windmill/issues/11539)) ([18e44d3](https://github.com/windmill-labs/windmill/commit/18e44d31742b8d16852b8c6ae663979666e064d7))
### Bug Fixes
* group raw app edits that carry a file diff in the ai chat ([#11558](https://github.com/windmill-labs/windmill/issues/11558)) ([5912d30](https://github.com/windmill-labs/windmill/commit/5912d300a550a33674fd73740d613d1b434fbba1))
* honor custom timeout in setup phases and name the limit hit ([#11557](https://github.com/windmill-labs/windmill/issues/11557)) ([4fd4f76](https://github.com/windmill-labs/windmill/commit/4fd4f76d0df740cb3eebed1a0625b970484807fc))
* search slow runs filters by time windows instead of timing out ([#11549](https://github.com/windmill-labs/windmill/issues/11549)) ([2bf9cfc](https://github.com/windmill-labs/windmill/commit/2bf9cfcd59e1101695160524c31a4da1a41699dc))
* serve the raw-app preview shell sandboxed, load a blob copy in the editor ([#11554](https://github.com/windmill-labs/windmill/issues/11554)) ([5f92daa](https://github.com/windmill-labs/windmill/commit/5f92daab6d0ecac30dd384e1b0f302af13fdd9ab))
* simplify the run page AI card to a prompt and a chat button ([#11561](https://github.com/windmill-labs/windmill/issues/11561)) ([8c74f75](https://github.com/windmill-labs/windmill/commit/8c74f75de3fa62b07186ca4f56dae4a7e4758034))
## [1.824.1](https://github.com/windmill-labs/windmill/compare/v1.824.0...v1.824.1) (2026-10-05)
### Bug Fixes
* keep monaco's diff engine out of the app shell bundle ([#11542](https://github.com/windmill-labs/windmill/issues/11542)) ([0908dee](https://github.com/windmill-labs/windmill/commit/0908dee897e0f87b97418a23ede3662d96270340))
## [1.824.0](https://github.com/windmill-labs/windmill/compare/v1.823.1...v1.824.0) (2026-10-05)
### Features
* add an AI decision flow step (TypeSafe's Jev, Cloudflare's Clef) ([#11474](https://github.com/windmill-labs/windmill/issues/11474)) ([3cba8a7](https://github.com/windmill-labs/windmill/commit/3cba8a7e4cca3ef20ba73a7dad79d892bdc9fed8))
* add notion oauth provider ([#11528](https://github.com/windmill-labs/windmill/issues/11528)) ([8b2dc1e](https://github.com/windmill-labs/windmill/commit/8b2dc1e46c7f4e3859263f18b686ce6f3ce6fd30))
* **ai-chat:** show per-file diffs for raw app edits ([#11521](https://github.com/windmill-labs/windmill/issues/11521)) ([ec0883a](https://github.com/windmill-labs/windmill/commit/ec0883a627b06b6ba2a393d5cf66ddf6ebc4cd0d))
* bill team-plan service accounts as half a seat ([#11298](https://github.com/windmill-labs/windmill/issues/11298)) ([3aee181](https://github.com/windmill-labs/windmill/commit/3aee1815746f0116f5662f162ad1e234717af90d))
* card layout and load-more for the audit logs page ([#11507](https://github.com/windmill-labs/windmill/issues/11507)) ([af1a29a](https://github.com/windmill-labs/windmill/commit/af1a29a3cb33386f61a759ec0dd5eec0ccefefc2))
* offer audit-log and drive-metadata scopes for google oauth connects ([#11527](https://github.com/windmill-labs/windmill/issues/11527)) ([c4e7c71](https://github.com/windmill-labs/windmill/commit/c4e7c714e455f958d9a927c4bc4eb23256324780))
* offer slack read scopes for files, user groups, emoji and dms ([#11526](https://github.com/windmill-labs/windmill/issues/11526)) ([b5fda7d](https://github.com/windmill-labs/windmill/commit/b5fda7d5af7105fde69beb68410984350af2ac7e))
### Bug Fixes
* bound s3 ai attachment downloads before encoding ([#11534](https://github.com/windmill-labs/windmill/issues/11534)) ([92fbfc0](https://github.com/windmill-labs/windmill/commit/92fbfc03d219544c16e8f7db47a547f9ff402c27))
* collapse queued and running chat tool calls into a waiting row ([#11523](https://github.com/windmill-labs/windmill/issues/11523)) ([4f30982](https://github.com/windmill-labs/windmill/commit/4f30982ce3f7abc64a31890f8e88c31c1c2e0803))
* disable postgres triggers whose replication slot was invalidated ([#11536](https://github.com/windmill-labs/windmill/issues/11536)) ([85248ee](https://github.com/windmill-labs/windmill/commit/85248eee786b633def40c42b6007fc7b907fb09e))
* evaluate field conditions and step test inputs in QuickJS ([#11487](https://github.com/windmill-labs/windmill/issues/11487)) ([c962d37](https://github.com/windmill-labs/windmill/commit/c962d3766b1a250ba960e413556890d5919ebc94))
* flush proxied responses before the dev supervisor closes the client ([#11530](https://github.com/windmill-labs/windmill/issues/11530)) ([cefb195](https://github.com/windmill-labs/windmill/commit/cefb1953764e714d79556e2f8065cfbec78acb86))
* label the default slack scopes and list them first in the connect dialog ([#11529](https://github.com/windmill-labs/windmill/issues/11529)) ([e76781c](https://github.com/windmill-labs/windmill/commit/e76781cc2709fda08403e14c1a0a01957e430db1))
* run each ai eval model in its own job and let the docs tools reach the backend ([#11533](https://github.com/windmill-labs/windmill/issues/11533)) ([222dad1](https://github.com/windmill-labs/windmill/commit/222dad1d8cc9cbb6925fdff709e00a49bb63bc4a))
* show the flow row edit button to builder operators ([#11535](https://github.com/windmill-labs/windmill/issues/11535)) ([6c4e34c](https://github.com/windmill-labs/windmill/commit/6c4e34cd0dd9b4329084214c40695f5915947cc2))
## [1.823.1](https://github.com/windmill-labs/windmill/compare/v1.823.0...v1.823.1) (2026-10-05)
### Bug Fixes
* python results with a KeyError-raising __getattr__ fail the job ([#11517](https://github.com/windmill-labs/windmill/issues/11517)) ([3fff1bd](https://github.com/windmill-labs/windmill/commit/3fff1bd3dcedce22c58d988ad2e725e3d4e96e0e))
* stream the ai chat compaction request ([#11514](https://github.com/windmill-labs/windmill/issues/11514)) ([289d3c3](https://github.com/windmill-labs/windmill/commit/289d3c3941c2d9997bf0476bf9bfdfd948542c55))
## [1.823.0](https://github.com/windmill-labs/windmill/compare/v1.822.0...v1.823.0) (2026-10-04)
### Features
* redesign the service logs page ([#11506](https://github.com/windmill-labs/windmill/issues/11506)) ([0f65df2](https://github.com/windmill-labs/windmill/commit/0f65df24d2cabd9d8daa71c103969e6392e37b4f))
### Bug Fixes
* apply the pg keepalive settings to the postgres trigger connection ([#11512](https://github.com/windmill-labs/windmill/issues/11512)) ([33f6de0](https://github.com/windmill-labs/windmill/commit/33f6de0cd20f45ff56770f946a4731e5b13bf677))
* bound the datatable migration lock wait and reap a dead holder ([#11510](https://github.com/windmill-labs/windmill/issues/11510)) ([711e08c](https://github.com/windmill-labs/windmill/commit/711e08c1d20a326142235c83d8805b7990bf6e6d))
* bound the pg cached-connection reset probe so a vanished server fails fast ([#11505](https://github.com/windmill-labs/windmill/issues/11505)) ([d4a423f](https://github.com/windmill-labs/windmill/commit/d4a423f567e1fb5e21016a2be61d858ab61a4d4f))
* cancel an abandoned pg query and close failed connections cleanly ([#11511](https://github.com/windmill-labs/windmill/issues/11511)) ([26856b8](https://github.com/windmill-labs/windmill/commit/26856b8061c28eade191c7d85a32b74ca44c4fea))
* delete a flow chat turn with its flow run, not its step jobs ([#11477](https://github.com/windmill-labs/windmill/issues/11477)) ([35ec16d](https://github.com/windmill-labs/windmill/commit/35ec16d12728531ab90632116913e98f80d1cc05))
* drop a fork's datatable database despite connected sessions ([#11509](https://github.com/windmill-labs/windmill/issues/11509)) ([fa419af](https://github.com/windmill-labs/windmill/commit/fa419af9b3f7d65a607bb8ea2bcea58223f743c4))
## [1.822.0](https://github.com/windmill-labs/windmill/compare/v1.821.0...v1.822.0) (2026-10-03)
### Features
* add a cancel-only jobs:cancel token scope, optionally path-scoped ([#11479](https://github.com/windmill-labs/windmill/issues/11479)) ([4bc7e0d](https://github.com/windmill-labs/windmill/commit/4bc7e0d7bad22e9e1a3532ca747ed863f90213ba))
* add an instance setting routing all dependency jobs to one tag ([#11486](https://github.com/windmill-labs/windmill/issues/11486)) ([3d1d249](https://github.com/windmill-labs/windmill/commit/3d1d2495567274b4c48babb374e7716c4ed24ecc))
* add trigger, tag, run-as and digest claims to job OIDC tokens ([#11481](https://github.com/windmill-labs/windmill/issues/11481)) ([4beb1f9](https://github.com/windmill-labs/windmill/commit/4beb1f9420524425c354e82729e4e35c5bf65451))
* log pg job progress, warn on stalls, detect dead db connections ([#11491](https://github.com/windmill-labs/windmill/issues/11491)) ([d722772](https://github.com/windmill-labs/windmill/commit/d7227726be2b082bbfb204abb75a3ff081db77de))
* read the OIDC signing key from a file and rotate it ([#11482](https://github.com/windmill-labs/windmill/issues/11482)) ([d949484](https://github.com/windmill-labs/windmill/commit/d949484e7ba9911cf128387e096f78c917fb3f35))
* replace the AI input filling toggle with an additional prompt ([#11501](https://github.com/windmill-labs/windmill/issues/11501)) ([e952298](https://github.com/windmill-labs/windmill/commit/e952298f84d04cbb11f0c44c32435f0b711bf3bf))
* restricted job tokens per script and flow ([#11484](https://github.com/windmill-labs/windmill/issues/11484)) ([e7fc1b2](https://github.com/windmill-labs/windmill/commit/e7fc1b2e2e9b358b414d0ca0eaf2753e142dded7))
### Bug Fixes
* keep a resource default set in the schema when the script is redeployed ([#11495](https://github.com/windmill-labs/windmill/issues/11495)) ([68f8f19](https://github.com/windmill-labs/windmill/commit/68f8f19b33768451ebab267b36f931a6f386c678))
* let instances withhold signing secrets from the settings API ([#11483](https://github.com/windmill-labs/windmill/issues/11483)) ([99e96d3](https://github.com/windmill-labs/windmill/commit/99e96d3f781decda8fed2cbd5409cbc5c3520eaa))
* let legacy draft-only items be discarded from the home page ([#11488](https://github.com/windmill-labs/windmill/issues/11488)) ([98274a7](https://github.com/windmill-labs/windmill/commit/98274a73361618ff37a929584e5b5f519b71a912))
* never reuse a pg connection a script left inside a transaction ([#11497](https://github.com/windmill-labs/windmill/issues/11497)) ([b7f74cd](https://github.com/windmill-labs/windmill/commit/b7f74cd56294cdb7052e311c5a68de9ee0bb4122))
* read inet and cidr results with their prefix, including arrays ([#11476](https://github.com/windmill-labs/windmill/issues/11476)) ([ae093b7](https://github.com/windmill-labs/windmill/commit/ae093b7666cefc3777be0e45144bb272732846d0))
* stop the pg executor cache from pinning a pooler slot ([#11490](https://github.com/windmill-labs/windmill/issues/11490)) ([eed7e7d](https://github.com/windmill-labs/windmill/commit/eed7e7d9e6bb375daebbb323b1288c36a278f977))
* unstick postgres jobs on large results with custom-typed columns ([#11475](https://github.com/windmill-labs/windmill/issues/11475)) ([14801fd](https://github.com/windmill-labs/windmill/commit/14801fdd68407add824bfa2c679c0e8cb4788610))
### Performance Improvements
* keep a pg executor connection per database ([#11492](https://github.com/windmill-labs/windmill/issues/11492)) ([013b302](https://github.com/windmill-labs/windmill/commit/013b302d484b967443cbf747fb9f2ecbb1145033))
## [1.821.0](https://github.com/windmill-labs/windmill/compare/v1.820.0...v1.821.0) (2026-10-01)
+3 -6
View File
@@ -83,7 +83,6 @@ COPY /python-client/docs/ /frontend/static/pydocs/
RUN npm run generate-backend-client
ENV NODE_OPTIONS "--max-old-space-size=8192"
ARG VITE_BASE_URL ""
# Must be declared for the build-arg to reach the bundle. See frontend/svelte.config.js.
ARG WM_BUILD_VERSION=""
# Read more about macro in docker/dev.nu
@@ -142,10 +141,10 @@ FROM ${DEBIAN_IMAGE}
ARG TARGETPLATFORM
ARG POWERSHELL_VERSION=7.5.0
ARG KUBECTL_VERSION=1.36.2
ARG KUBECTL_VERSION=1.37.1
ARG HELM_VERSION=3.21.4
# NOTE: If changing, also change go version in workspace dependencies template at WorkspaceDependenciesEditor.svelte
ARG GO_VERSION=1.26.8
ARG GO_VERSION=1.27.1
ARG APP=/usr/src/app
ARG WITH_POWERSHELL=true
ARG WITH_KUBECTL=true
@@ -242,7 +241,7 @@ ENV PATH="${PATH}:/usr/local/go/bin"
ENV GO_PATH=/usr/local/go/bin/go
# Install UV
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.11.24/uv-installer.sh | sh && mv /root/.local/bin/uv /usr/local/bin/uv
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.13.0/uv-installer.sh | sh && mv /root/.local/bin/uv /usr/local/bin/uv
# Preinstall python runtimes to temp build location (will copy with world-writable perms later)
# --compile-bytecode precompiles the stdlib to .pyc so jobs don't recompile it on every run
@@ -287,8 +286,6 @@ COPY --from=builder /frontend/build /static_frontend
COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
COPY --from=windmill_duckdb_ffi_internal_builder /windmill-duckdb-ffi-internal/target/release/libwindmill_duckdb_ffi_internal.so ${APP}/libwindmill_duckdb_ffi_internal.so
COPY --from=denoland/deno:2.2.1 --chmod=755 /usr/bin/deno /usr/bin/deno
COPY --from=oven/bun:1.4.0 /usr/local/bin/bun /usr/bin/bun
# Install windmill CLI
+2 -2
View File
@@ -150,7 +150,7 @@ You can run scripts locally by passing the right environment variables for the `
- **Frontend**: Svelte 5
- **Sandboxing**: [nsjail](https://github.com/google/nsjail) and PID namespace isolation
- **Runtimes**:
- TypeScript/JavaScript: Bun (default) and Deno
- TypeScript/JavaScript: Bun (default); Deno only on the `windmill-full` images
- Python: python3 with uv for dependency management
- Go, Bash, PowerShell, PHP, Rust, C#, Java, Ansible
@@ -318,7 +318,7 @@ running options.
This will also avoid compile time issue with sqlx's `query!` macro.
2. (optional, linux only) Install [nsjail](https://github.com/google/nsjail) and have it accessible in
your PATH
3. Install bun, deno and python3 (+ any languages you want to use), have the bins at `/usr/bin/bun`,`/usr/bin/deno`, and
3. Install bun and python3 (+ any languages you want to use), have the bins at `/usr/bin/bun` and
`/usr/local/bin/python3` or set the corresponding environment variables.
4. (optional) Install the [lld linker](https://lld.llvm.org/)
5. Go to `frontend/`:
+21 -1
View File
@@ -89,7 +89,21 @@ Notes:
- the command also prints accepted alias spellings such as `gpt-4o`, `gpt-55`, `claude-opus-4.6`, and `claude-haiku-4.5`
- frontend modes (`flow`, `script`, `app`, `global`) can use Anthropic, OpenAI, Gemini, and DeepSeek-backed aliases
- `cli` mode always uses the Anthropic agent SDK, so only Anthropic aliases are valid there
- `cli` mode runs a coding agent over the workspace, chosen by the alias's `cli` entry; aliases without one are rejected there:
| Agent | Models | Label | Needs |
| --- | --- | --- | --- |
| Claude Code (`@anthropic-ai/claude-agent-sdk`) | Claude aliases | `anthropic:<model>` | `ANTHROPIC_API_KEY` |
| Claude Code on DeepSeek's Anthropic-compatible endpoint | `deepseek-v4-pro` | `claude-code:<model>` | `DEEPSEEK_API_KEY` |
| Codex (`codex exec --json`) | `gpt-6.1-sol`, `gpt-6-astra` | `codex:<model>` | `codex` on `PATH` (CI pins 0.159.3), `OPENAI_API_KEY` |
Codex runs with a throwaway `HOME`, so your own `~/.codex` config and skills stay out of the run. It has no
Skill tool: it finds `.agents/skills` on its own and loads a skill by reading its `SKILL.md`, so the trace
records any command that touches `.agents/skills/<name>/SKILL.md` as a `Skill` call to `<name>`, just
before that command, or just after it when the command mutates something before reading the skill. Its shell commands are recorded as `Bash` and its patches as `Edit`, so the
`invokes skill … before first mutation` checks compare the same things for both agents. Codex has no
turn cap; a run stops at `maxTurns` rounds of tool calls (parallel calls count once) and fails, as a
Claude Code run does at its cap.
- the judge model is separate and currently defaults to `claude-sonnet-5-5`; use `--skip-judge` for deterministic-only runs
## Case Format
@@ -164,6 +178,12 @@ the decrypted value, exactly as against a real backend. The chat's read path pas
Seed a recognizable secret (the existing fixture uses `sk_live_do_not_leak_me`) and
assert it via `valueExcludes` to catch a leak.
`runtime.userAnswers` scripts the user's side of `askUserQuestion` in a global case: one
answer per question, in the order they are asked, and a question past the last answer is
dismissed, so `userAnswers: []` dismisses every question. Without it the tool reports that
it cannot ask, and the model usually carries on with its own guess, which makes "asks
before creating anything" impossible to assert.
`toolExpect.toolCallArgs` entries support `sharedByAtLeast: <n>`: at least `n` recorded
calls to that tool must carry the same non-blank string in the field. Use it for calls that
have to share an identifier, like two test runs of one chat conversation.
+71
View File
@@ -0,0 +1,71 @@
import { describe, expect, it } from "bun:test";
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { runCodex, toToolInvocations, unwrapShellCommand } from "./codex";
describe("unwrapShellCommand", () => {
it("strips the login-shell wrapper Codex reports", () => {
expect(unwrapShellCommand(`/usr/bin/zsh -lc 'cat .agents/skills/x/SKILL.md'`)).toBe(
"cat .agents/skills/x/SKILL.md"
);
expect(unwrapShellCommand(`/bin/bash -lc "printf 'hi' > \\"a b\\""`)).toBe(
`printf 'hi' > "a b"`
);
expect(unwrapShellCommand(`/bin/bash -lc 'echo '\\''x'\\'''`)).toBe(`echo 'x'`);
expect(unwrapShellCommand(`bash -lc 'wmill sync push'`)).toBe("wmill sync push");
expect(unwrapShellCommand(`/bin/bash -lc 'rg -g '"'"'!x'"'"' f'`)).toBe(`rg -g '!x' f`);
});
});
describe("toToolInvocations", () => {
it("records reading a SKILL.md as a Skill call before the command", () => {
const tools = toToolInvocations({
type: "command_execution",
command: `/bin/bash -lc 'sed -n 1,200p .agents/skills/write-script-bun/SKILL.md && mkdir f'`,
});
expect(tools.map((tool) => [tool.tool, tool.input])).toEqual([
["Skill", { skill: "write-script-bun" }],
["Bash", { command: "sed -n 1,200p .agents/skills/write-script-bun/SKILL.md && mkdir f" }],
]);
});
it("records a skill read after a mutation earlier in the same command", () => {
const tools = toToolInvocations({
type: "command_execution",
command: `/bin/bash -lc 'printf main > f/a.ts && cat .agents/skills/write-script-bun/SKILL.md'`,
});
expect(tools.map((tool) => tool.tool)).toEqual(["Bash", "Skill"]);
});
it("maps a patch to Edit so it counts as a mutation", () => {
expect(
toToolInvocations({ type: "file_change", changes: [{ path: "a.ts", kind: "add" }] })[0]
).toMatchObject({ tool: "Edit", input: { changes: [{ path: "a.ts", kind: "add" }] } });
});
});
describe("runCodex", () => {
it("keeps parallel tool calls in the order they started", async () => {
const dir = await mkdtemp(join(tmpdir(), "fake-codex-"));
const events = [
{ type: "item.started", item: { id: "a", type: "command_execution", command: "mkdir f" } },
{ type: "item.started", item: { id: "b", type: "command_execution", command: "cat .agents/skills/s/SKILL.md" } },
{ type: "item.completed", item: { id: "b", type: "command_execution", command: "cat .agents/skills/s/SKILL.md" } },
{ type: "item.completed", item: { id: "a", type: "command_execution", command: "mkdir f" } },
{ type: "item.completed", item: { id: "c", type: "agent_message", text: "done" } },
{ type: "turn.completed", usage: { input_tokens: 10, output_tokens: 2 } },
];
const lines = events.map((event) => `printf '%s\\n' '${JSON.stringify(event)}'`).join("\n");
await writeFile(join(dir, "codex"), `#!/bin/sh\ncat > /dev/null\n${lines}\n`);
await chmod(join(dir, "codex"), 0o755);
try {
const result = await runCodex("p", dir, 12, "m", { PATH: `${dir}:${process.env.PATH}` });
expect(result.toolsUsed.map((tool) => tool.tool)).toEqual(["Bash", "Skill", "Bash"]);
expect(result.output).toBe("done");
expect(result.tokenUsage).toEqual({ prompt: 10, completion: 2, total: 12 });
} finally {
await rm(dir, { recursive: true, force: true });
}
});
});
+241
View File
@@ -0,0 +1,241 @@
import { spawn } from "node:child_process";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { createInterface } from "node:readline";
import type { BenchmarkTokenUsage, CliToolInvocation } from "../../core/types";
import { isLikelyMutatingBashCommand } from "./mutation";
export interface AgentRunResult {
output: string;
toolsUsed: CliToolInvocation[];
assistantMessageCount: number;
tokenUsage: BenchmarkTokenUsage | null;
finalContextTokens: number | null;
}
interface CodexItem {
type?: string;
text?: string;
command?: string;
changes?: { path?: string; kind?: string }[];
[key: string]: unknown;
}
interface CodexEvent {
type?: string;
item?: CodexItem;
usage?: { input_tokens?: number; output_tokens?: number };
message?: string;
error?: { message?: string };
}
const SKILL_FILE_PATTERN = /\.agents\/skills\/([^/\s'"`*?[]+)\/SKILL\.md/g;
// Drives `codex exec` and maps its events onto the Claude Code tool vocabulary
// the validators read: shell commands become `Bash`, patches `Edit`, and
// reading `.agents/skills/<name>/SKILL.md` (how Codex loads a skill) becomes a
// `Skill` call recorded just before that command.
export async function runCodex(
prompt: string,
cwd: string,
maxTurns: number,
model: string,
env: Record<string, string>
): Promise<AgentRunResult> {
// A fresh HOME keeps the user's ~/.codex config and ~/.agents/skills out of the run.
const home = await mkdtemp(join(tmpdir(), "wmill-cli-benchmark-codex-home-"));
const result: AgentRunResult = {
output: "",
toolsUsed: [],
assistantMessageCount: 0,
tokenUsage: null,
finalContextTokens: null,
};
const messages: string[] = [];
let failure: string | null = null;
let lastError: string | null = null;
let stderr = "";
try {
const child = spawn(
"codex",
[
"exec",
"--json",
"--ephemeral",
"--skip-git-repo-check",
"--dangerously-bypass-approvals-and-sandbox",
"--model",
model,
"--cd",
cwd,
"-",
],
{
cwd,
env: {
...env,
HOME: home,
CODEX_HOME: home,
CODEX_API_KEY: env.OPENAI_API_KEY ?? "",
},
stdio: ["pipe", "pipe", "pipe"],
}
);
// Without this, a missing `codex` binary leaves the stdout loop waiting forever.
await new Promise<void>((resolve, reject) => {
child.once("spawn", resolve);
child.once("error", reject);
});
child.stdin.on("error", () => {});
child.stdin.end(prompt);
child.stderr.on("data", (chunk) => {
stderr = (stderr + chunk).slice(-4000);
});
const exited = new Promise<number | null>((resolve, reject) => {
child.on("error", reject);
child.on("close", resolve);
});
// Codex has no turn cap. A turn starts when the agent issues tool calls with
// none in flight, so parallel calls count once, as they do for Claude Code.
// Claude Code's cap includes the final reply, so the maxTurns-th tool round is
// already over it.
// ponytail: parallel calls that finish before the next one starts count as
// separate turns; count model calls if Codex ever reports them.
let turns = 0;
let inFlight = 0;
let capped = false;
// Parallel calls complete out of order; the trace keeps the order they started in.
const slots = new Map<string, number>();
const ordered: CliToolInvocation[][] = [];
const slotFor = (item: CodexItem) => {
const id = typeof item.id === "string" ? item.id : undefined;
if (id !== undefined && slots.has(id)) {
return slots.get(id)!;
}
ordered.push([]);
if (id !== undefined) {
slots.set(id, ordered.length - 1);
}
return ordered.length - 1;
};
for await (const line of createInterface({ input: child.stdout })) {
const event = parseEvent(line);
if (!event) {
continue;
}
const item = event.item;
if (event.type === "item.started" && item && isToolItem(item)) {
if (inFlight === 0) {
turns += 1;
}
inFlight += 1;
slotFor(item);
if (turns >= maxTurns && !capped) {
capped = true;
child.kill("SIGTERM");
}
} else if (event.type === "item.completed" && item) {
if (item.type === "agent_message") {
result.assistantMessageCount += 1;
if (typeof item.text === "string") {
messages.push(item.text);
}
} else if (isToolItem(item)) {
inFlight = Math.max(0, inFlight - 1);
ordered[slotFor(item)] = toToolInvocations(item);
}
} else if (event.type === "turn.completed" && event.usage) {
const prompt = event.usage.input_tokens ?? 0;
const completion = event.usage.output_tokens ?? 0;
result.tokenUsage = { prompt, completion, total: prompt + completion };
} else if (event.type === "turn.failed") {
failure = event.error?.message ?? JSON.stringify(event);
} else if (event.type === "error") {
// Also sent for retries Codex recovers from ("Reconnecting... 1/5").
lastError = event.message ?? JSON.stringify(event);
}
}
result.toolsUsed = ordered.flat();
const code = await exited;
if (failure) {
throw new Error(`codex: ${failure}`);
}
// Fail the attempt, as Claude Code does at its cap.
if (capped) {
throw new Error(`codex: reached maximum number of turns (${maxTurns})`);
}
if (code !== 0) {
throw new Error(`codex exited with ${code}: ${lastError ?? stderr.trim()}`);
}
} finally {
await rm(home, { recursive: true, force: true });
}
result.output = messages.join("\n");
return result;
}
export function toToolInvocations(item: CodexItem): CliToolInvocation[] {
const timestamp = Date.now();
if (item.type === "command_execution" && typeof item.command === "string") {
const command = unwrapShellCommand(item.command);
// A skill read counts as preceding the command only when nothing before it in
// the command mutates; otherwise `printf x > f && cat SKILL.md` would pass a
// skill-before-first-mutation check.
const before: string[] = [];
const after: string[] = [];
for (const match of command.matchAll(SKILL_FILE_PATTERN)) {
const skill = match[1]!;
if (before.includes(skill) || after.includes(skill)) {
continue;
}
(isLikelyMutatingBashCommand(command.slice(0, match.index)) ? after : before).push(skill);
}
const skillCall = (skill: string) => ({ tool: "Skill", input: { skill }, timestamp });
return [
...before.map(skillCall),
{ tool: "Bash", input: { command }, timestamp },
...after.map(skillCall),
];
}
if (item.type === "file_change") {
return [{ tool: "Edit", input: { changes: item.changes ?? [] }, timestamp }];
}
const { id: _id, type, status: _status, ...input } = item;
return [{ tool: String(type), input, timestamp }];
}
// Codex reports commands as run through the user's login shell, e.g.
// `/usr/bin/zsh -lc 'cat SKILL.md'`.
export function unwrapShellCommand(command: string): string {
const match = command.match(/^(?:\S*\/)?(?:ba|z)?sh -l?c (['"])([\s\S]*)\1$/);
if (!match) {
return command;
}
const body = match[2]!;
return match[1] === "'"
? body.replaceAll(`'\\''`, "'").replaceAll(`'"'"'`, "'")
: body.replace(/\\(["\\$`])/g, "$1");
}
function isToolItem(item: CodexItem): boolean {
return !["agent_message", "reasoning", "todo_list", "error"].includes(item.type ?? "");
}
function parseEvent(line: string): CodexEvent | null {
try {
const value = JSON.parse(line);
return value && typeof value === "object" ? (value as CodexEvent) : null;
} catch {
return null;
}
}
+10
View File
@@ -0,0 +1,10 @@
export function isLikelyMutatingBashCommand(command: string): boolean {
return (
/\b(?:mkdir|touch|rm|mv|cp|install|tee)\b/.test(command) ||
/\b(?:cat|echo|printf)\b.*(?:>|>>|\|\s*tee\b)/.test(command) ||
/\bsed\s+-i\b/.test(command) ||
/\bperl\s+-pi\b/.test(command) ||
// In command position only: `cat AGENTS.wmill.md` is a read.
/(?:^|[;&|(]|\b(?:then|do|xargs)\s)\s*wmill(?:\s|$)/m.test(command)
);
}
+31
View File
@@ -2,7 +2,9 @@ import { describe, expect, it } from "bun:test";
import {
anthropicUsageToBenchmarkTokenUsage,
extractCliResultTokenUsage,
endpointEnv,
extractProposedWmillCommands,
getFirstMutationToolIndex,
parseWmillInvocationLog,
} from "./runtime";
@@ -147,3 +149,32 @@ push
]);
});
});
describe("getFirstMutationToolIndex", () => {
it("counts wmill only as a command, not in a file name", () => {
const bash = (command: string) => ({ tool: "Bash", input: { command }, timestamp: 0 });
expect(
getFirstMutationToolIndex([
bash("cat AGENTS.wmill.md .agents/skills/x/SKILL.md"),
bash("ls && wmill generate-metadata"),
])
).toBe(1);
expect(getFirstMutationToolIndex([bash("cd f\nwmill sync push")])).toBe(0);
});
});
describe("endpointEnv", () => {
it("passes the endpoint only its own key", () => {
const env = endpointEnv(
{ baseUrl: "https://example.test", apiKeyEnv: "DEEPSEEK_API_KEY" },
"m",
{ PATH: "/bin", DEEPSEEK_API_KEY: "ds", OPENAI_API_KEY: "oa", ANTHROPIC_AUTH_TOKEN: "t" }
);
expect(env).toEqual({
PATH: "/bin",
ANTHROPIC_BASE_URL: "https://example.test",
ANTHROPIC_API_KEY: "ds",
ANTHROPIC_DEFAULT_HAIKU_MODEL: "m",
});
});
});
+103 -70
View File
@@ -2,7 +2,14 @@ import { query, type Options } from "@anthropic-ai/claude-agent-sdk";
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
import { delimiter, join } from "path";
import { fileURLToPath } from "url";
import { getCliEvalModel, resolveEvalModel, type CliEvalModelConfig } from "../../core/models";
import {
getCliEvalModel,
resolveEvalModel,
type CliEvalModelConfig,
} from "../../core/models";
import { runCodex, type AgentRunResult } from "./codex";
import { isLikelyMutatingBashCommand } from "./mutation";
export { formatCliRunModelLabel } from "../../core/models";
import type {
BenchmarkTokenUsage,
CliToolInvocation,
@@ -141,16 +148,94 @@ export async function runPromptAndCapture(
maxTurns: number = 3,
modelConfig: CliEvalModelConfig = DEFAULT_CLI_EVAL_MODEL
): Promise<PromptRunResult> {
const toolsUsed: ToolInvocation[] = [];
const skillsInvoked: string[] = [];
const bashCommands: string[] = [];
let output = "";
let assistantMessageCount = 0;
let tokenUsage: BenchmarkTokenUsage | null = null;
let finalContextTokens: number | null = null;
const startedAt = Date.now();
const stubBinDir = join(cwd, WMILL_STUB_DIR_NAME);
const wmillLogPath = join(cwd, WMILL_LOG_FILE_NAME);
const env = {
...getQueryEnv(),
PATH: process.env.PATH ? `${stubBinDir}${delimiter}${process.env.PATH}` : stubBinDir,
WMILL_BENCHMARK_LOG_PATH: wmillLogPath,
};
await installWmillStub(stubBinDir);
const run =
modelConfig.runtime === "codex"
? await runCodex(prompt, cwd, maxTurns, modelConfig.model, env)
: await runClaudeCode(prompt, cwd, maxTurns, modelConfig, env);
const skillsInvoked: string[] = [];
const bashCommands: string[] = [];
for (const tool of run.toolsUsed) {
if (tool.tool === "Skill" && typeof tool.input.skill === "string") {
pushUnique(skillsInvoked, tool.input.skill);
}
if (tool.tool === "Bash") {
for (const command of extractBashCommands(tool.input)) {
pushUnique(bashCommands, command);
}
}
}
const wmillInvocations = await readWmillInvocationLog(wmillLogPath);
return {
output: run.output,
durationMs: Date.now() - startedAt,
tokenUsage: run.tokenUsage,
finalContextTokens: run.finalContextTokens,
trace: {
toolsUsed: run.toolsUsed,
skillsInvoked,
assistantMessageCount: run.assistantMessageCount,
bashCommands,
proposedCommands: extractProposedWmillCommands(run.output),
executedWmillCommands: wmillInvocations.map(formatExecutedWmillCommand),
wmillInvocations,
firstMutationToolIndex: getFirstMutationToolIndex(run.toolsUsed),
},
};
}
// Only the endpoint's own key may reach it: a missing key would make Claude Code
// fall back to the user's Claude login, and the agent's Bash inherits this env,
// so any other credential could end up in a tool result sent to the endpoint.
export function endpointEnv(
endpoint: NonNullable<CliEvalModelConfig["anthropicEndpoint"]>,
model: string,
env: Record<string, string>
): Record<string, string> {
const key = env[endpoint.apiKeyEnv];
if (!key) {
throw new Error(`${endpoint.apiKeyEnv} is not set`);
}
const rest = Object.fromEntries(
Object.entries(env).filter(([name]) => !/KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL/i.test(name))
);
return {
...rest,
ANTHROPIC_BASE_URL: endpoint.baseUrl,
ANTHROPIC_API_KEY: key,
// Claude Code's background calls default to Haiku, which the endpoint does not serve.
ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
};
}
async function runClaudeCode(
prompt: string,
cwd: string,
maxTurns: number,
modelConfig: CliEvalModelConfig,
env: Record<string, string>
): Promise<AgentRunResult> {
const result: AgentRunResult = {
output: "",
toolsUsed: [],
assistantMessageCount: 0,
tokenUsage: null,
finalContextTokens: null,
};
const endpoint = modelConfig.anthropicEndpoint;
const options: Options = {
cwd,
@@ -158,80 +243,42 @@ export async function runPromptAndCapture(
maxTurns,
settingSources: ["project"],
allowedTools: ["Skill", "Read", "Glob", "Grep", "Bash", "Write", "Edit"],
env: {
...getQueryEnv(),
PATH: process.env.PATH ? `${stubBinDir}${delimiter}${process.env.PATH}` : stubBinDir,
WMILL_BENCHMARK_LOG_PATH: wmillLogPath,
},
env: endpoint ? endpointEnv(endpoint, modelConfig.model, env) : env,
};
await installWmillStub(stubBinDir);
for await (const message of query({ prompt, options })) {
if (message.type === "assistant") {
assistantMessageCount += 1;
result.assistantMessageCount += 1;
const turnContext = anthropicUsageToBenchmarkTokenUsage(
message.message?.usage
)?.prompt;
if (turnContext && turnContext > 0) {
finalContextTokens = turnContext;
result.finalContextTokens = turnContext;
}
const content = message.message?.content;
if (Array.isArray(content)) {
for (const block of content) {
if (block.type === "tool_use") {
const input = normalizeToolInput(block.input);
toolsUsed.push({
result.toolsUsed.push({
tool: block.name,
input,
input: normalizeToolInput(block.input),
timestamp: Date.now()
});
if (block.name === "Skill") {
const skillInput = input as { skill?: string };
if (skillInput.skill) {
pushUnique(skillsInvoked, skillInput.skill);
}
}
if (block.name === "Bash") {
for (const command of extractBashCommands(input)) {
pushUnique(bashCommands, command);
}
}
} else if (block.type === "text") {
output += block.text;
result.output += block.text;
}
}
}
} else if (message.type === "result") {
const resultMessage = message as { result?: string };
tokenUsage = extractCliResultTokenUsage(message) ?? tokenUsage;
result.tokenUsage = extractCliResultTokenUsage(message) ?? result.tokenUsage;
if (typeof resultMessage.result === "string") {
output += resultMessage.result;
result.output += resultMessage.result;
}
}
}
const proposedCommands = extractProposedWmillCommands(output);
const wmillInvocations = await readWmillInvocationLog(wmillLogPath);
return {
output,
durationMs: Date.now() - startedAt,
tokenUsage,
finalContextTokens,
trace: {
toolsUsed,
skillsInvoked,
assistantMessageCount,
bashCommands,
proposedCommands,
executedWmillCommands: wmillInvocations.map(formatExecutedWmillCommand),
wmillInvocations,
firstMutationToolIndex: getFirstMutationToolIndex(toolsUsed),
},
};
return result;
}
export function wasSkillInvoked(result: PromptRunResult, skillName: string): boolean {
@@ -242,10 +289,6 @@ export function wasToolUsed(result: PromptRunResult, toolName: string): boolean
return result.trace.toolsUsed.some((tool) => tool.tool === toolName);
}
export function formatCliRunModelLabel(modelConfig: CliEvalModelConfig): string {
return `${modelConfig.provider}:${modelConfig.model}`;
}
export function getToolInputs(
result: PromptRunResult,
toolName: string
@@ -512,7 +555,7 @@ function formatExecutedWmillCommand(entry: CliWmillInvocation): string {
return ["wmill", ...entry.argv].join(" ").trim();
}
function getFirstMutationToolIndex(toolsUsed: ToolInvocation[]): number | null {
export function getFirstMutationToolIndex(toolsUsed: ToolInvocation[]): number | null {
for (const [index, tool] of toolsUsed.entries()) {
if (tool.tool === "Write" || tool.tool === "Edit") {
return index;
@@ -526,16 +569,6 @@ function getFirstMutationToolIndex(toolsUsed: ToolInvocation[]): number | null {
return null;
}
function isLikelyMutatingBashCommand(command: string): boolean {
return (
/\b(?:mkdir|touch|rm|mv|cp|install|tee)\b/.test(command) ||
/\b(?:cat|echo|printf)\b.*(?:>|>>|\|\s*tee\b)/.test(command) ||
/\bsed\s+-i\b/.test(command) ||
/\bperl\s+-pi\b/.test(command) ||
/\bwmill\b/.test(command)
);
}
function pushUnique(values: string[], value: string): void {
if (!values.includes(value)) {
values.push(value);
@@ -123,6 +123,7 @@ export interface GlobalEvalOptions {
planMode?: boolean;
model?: string;
maxIterations?: number;
userAnswers?: string[];
provider?: AIProvider;
backend: WindmillBackendSettings;
workspaceRoot?: string;
@@ -220,6 +221,7 @@ export async function runGlobalEval(
onToolCall: options.runContext?.onToolCall,
options: {
maxIterations: options.maxIterations,
userAnswers: options.userAnswers,
model,
workspace: workspaceRoot,
provider: options.provider,
@@ -85,6 +85,7 @@ export async function runEval<THelpers, TOutput>(
const model = options.model ?? "gpt-4o";
const maxIterations = options.maxIterations ?? 20;
const pendingAnswers = options.userAnswers && [...options.userAnswers];
const workspace = options.workspace ?? "test-workspace";
const provider = toFrontendEvalProvider(options.provider);
@@ -138,6 +139,12 @@ export async function runEval<THelpers, TOutput>(
// edit the arguments, so a case can assert what the model proposed but never how
// it reacts to the user changing something.
requestRunArgs: async (_toolId, form) => form.args,
...(pendingAnswers && {
requestUserQuestion: async () => {
const answer = pendingAnswers.shift();
return answer === undefined ? undefined : [answer];
},
}),
onNewToken: (token: string) => {
if (shouldEmitMessageStart) {
onAssistantMessageStart?.();
@@ -16,6 +16,9 @@ export interface ToolCallDetail {
export interface EvalRunnerOptions {
backend: WindmillBackendSettings;
maxIterations?: number;
// Scripted answers to the model's questions, one per question in order; a question past
// the last one is dismissed. Unset, the run cannot be asked anything.
userAnswers?: string[];
model?: string;
workspace?: string;
provider?: AIProvider;
@@ -6,6 +6,8 @@ import { dirname, resolve } from 'path'
// @ts-ignore - Node.js url
import { fileURLToPath } from 'url'
import { handleBenchmarkApiFetch, hasBenchmarkApiHandler } from './mockBackend'
import { resolveWindmillBackendSettings } from '../../core/windmillBackendSettings'
import { WindmillBackendClient } from './windmillBackend'
const FRONTEND_DIR = fileURLToPath(new URL('../../../frontend/', import.meta.url))
@@ -28,6 +30,11 @@ globalThis.fetch = (async (input: unknown, init?: RequestInit) => {
if (typeof url === 'string' && hasBenchmarkApiHandler(url)) {
return handleBenchmarkApiFetch(url, init)
}
// The docs tools read the documentation bundled into the backend: hand them to the
// benchmark's real backend, logged in like the AI proxy calls.
if (typeof url === 'string' && url.startsWith('/api/docs/')) {
return new WindmillBackendClient(resolveWindmillBackendSettings()).request(url.slice('/api'.length), init)
}
// The parsers behind inferArgs load their wasm from a vite `?url` path, which only a dev
// server serves. Unserved, every script schema infers as empty, and the tools then tell the
// model its arguments are undeclared, so it rewrites a correct script until it runs out of turns.
@@ -684,6 +691,7 @@ benchmarkIt(
resetBenchmarkMockBackend()
}
},
// Full-suite runs (30+ cases at concurrency 2-3) routinely exceed 10 minutes.
7_200_000
// A full suite on a slow reasoning model runs for hours (gpt-6-astra on global went past
// 2h); the CI job's own timeout is the real bound.
18_000_000
)
+106 -1
View File
@@ -198,22 +198,127 @@
- uses the requested placeholder value and description
- does not create a resource or deploy anything
# A new app that has to store data, with nothing said about where: the data setup is the
# user's call, so it is asked before anything is created. The question is dismissed here,
# which leaves nothing the model may build on.
- id: global-test7-ambiguous-app-asks-question
prompt: |-
Create a new raw app for triaging support tickets.
initial: ai_evals/fixtures/frontend/global/initial/datatable_orders_seed.json
runtime:
maxTurns: 4
maxTurns: 6
userAnswers: []
validate:
draftCountExactly: 0
toolExpect:
requiredToolsUsed:
- list_datatables
- askUserQuestion
forbiddenToolsUsed:
- init_app
- exec_datatable_sql
- write_app_file
- write_app_runnable
- deploy_workspace_item
- delete_workspace_item
toolCallArgs:
- tool: askUserQuestion
field: question
stringIncludesAnyOf:
- data table
- datatable
- schema
- tables
- store
skipJudge: true
# The same request with the question answered: the app is built on what the user chose.
- id: global-new-app-data-setup-answer-applied
prompt: |-
Create a new raw app for triaging support tickets.
initial: ai_evals/fixtures/frontend/global/initial/datatable_orders_seed.json
runtime:
maxTurns: 32
userAnswers:
- A new schema named helpdesk
- Create new tables
validate:
draftCountExactly: 1
requiredDrafts:
- type: app
valueIncludes:
- helpdesk
- react-dom/client
toolExpect:
requiredToolsUsed:
- askUserQuestion
- init_app
forbiddenToolsUsed:
- deploy_workspace_item
toolCallArgs:
- tool: init_app
field: framework
stringEqualsAnyOf:
- react19
- tool: exec_datatable_sql
field: sql
stringIncludesAnyOf:
- helpdesk
skipJudge: true
# No framework named, no app to follow, nothing to store: the modal's recommended
# framework is used without a question.
- id: global-new-app-defaults-to-react19
prompt: |-
Build me a little app that converts temperatures between Celsius and Fahrenheit.
runtime:
maxTurns: 12
validate:
draftCountExactly: 1
requiredDrafts:
- type: app
valueIncludes:
- react-dom/client
toolExpect:
requiredToolsUsed:
- init_app
forbiddenToolsUsed:
- askUserQuestion
- exec_datatable_sql
- deploy_workspace_item
toolCallArgs:
- tool: init_app
field: framework
stringEqualsAnyOf:
- react19
skipJudge: true
# The user said where the data goes, so there is nothing left to ask.
- id: global-new-app-storage-specified-no-question
prompt: |-
Build a todo list app in React. Keep the todos in the main data table, in a new
schema called todo_app.
initial: ai_evals/fixtures/frontend/global/initial/datatable_orders_seed.json
runtime:
maxTurns: 20
validate:
draftCountExactly: 1
requiredDrafts:
- type: app
valueIncludes:
- todo_app
toolExpect:
requiredToolsUsed:
- init_app
- write_app_runnable
forbiddenToolsUsed:
- askUserQuestion
- deploy_workspace_item
toolCallArgs:
- tool: exec_datatable_sql
field: sql
stringIncludesAnyOf:
- todo_app
skipJudge: true
- id: global-test8-human-script-infer-path-language
-2
View File
@@ -192,8 +192,6 @@ describe("loadCases", () => {
requiredSkills: ["write-script-bun"],
requiredSkillsBeforeFirstMutation: ["write-script-bun"],
forbiddenSkills: ["write-script-python3", "write-flow"],
orderedAssistantMentions: ["wmill generate-metadata", "wmill sync push"],
orderedProposedCommands: ["wmill generate-metadata", "wmill sync push"],
forbiddenExecutedCommands: ["^wmill generate-metadata", "^wmill sync push"],
});
});
+13 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from "bun:test";
import { resolveEvalModel } from "./models";
import { formatRunModelLabel, resolveEvalModel } from "./models";
describe("resolveEvalModel", () => {
it("supports GPT-5.5 aliases for frontend evals", () => {
@@ -47,6 +47,18 @@ describe("resolveEvalModel", () => {
});
});
it("labels cli runs by agent, keeping Claude's historical label", () => {
expect(formatRunModelLabel("cli", resolveEvalModel("cli", "sonnet-5.5"))).toBe(
"anthropic:claude-sonnet-5-5",
);
expect(formatRunModelLabel("cli", resolveEvalModel("cli", "gpt-6.1-sol"))).toBe(
"codex:gpt-6.1-sol",
);
expect(formatRunModelLabel("cli", resolveEvalModel("cli", "deepseek-v4-pro"))).toBe(
"claude-code:deepseek-v4-pro",
);
});
it("rejects Gemini aliases for cli evals", () => {
expect(() => resolveEvalModel("cli", "gemini-3-flash-preview")).toThrow(
"Model gemini-3-flash-preview is not supported for cli mode",
+54 -7
View File
@@ -5,9 +5,13 @@ export interface FrontendEvalModelConfig {
model: string;
}
// The coding agent that drives the model in cli mode (adapters/cli/runtime.ts).
export interface CliEvalModelConfig {
provider: "anthropic";
runtime: "claude-code" | "codex";
model: string;
// An Anthropic-compatible endpoint other than Anthropic's, for claude-code,
// and the env var holding its key.
anthropicEndpoint?: { baseUrl: string; apiKeyEnv: string };
}
export interface EvalModelSpec {
@@ -35,7 +39,7 @@ export const EVAL_MODELS: EvalModelSpec[] = [
model: "claude-haiku-4-5-20251001",
},
cli: {
provider: "anthropic",
runtime: "claude-code",
model: "haiku",
},
},
@@ -55,7 +59,7 @@ export const EVAL_MODELS: EvalModelSpec[] = [
model: "claude-sonnet-4-5-20250929",
},
cli: {
provider: "anthropic",
runtime: "claude-code",
model: "sonnet",
},
},
@@ -74,7 +78,7 @@ export const EVAL_MODELS: EvalModelSpec[] = [
model: "claude-opus-4-6",
},
cli: {
provider: "anthropic",
runtime: "claude-code",
model: "opus",
},
},
@@ -87,7 +91,7 @@ export const EVAL_MODELS: EvalModelSpec[] = [
model: "claude-sonnet-5-5",
},
cli: {
provider: "anthropic",
runtime: "claude-code",
model: "claude-sonnet-5-5",
},
},
@@ -100,7 +104,7 @@ export const EVAL_MODELS: EvalModelSpec[] = [
model: "claude-opus-5-5",
},
cli: {
provider: "anthropic",
runtime: "claude-code",
model: "claude-opus-5-5",
},
},
@@ -139,6 +143,19 @@ export const EVAL_MODELS: EvalModelSpec[] = [
provider: "openai",
model: "gpt-6-astra",
},
cli: {
runtime: "codex",
model: "gpt-6-astra",
},
},
{
id: "gpt-6.1-sol",
label: "GPT-6.1 Sol",
aliases: ["gpt-6.1-sol"],
frontend: {
provider: "openai",
model: "gpt-6.1-sol",
},
},
{
id: "gpt-6-sol",
@@ -149,6 +166,19 @@ export const EVAL_MODELS: EvalModelSpec[] = [
model: "gpt-6-sol",
},
},
{
id: "gpt-6.1-sol",
label: "GPT-6.1 Sol",
aliases: ["gpt-6.1-sol"],
frontend: {
provider: "openai",
model: "gpt-6.1-sol",
},
cli: {
runtime: "codex",
model: "gpt-6.1-sol",
},
},
{
id: "gpt-6-luna",
label: "GPT-6 Luna",
@@ -215,6 +245,14 @@ export const EVAL_MODELS: EvalModelSpec[] = [
provider: "deepseek",
model: "deepseek-v4-pro",
},
cli: {
runtime: "claude-code",
model: "deepseek-v4-pro",
anthropicEndpoint: {
baseUrl: "https://api.deepseek.com/anthropic",
apiKeyEnv: "DEEPSEEK_API_KEY",
},
},
},
];
@@ -253,11 +291,20 @@ export function formatRunModelLabel(
model: EvalModelSpec,
): string {
if (mode === "cli") {
return `${model.cli!.provider}:${model.cli!.model}`;
return formatCliRunModelLabel(model.cli!);
}
return `${model.frontend!.provider}:${model.frontend!.model}`;
}
// Claude on Claude Code keeps the `anthropic:` prefix its dashboard history was
// recorded under; any other pairing names the agent.
export function formatCliRunModelLabel(config: CliEvalModelConfig): string {
if (config.runtime === "claude-code" && !config.anthropicEndpoint) {
return `anthropic:${config.model}`;
}
return `${config.runtime}:${config.model}`;
}
export function getFrontendEvalModel(
model: EvalModelSpec,
): FrontendEvalModelConfig {
+4
View File
@@ -29,6 +29,10 @@ export interface EvalCaseRuntimeAppContextSpec {
export interface EvalCaseRuntimeSpec {
maxTurns?: number;
// Global mode: scripted answers to askUserQuestion, one per question in order; a question
// past the last one is dismissed, so `[]` dismisses them all. Unset, the question tool
// reports that it cannot ask.
userAnswers?: string[];
backendPreview?: EvalCaseRuntimeBackendPreview;
appContext?: EvalCaseRuntimeAppContextSpec;
// Global mode: run as a session chat (preview tools + session prompt) vs the standalone chat.
+32 -9
View File
@@ -39,17 +39,36 @@ interface CliRunActual {
trace: CliTrace;
}
const CLAUDE_PROJECT_PREAMBLE = [
"Follow the project instructions from AGENTS.md exactly.",
"Before creating or modifying any Windmill entity, you MUST invoke the relevant Skill tool and follow it.",
"Use the skill guidance for file layout, implementation details, and the exact next commands to tell the user.",
"Do not skip the Skill step.",
// Only the skill wording differs per agent: Claude Code has a Skill tool, Codex
// loads a skill by reading its SKILL.md.
const SKILL_STEP: Record<CliEvalModelConfig["runtime"], string[]> = {
"claude-code": [
"Before creating or modifying any Windmill entity, you MUST invoke the relevant Skill tool and follow it.",
"Use the skill guidance for file layout, implementation details, and the exact next commands to tell the user.",
"Do not skip the Skill step.",
],
codex: [
"Before creating or modifying any Windmill entity, you MUST read the relevant skill's SKILL.md under .agents/skills and follow it.",
"Use the skill guidance for file layout, implementation details, and the exact next commands to tell the user.",
"Do not skip the skill step.",
],
};
const HARNESS_PREAMBLE = [
"You are running inside an automated benchmark harness, not an interactive user session.",
"Act autonomously and complete the requested file changes directly in the workspace.",
"Do not ask for confirmation, do not ask the user to save or create files manually, and do not wait for approval.",
"Do not respond with a plan when you can make the change directly.",
"Only describe what was done after you have written the files.",
].join(" ");
];
function projectPreamble(runtime: CliEvalModelConfig["runtime"]): string {
return [
"Follow the project instructions from AGENTS.md exactly.",
...SKILL_STEP[runtime],
...HARNESS_PREAMBLE,
].join(" ");
}
export function createCliModeRunner(
modelConfig: CliEvalModelConfig = DEFAULT_CLI_EVAL_MODEL
@@ -89,7 +108,7 @@ export function createCliModeRunner(
});
await writeFile(join(workspaceDir, "rt.d.ts"), "export namespace RT {}\n", "utf8");
const renderedPrompt = await renderPrompt(prompt, workspaceDir);
const renderedPrompt = await renderPrompt(prompt, workspaceDir, modelConfig.runtime);
const run = await runPromptAndCapture(
renderedPrompt,
workspaceDir,
@@ -193,7 +212,11 @@ export function getCliRunModelLabel(
return formatCliRunModelLabel(modelConfig);
}
async function renderPrompt(prompt: string, workspaceDir: string): Promise<string> {
async function renderPrompt(
prompt: string,
workspaceDir: string,
runtime: CliEvalModelConfig["runtime"]
): Promise<string> {
const renderedUserPrompt = prompt.replaceAll("{{workspace_root}}", workspaceDir);
const agentsInstructions = await readFile(path.join(workspaceDir, "AGENTS.md"), "utf8");
@@ -202,7 +225,7 @@ async function renderPrompt(prompt: string, workspaceDir: string): Promise<strin
agentsInstructions.trim(),
"",
"# Benchmark Harness",
CLAUDE_PROJECT_PREAMBLE,
projectPreamble(runtime),
"",
"# User Request",
renderedUserPrompt,
+1
View File
@@ -54,6 +54,7 @@ export function createGlobalModeRunner(
sessionChat: context.evalCase?.runtime?.sessionChat,
planMode: context.evalCase?.runtime?.planMode,
maxIterations: context.evalCase?.runtime?.maxTurns,
userAnswers: context.evalCase?.runtime?.userAnswers,
provider: modelConfig.provider,
model: modelConfig.model,
backend: backendSettings,
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, ws_error_handler_muted)\n VALUES ('test-workspace', $1, 'f/test/muted_failing_script', 'export function main() { throw new Error(\"fail\"); }', 'deno', 'script', 'test-user', '{}', '', '', '', true)\n ",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, ws_error_handler_muted)\n VALUES ('test-workspace', $1, 'f/test/muted_failing_script', 'export function main() { throw new Error(\"fail\"); }', 'bun', 'script', 'test-user', '{}', '', '', E'{}\\n//bun.lock\\n<empty>', true)\n ",
"describe": {
"columns": [],
"parameters": {
@@ -10,5 +10,5 @@
},
"nullable": []
},
"hash": "782c259ccdf71c5e2fa8dcb27515e7c5ff83009774dc15095ed0dbcb0ecdbdde"
"hash": "009fd85c1aa55ea36454eafffbf62505461eb1cc8b9af85a2e2ab6e7dbe950c6"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "\nINSERT INTO concurrency_counter(concurrency_id, job_uuids)\nVALUES ($1, '{}'::jsonb)\nON CONFLICT (concurrency_id)\nDO UPDATE SET job_uuids = concurrency_counter.job_uuids\nRETURNING (SELECT COUNT(*)\n FROM jsonb_object_keys(job_uuids) AS keys(key)\n WHERE key <> $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": [
null
]
},
"hash": "03cc00b0b5b8b1ffcc14ac5f6cb3062a8f706e70bc9c4b3764cd1d6f99b9440a"
}
@@ -0,0 +1,19 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script\n (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, delete_after_secs, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules, labels, job_token_scopes, lock_error_logs, created_at)\n\n SELECT workspace_id, $1, path, array_prepend($2::bigint, COALESCE(parent_hashes, '{}'::bigint[])), summary, description, content, created_by, schema, is_template, extra_perms, $4::text, language, kind, tag, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, delete_after_secs, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, COALESCE($5::jsonb, modules), labels, job_token_scopes, $6::text, clock_timestamp()\n\n FROM script WHERE hash = $2 AND workspace_id = $3;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Int8",
"Text",
"Text",
"Jsonb",
"Text"
]
},
"nullable": []
},
"hash": "05b610ad1809d487c32e85b0392cfca8913ba1129fdf4978a8a4738689786160"
}
@@ -0,0 +1,152 @@
{
"db_name": "PostgreSQL",
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (\n id, -- 1\n workspace_id, -- 2\n raw_code, -- 3\n raw_lock, -- 4\n raw_flow, -- 5\n tag, -- 6\n parent_job, -- 7\n created_by, -- 8\n permissioned_as, -- 9\n runnable_id, -- 10\n runnable_path, -- 11\n args, -- 12\n kind, -- 13\n trigger, -- 14\n script_lang, -- 15\n same_worker, -- 16\n pre_run_error, -- 17\n permissioned_as_email, -- 18\n visible_to_owner, -- 19\n flow_innermost_root_job, -- 20\n root_job, -- 38\n concurrent_limit, -- 21\n concurrency_time_window_s, -- 22\n timeout, -- 23\n flow_step_id, -- 24\n cache_ttl, -- 25\n priority, -- 26\n trigger_kind, -- 39\n script_entrypoint_override, -- 12\n preprocessed, -- 27,\n labels -- 44\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $38, $21, $22, $23, $24, $25, $26, $39::job_trigger_kind,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27,\n -- $44 (payload labels) merged with the labels of the runnable's folder, if any\n -- ($45/$46 are runnable_path/workspace_id again, kept separate to avoid parameter type conflicts)\n (SELECT CASE WHEN fl.labels IS NULL THEN $44\n ELSE (SELECT array_agg(DISTINCT lbl) FROM unnest(COALESCE($44, ARRAY[]::TEXT[]) || fl.labels) lbl)\n END\n FROM folder_labels($46, $45) AS fl(labels)))\n ),\n inserted_runtime AS (\n INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)\n ),\n inserted_job_perms AS (\n INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id, end_user_email, job_token_scopes)\n values ($1, $32, $33, $34, $35, $36, $37, $2, $41, $47)\n ON CONFLICT (job_id) DO UPDATE SET email = EXCLUDED.email, username = EXCLUDED.username, is_admin = EXCLUDED.is_admin, is_operator = EXCLUDED.is_operator, folders = EXCLUDED.folders, groups = EXCLUDED.groups, workspace_id = EXCLUDED.workspace_id, end_user_email = EXCLUDED.end_user_email, job_token_scopes = EXCLUDED.job_token_scopes\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority, cache_ignore_s3_path, runnable_settings_handle)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 OR $40 THEN now() END, $30, $31, $42, $43)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Varchar",
"Text",
"Text",
"Jsonb",
"Varchar",
"Uuid",
"Varchar",
"Varchar",
"Int8",
"Varchar",
"Jsonb",
{
"Custom": {
"name": "job_kind",
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub",
"identity",
"flowdependencies",
"http",
"graphql",
"postgresql",
"noop",
"appdependencies",
"deploymentcallback",
"singlestepflow",
"flowscript",
"flownode",
"appscript",
"aiagent",
"unassigned_script",
"unassigned_flow",
"unassigned_singlestepflow"
]
}
}
},
"Varchar",
{
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang",
"dbt"
]
}
}
},
"Bool",
"Text",
"Varchar",
"Bool",
"Uuid",
"Int4",
"Int4",
"Int4",
"Varchar",
"Int4",
"Int2",
"Bool",
"Bool",
"Timestamptz",
"Varchar",
"Int2",
"Varchar",
"Varchar",
"Bool",
"Bool",
"JsonbArray",
"TextArray",
"Uuid",
{
"Custom": {
"name": "job_trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats",
"schedule",
"app",
"ui",
"postgres",
"sqs",
"gcp",
"mqtt",
"nextcloud",
"google",
"ci_test",
"github",
"azure",
"asset",
"freshness",
"amqp"
]
}
}
},
"Bool",
"Varchar",
"Bool",
"Int8",
"TextArray",
"Text",
"Text",
"TextArray"
]
},
"nullable": []
},
"hash": "095fa75c60724664f0355cd6e3a64f84a0f1a31cd6732c0ab994a2d6ac3c3eec"
}
@@ -0,0 +1,47 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT ON (path)\n path,\n value as \"value!: sqlx::types::Json<Box<serde_json::value::RawValue>>\",\n created_at,\n email IS NULL as \"legacy!\",\n typ::text as \"typ!\"\n FROM draft\n WHERE workspace_id = $1\n AND typ IN ('app', 'raw_app')\n AND (email = $2 OR email IS NULL)\n AND NOT EXISTS (\n SELECT 1 FROM app a\n WHERE a.workspace_id = draft.workspace_id\n AND a.path = draft.path\n )\n ORDER BY path, (email IS NULL), created_at DESC",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "value!: sqlx::types::Json<Box<serde_json::value::RawValue>>",
"type_info": "Json"
},
{
"ordinal": 2,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 3,
"name": "legacy!",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "typ!",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false,
false,
false,
null,
null
]
},
"hash": "0d260ba4f168d725ea3b82d33324dd1d16a68a2bae6e500d9e480b152fd5859d"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', $1, 'f/test/simple_script', $2, 'deno', 'script', 'test-user', '{}', 'Simple test script', 'A simple test script', '')\n ",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', $1, 'f/test/simple_script', $2, 'bun', 'script', 'test-user', '{}', 'Simple test script', 'A simple test script', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
@@ -11,5 +11,5 @@
},
"nullable": []
},
"hash": "dbc05cbf6720cc85e01118bcdcbb478724ac0ea8f3e043da2de9d932216cc730"
"hash": "1043947475822c27f73b5357e6ec0d527d999f2865ff5de75186b49004a3565e"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (\n SELECT 1 FROM v2_job o, v2_job t,\n LATERAL (SELECT ARRAY_REMOVE(ARRAY[o.id, o.parent_job, o.root_job,\n o.flow_innermost_root_job], NULL) AS run) l\n WHERE o.id = $1 AND t.id = $2 AND t.workspace_id = o.workspace_id\n AND (t.id = ANY(l.run) OR t.parent_job = ANY(l.run)\n OR t.root_job = ANY(l.run) OR t.flow_innermost_root_job = ANY(l.run))\n )",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "10f166464a10fc35df2b6ff1b497b17d6bb71f0ae69cd218e6a3fbc151d19d87"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "WITH prev AS (SELECT started_at FROM v2_job_queue WHERE id = $1)\n UPDATE v2_job_queue q SET running = false, started_at = null,\n extras = CASE WHEN q.started_at IS NULL OR q.extras ? 'wac_first_started_at' THEN q.extras\n ELSE jsonb_set(COALESCE(q.extras, '{}'::jsonb), '{wac_first_started_at}', to_jsonb(q.started_at))\n END\n FROM prev WHERE q.id = $1\n RETURNING (extract(epoch FROM now() - prev.started_at) * 1000)::bigint",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "int8",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "1333436e3d0466eccdaf99fb70aadad56b50619036fab3f2c1bdbbf280a80217"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT job_token_scopes FROM job_perms WHERE job_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
true
]
},
"hash": "13f358b7c76cda0b24fcb17dbbe10a00333bbf3b8b43bbccc7a6e1926d82478c"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM runnable_job_stats s WHERE s.hour >= $1 AND NOT EXISTS (SELECT 1 FROM workspace w WHERE w.id = s.workspace_id)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": []
},
"hash": "1ae4aab40783b4cd588e5a4da57eabca765789cd706ad682e8094c8960bc46a8"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT wp.draining FROM v2_job_queue q JOIN worker_ping wp ON wp.worker = q.worker\n WHERE q.id = $1 AND q.workspace_id = $2 AND q.running AND q.started_at IS NOT NULL",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "draining",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false
]
},
"hash": "1e3407ad2ec46bd965f2aeede0d3cd4a3f9226a5e0c6b15c2580ddd1dba6199b"
}
@@ -0,0 +1,40 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COALESCE((operator_settings->>'builder_flows')::boolean, false) AS \"flows!\",\n COALESCE((operator_settings->>'builder_apps')::boolean, false) AS \"apps!\",\n COALESCE((operator_settings->>'manage_schedules')::boolean, true) AS \"schedules!\",\n COALESCE((operator_settings->>'manage_triggers')::boolean, true) AS \"triggers!\"\n FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "flows!",
"type_info": "Bool"
},
{
"ordinal": 1,
"name": "apps!",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "schedules!",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "triggers!",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null,
null,
null,
null
]
},
"hash": "1fd3d5e8918143c6e4828b092c5d7d376555217b037d7694efa5ceffc4980f80"
}
@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO resource_type (workspace_id, name, schema, description, format_extension, display_name, edited_at)\n VALUES ('admins', $1, $2, $3, $4, $6, now())\n ON CONFLICT (workspace_id, name) DO UPDATE\n SET schema = EXCLUDED.schema, description = EXCLUDED.description,\n -- A fileset is a set of files, so it cannot also be one file.\n -- Create and update reject the pair; this writer bypasses both, so\n -- it declines the extension rather than persisting the forbidden\n -- combination onto a same-named local fileset.\n format_extension = CASE\n WHEN resource_type.is_fileset THEN NULL\n WHEN $5 THEN EXCLUDED.format_extension\n ELSE resource_type.format_extension END,\n display_name = CASE WHEN $7 THEN EXCLUDED.display_name ELSE resource_type.display_name END,\n edited_at = now()",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Jsonb",
"Text",
"Varchar",
"Bool",
"Varchar",
"Bool"
]
},
"nullable": []
},
"hash": "212bf5b32de102a9c537907aaff04befc3a6596c258086805dd42f513ddb3ead"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO runnable_job_stats\n (hour, workspace_id, runnable_path, worker_group, job_count, total_duration_ms,\n max_memory_peak, sum_memory_peak, memory_sample_count, total_cpu_ms)\n SELECT s.hour, s.workspace_id, s.runnable_path, s.worker_group, s.job_count,\n s.total_duration_ms, s.max_memory_peak, s.sum_memory_peak,\n s.memory_sample_count, s.total_cpu_ms\n FROM UNNEST($1::bigint[], $2::text[], $3::text[], $4::text[], $5::int[], $6::bigint[],\n $7::int[], $8::bigint[], $9::int[], $10::bigint[])\n AS s(hour, workspace_id, runnable_path, worker_group, job_count, total_duration_ms,\n max_memory_peak, sum_memory_peak, memory_sample_count, total_cpu_ms)\n JOIN workspace w ON w.id = s.workspace_id\n ORDER BY s.hour, s.workspace_id, s.runnable_path, s.worker_group\n ON CONFLICT (hour, workspace_id, runnable_path, worker_group) DO UPDATE SET\n job_count = runnable_job_stats.job_count + EXCLUDED.job_count,\n total_duration_ms = runnable_job_stats.total_duration_ms + EXCLUDED.total_duration_ms,\n max_memory_peak = GREATEST(runnable_job_stats.max_memory_peak, EXCLUDED.max_memory_peak),\n sum_memory_peak = runnable_job_stats.sum_memory_peak + EXCLUDED.sum_memory_peak,\n memory_sample_count = runnable_job_stats.memory_sample_count + EXCLUDED.memory_sample_count,\n total_cpu_ms = runnable_job_stats.total_cpu_ms + EXCLUDED.total_cpu_ms\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8Array",
"TextArray",
"TextArray",
"TextArray",
"Int4Array",
"Int8Array",
"Int4Array",
"Int8Array",
"Int4Array",
"Int8Array"
]
},
"nullable": []
},
"hash": "24cfd719a45af5beb4eb264939290c01e1b684525bae4cb329515989cd341875"
}
@@ -0,0 +1,324 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n v2_job_queue.workspace_id,\n v2_job_queue.id,\n v2_job.args as \"args: sqlx::types::Json<HashMap<String, Box<RawValue>>>\",\n v2_job.parent_job,\n v2_job.created_by,\n v2_job_queue.started_at,\n v2_job_queue.runnable_settings_handle,\n scheduled_for,\n runnable_path,\n kind as \"kind: JobKind\",\n runnable_id as \"runnable_id: ScriptHash\",\n canceled_reason,\n canceled_by,\n permissioned_as,\n permissioned_as_email,\n flow_status as \"flow_status: sqlx::types::Json<Box<RawValue>>\",\n v2_job.tag,\n script_lang as \"script_lang: ScriptLang\",\n same_worker,\n pre_run_error,\n concurrent_limit,\n concurrency_time_window_s,\n flow_innermost_root_job,\n root_job,\n timeout,\n flow_step_id,\n cache_ttl,\n cache_ignore_s3_path,\n v2_job_queue.priority,\n preprocessed,\n script_entrypoint_override,\n trigger,\n trigger_kind as \"trigger_kind: TriggerKindLabel\",\n visible_to_owner,\n NULL as permissioned_as_end_user_email,\n job_perms.job_token_scopes\n FROM v2_job_queue INNER JOIN v2_job ON v2_job.id = v2_job_queue.id LEFT JOIN v2_job_status ON v2_job_status.id = v2_job_queue.id\n LEFT JOIN job_perms ON job_perms.job_id = v2_job_queue.id WHERE v2_job_queue.id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "args: sqlx::types::Json<HashMap<String, Box<RawValue>>>",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "parent_job",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "started_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "runnable_settings_handle",
"type_info": "Int8"
},
{
"ordinal": 7,
"name": "scheduled_for",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "runnable_path",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "kind: JobKind",
"type_info": {
"Custom": {
"name": "job_kind",
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub",
"identity",
"flowdependencies",
"http",
"graphql",
"postgresql",
"noop",
"appdependencies",
"deploymentcallback",
"singlestepflow",
"flowscript",
"flownode",
"appscript",
"aiagent",
"unassigned_script",
"unassigned_flow",
"unassigned_singlestepflow"
]
}
}
}
},
{
"ordinal": 10,
"name": "runnable_id: ScriptHash",
"type_info": "Int8"
},
{
"ordinal": 11,
"name": "canceled_reason",
"type_info": "Text"
},
{
"ordinal": 12,
"name": "canceled_by",
"type_info": "Varchar"
},
{
"ordinal": 13,
"name": "permissioned_as",
"type_info": "Varchar"
},
{
"ordinal": 14,
"name": "permissioned_as_email",
"type_info": "Varchar"
},
{
"ordinal": 15,
"name": "flow_status: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 16,
"name": "tag",
"type_info": "Varchar"
},
{
"ordinal": 17,
"name": "script_lang: ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang",
"dbt"
]
}
}
}
},
{
"ordinal": 18,
"name": "same_worker",
"type_info": "Bool"
},
{
"ordinal": 19,
"name": "pre_run_error",
"type_info": "Text"
},
{
"ordinal": 20,
"name": "concurrent_limit",
"type_info": "Int4"
},
{
"ordinal": 21,
"name": "concurrency_time_window_s",
"type_info": "Int4"
},
{
"ordinal": 22,
"name": "flow_innermost_root_job",
"type_info": "Uuid"
},
{
"ordinal": 23,
"name": "root_job",
"type_info": "Uuid"
},
{
"ordinal": 24,
"name": "timeout",
"type_info": "Int4"
},
{
"ordinal": 25,
"name": "flow_step_id",
"type_info": "Varchar"
},
{
"ordinal": 26,
"name": "cache_ttl",
"type_info": "Int4"
},
{
"ordinal": 27,
"name": "cache_ignore_s3_path",
"type_info": "Bool"
},
{
"ordinal": 28,
"name": "priority",
"type_info": "Int2"
},
{
"ordinal": 29,
"name": "preprocessed",
"type_info": "Bool"
},
{
"ordinal": 30,
"name": "script_entrypoint_override",
"type_info": "Varchar"
},
{
"ordinal": 31,
"name": "trigger",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "trigger_kind: TriggerKindLabel",
"type_info": {
"Custom": {
"name": "job_trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats",
"schedule",
"app",
"ui",
"postgres",
"sqs",
"gcp",
"mqtt",
"nextcloud",
"google",
"ci_test",
"github",
"azure",
"asset",
"freshness",
"amqp"
]
}
}
}
},
{
"ordinal": 33,
"name": "visible_to_owner",
"type_info": "Bool"
},
{
"ordinal": 34,
"name": "permissioned_as_end_user_email",
"type_info": "Text"
},
{
"ordinal": 35,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false,
true,
true,
false,
true,
true,
false,
true,
false,
true,
true,
true,
false,
false,
true,
false,
true,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false,
null,
true
]
},
"hash": "333f7116d660756c36dfc0aa2b8d7ebd10a38cbe5724a554a12291c287b67f6d"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 3333333333, 'f/test/error_handler', 'export function main() { return \"handled\"; }', 'deno', 'script', 'test-user', '{}', '', '', '')\n ",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 3333333333, 'f/test/error_handler', 'export function main() { return \"handled\"; }', 'bun', 'script', 'test-user', '{}', '', '', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
@@ -8,5 +8,5 @@
},
"nullable": []
},
"hash": "7f98c013682aca6d269ef6ef754a7247b6e2dd4958d0968a3f2eb49cc320e877"
"hash": "344c08104d62d9bcd3f9117abb574e73a6fb364e4ab3e3916958c2e493673b1d"
}
@@ -0,0 +1,29 @@
{
"db_name": "PostgreSQL",
"query": "WITH RECURSIVE chain(origin, id, parent_job) AS (\n SELECT id, id, parent_job FROM v2_job WHERE id = ANY($1) AND workspace_id = $2\n UNION ALL\n SELECT c.origin, j.id, j.parent_job FROM v2_job j\n JOIN chain c ON j.id = c.parent_job AND j.workspace_id = $2\n )\n SELECT c.origin AS \"origin!\",\n CASE WHEN a.agent THEN regexp_replace(j.runnable_path, '\\.chat$', '')\n ELSE j.runnable_path END AS \"runnable_path!\"\n FROM chain c JOIN v2_job j ON j.id = c.id,\n LATERAL (SELECT j.kind = 'flowpreview'\n AND j.raw_flow->'modules'->1 IS NULL\n AND j.raw_flow->'modules'->0->>'id' = '__wm_agent_root' AS agent) a\n WHERE j.workspace_id = $2 AND j.runnable_path IS NOT NULL\n AND (a.agent OR j.kind IN ('script', 'script_hub', 'unassigned_script', 'flow',\n 'unassigned_flow', 'singlestepflow', 'unassigned_singlestepflow'))",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "origin!",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "runnable_path!",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"UuidArray",
"Text"
]
},
"nullable": [
null,
null
]
},
"hash": "35f960e9de880fdcaf81615933c828c4a877709c3c39a530d629cc91f9dd2d29"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM resource_type WHERE workspace_id = 'admins' AND name = $1 AND schema IS NOT DISTINCT FROM $2 AND description IS NOT DISTINCT FROM $3 AND ($5 IS NOT TRUE OR format_extension IS NOT DISTINCT FROM $4) AND ($7 IS NOT TRUE OR display_name IS NOT DISTINCT FROM $6))",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Jsonb",
"Text",
"Text",
"Bool",
"Text",
"Bool"
]
},
"nullable": [
null
]
},
"hash": "386e14cf7572027f2c4ef313cd7cc5dd6c7b0da4f76131313d3e6d97f36c5c34"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 1234567890, 'f/test/success_handler', $1, 'deno', 'script', 'test-user', '{}', 'Success handler script', 'Handles successful job completions', '')\n ",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 1234567890, 'f/test/success_handler', $1, 'bun', 'script', 'test-user', '{}', 'Success handler script', 'Handles successful job completions', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
@@ -10,5 +10,5 @@
},
"nullable": []
},
"hash": "2d43c1889b492df6f77380e739e41e20fe6bea0553cc39e30b7aa8ae59963f95"
"hash": "42250637493a623850ca76fe5a705fe4acef039f38a5e76da8d09f2f7e755779"
}
@@ -0,0 +1,84 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n flow_version.id AS version,\n flow_version.value->>'early_return' as early_return,\n flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor,\n flow_version.value->>'failure_module' IS NOT NULL as has_failure_module,\n (flow_version.value->>'chat_input_enabled')::boolean as chat_input_enabled,\n flow.tag,\n flow.dedicated_worker,\n flow.on_behalf_of,\n flow.edited_by,\n flow.labels,\n flow.job_token_scopes\n FROM\n flow_version\n INNER JOIN flow\n ON flow.path = flow_version.path AND\n flow.workspace_id = flow_version.workspace_id\n WHERE\n flow_version.workspace_id = $1 AND\n flow_version.path = $2 AND\n flow_version.id = $3\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version",
"type_info": "Int8"
},
{
"ordinal": 1,
"name": "early_return",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "has_preprocessor",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "has_failure_module",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "chat_input_enabled",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "tag",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "dedicated_worker",
"type_info": "Bool"
},
{
"ordinal": 7,
"name": "on_behalf_of",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "labels",
"type_info": "TextArray"
},
{
"ordinal": 10,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Int8"
]
},
"nullable": [
false,
null,
null,
null,
null,
true,
true,
true,
false,
true,
true
]
},
"hash": "4631200a37f7edec92f3796ab4d4585d9c2aba36fdf33bca9739049366bed107"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id, job_token_scopes)\n SELECT unnest($1::uuid[]), $2, $3, $4, $5, $6, $7, $8, $9",
"describe": {
"columns": [],
"parameters": {
"Left": [
"UuidArray",
"Varchar",
"Varchar",
"Bool",
"Bool",
"JsonbArray",
"TextArray",
"Varchar",
"TextArray"
]
},
"nullable": []
},
"hash": "4cc81f5e04caefa4f170807c0ce96c69f22d9ea9dc3586099553a8f0e76aad82"
}
@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, labels, job_token_scopes)\n SELECT workspace_id, $1, summary, description, archived, extra_perms, dependency_job, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, labels, job_token_scopes\n FROM flow\n WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "580271c5fe178f5e31f3e211cd7fea97aec4d6d3ec65d3e7402811c7dddbbf64"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT canceled_by IS NOT NULL FROM v2_job_queue WHERE id = $1 AND workspace_id = $2 AND running",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
null
]
},
"hash": "58ea7e2c6b07ffc7ab7387b2ebb542cba3a5532c64a9594d2e0ccdf21dee90d0"
}
@@ -0,0 +1,253 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n j.id, j.workspace_id, j.runnable_id AS \"runnable_id: ScriptHash\", q.scheduled_for, q.started_at, j.parent_job, j.flow_innermost_root_job, j.runnable_path, j.kind as \"kind!: JobKind\", j.permissioned_as,\n j.created_by, j.script_lang AS \"script_lang: ScriptLang\", j.permissioned_as_email, j.flow_step_id, j.trigger_kind AS \"trigger_kind: TriggerKindLabel\", j.trigger, j.priority, j.concurrent_limit, j.tag, j.cache_ttl, q.cache_ignore_s3_path, q.runnable_settings_handle,\n COALESCE(j.args->'build_binary_only' = 'true'::jsonb, false) AS \"build_binary_only!\",\n p.job_token_scopes AS \"job_token_scopes?\"\n FROM v2_job j LEFT JOIN v2_job_queue q ON j.id = q.id\n LEFT JOIN job_perms p ON p.job_id = j.id\n WHERE j.id = $1 AND j.workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "runnable_id: ScriptHash",
"type_info": "Int8"
},
{
"ordinal": 3,
"name": "scheduled_for",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "started_at",
"type_info": "Timestamptz"
},
{
"ordinal": 5,
"name": "parent_job",
"type_info": "Uuid"
},
{
"ordinal": 6,
"name": "flow_innermost_root_job",
"type_info": "Uuid"
},
{
"ordinal": 7,
"name": "runnable_path",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "kind!: JobKind",
"type_info": {
"Custom": {
"name": "job_kind",
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub",
"identity",
"flowdependencies",
"http",
"graphql",
"postgresql",
"noop",
"appdependencies",
"deploymentcallback",
"singlestepflow",
"flowscript",
"flownode",
"appscript",
"aiagent",
"unassigned_script",
"unassigned_flow",
"unassigned_singlestepflow"
]
}
}
}
},
{
"ordinal": 9,
"name": "permissioned_as",
"type_info": "Varchar"
},
{
"ordinal": 10,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "script_lang: ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang",
"dbt"
]
}
}
}
},
{
"ordinal": 12,
"name": "permissioned_as_email",
"type_info": "Varchar"
},
{
"ordinal": 13,
"name": "flow_step_id",
"type_info": "Varchar"
},
{
"ordinal": 14,
"name": "trigger_kind: TriggerKindLabel",
"type_info": {
"Custom": {
"name": "job_trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats",
"schedule",
"app",
"ui",
"postgres",
"sqs",
"gcp",
"mqtt",
"nextcloud",
"google",
"ci_test",
"github",
"azure",
"asset",
"freshness",
"amqp"
]
}
}
}
},
{
"ordinal": 15,
"name": "trigger",
"type_info": "Varchar"
},
{
"ordinal": 16,
"name": "priority",
"type_info": "Int2"
},
{
"ordinal": 17,
"name": "concurrent_limit",
"type_info": "Int4"
},
{
"ordinal": 18,
"name": "tag",
"type_info": "Varchar"
},
{
"ordinal": 19,
"name": "cache_ttl",
"type_info": "Int4"
},
{
"ordinal": 20,
"name": "cache_ignore_s3_path",
"type_info": "Bool"
},
{
"ordinal": 21,
"name": "runnable_settings_handle",
"type_info": "Int8"
},
{
"ordinal": 22,
"name": "build_binary_only!",
"type_info": "Bool"
},
{
"ordinal": 23,
"name": "job_token_scopes?",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false,
false,
true,
false,
true,
true,
true,
true,
false,
false,
false,
true,
false,
true,
true,
true,
true,
true,
false,
true,
true,
true,
null,
true
]
},
"hash": "5a975e486a0cdb0fae4dadd344ad3abc2f67827597ef74fef473e309b1951544"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT job_token_scopes FROM script WHERE hash = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Int8",
"Text"
]
},
"nullable": [
true
]
},
"hash": "60d53c73e67dd7b29cce910fd76b6c87f2994fa2d5f33e0f3ee9effe28614abe"
}
@@ -0,0 +1,331 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job_status SET\n flow_status = JSONB_SET(\n JSONB_SET(v2_job_status.flow_status, $2::TEXT[], $3),\n $4::TEXT[], $5\n ) - $6::TEXT[],\n flow_leaf_jobs = CASE\n WHEN $7::TEXT IS NULL\n OR COALESCE(v2_job.flow_innermost_root_job, v2_job_status.id) <> v2_job_status.id\n THEN v2_job_status.flow_leaf_jobs\n ELSE JSONB_SET(COALESCE(v2_job_status.flow_leaf_jobs, '{}'::JSONB), ARRAY[$7::TEXT], $8) END\n FROM v2_job_queue INNER JOIN v2_job ON v2_job.id = v2_job_queue.id\n LEFT JOIN job_perms ON job_perms.job_id = v2_job_queue.id\n WHERE v2_job_status.id = $1 AND v2_job_queue.id = $1\n RETURNING\n v2_job_queue.workspace_id,\n v2_job_queue.id,\n v2_job.args as \"args: sqlx::types::Json<HashMap<String, Box<RawValue>>>\",\n v2_job.parent_job,\n v2_job.created_by,\n v2_job_queue.started_at,\n v2_job_queue.runnable_settings_handle,\n v2_job_queue.scheduled_for,\n v2_job.runnable_path,\n v2_job.kind as \"kind: JobKind\",\n v2_job.runnable_id as \"runnable_id: ScriptHash\",\n v2_job_queue.canceled_reason,\n v2_job_queue.canceled_by,\n v2_job.permissioned_as,\n v2_job.permissioned_as_email,\n v2_job_status.flow_status as \"flow_status: sqlx::types::Json<Box<RawValue>>\",\n v2_job.tag,\n v2_job.script_lang as \"script_lang: ScriptLang\",\n v2_job.same_worker,\n v2_job.pre_run_error,\n v2_job.concurrent_limit,\n v2_job.concurrency_time_window_s,\n v2_job.flow_innermost_root_job,\n v2_job.root_job,\n v2_job.timeout,\n v2_job.flow_step_id,\n v2_job.cache_ttl,\n v2_job_queue.cache_ignore_s3_path,\n v2_job_queue.priority,\n v2_job.preprocessed,\n v2_job.script_entrypoint_override,\n v2_job.trigger,\n v2_job.trigger_kind as \"trigger_kind: TriggerKindLabel\",\n v2_job.visible_to_owner,\n NULL as permissioned_as_end_user_email,\n job_perms.job_token_scopes",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "args: sqlx::types::Json<HashMap<String, Box<RawValue>>>",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "parent_job",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "started_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "runnable_settings_handle",
"type_info": "Int8"
},
{
"ordinal": 7,
"name": "scheduled_for",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "runnable_path",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "kind: JobKind",
"type_info": {
"Custom": {
"name": "job_kind",
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub",
"identity",
"flowdependencies",
"http",
"graphql",
"postgresql",
"noop",
"appdependencies",
"deploymentcallback",
"singlestepflow",
"flowscript",
"flownode",
"appscript",
"aiagent",
"unassigned_script",
"unassigned_flow",
"unassigned_singlestepflow"
]
}
}
}
},
{
"ordinal": 10,
"name": "runnable_id: ScriptHash",
"type_info": "Int8"
},
{
"ordinal": 11,
"name": "canceled_reason",
"type_info": "Text"
},
{
"ordinal": 12,
"name": "canceled_by",
"type_info": "Varchar"
},
{
"ordinal": 13,
"name": "permissioned_as",
"type_info": "Varchar"
},
{
"ordinal": 14,
"name": "permissioned_as_email",
"type_info": "Varchar"
},
{
"ordinal": 15,
"name": "flow_status: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 16,
"name": "tag",
"type_info": "Varchar"
},
{
"ordinal": 17,
"name": "script_lang: ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang",
"dbt"
]
}
}
}
},
{
"ordinal": 18,
"name": "same_worker",
"type_info": "Bool"
},
{
"ordinal": 19,
"name": "pre_run_error",
"type_info": "Text"
},
{
"ordinal": 20,
"name": "concurrent_limit",
"type_info": "Int4"
},
{
"ordinal": 21,
"name": "concurrency_time_window_s",
"type_info": "Int4"
},
{
"ordinal": 22,
"name": "flow_innermost_root_job",
"type_info": "Uuid"
},
{
"ordinal": 23,
"name": "root_job",
"type_info": "Uuid"
},
{
"ordinal": 24,
"name": "timeout",
"type_info": "Int4"
},
{
"ordinal": 25,
"name": "flow_step_id",
"type_info": "Varchar"
},
{
"ordinal": 26,
"name": "cache_ttl",
"type_info": "Int4"
},
{
"ordinal": 27,
"name": "cache_ignore_s3_path",
"type_info": "Bool"
},
{
"ordinal": 28,
"name": "priority",
"type_info": "Int2"
},
{
"ordinal": 29,
"name": "preprocessed",
"type_info": "Bool"
},
{
"ordinal": 30,
"name": "script_entrypoint_override",
"type_info": "Varchar"
},
{
"ordinal": 31,
"name": "trigger",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "trigger_kind: TriggerKindLabel",
"type_info": {
"Custom": {
"name": "job_trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats",
"schedule",
"app",
"ui",
"postgres",
"sqs",
"gcp",
"mqtt",
"nextcloud",
"google",
"ci_test",
"github",
"azure",
"asset",
"freshness",
"amqp"
]
}
}
}
},
{
"ordinal": 33,
"name": "visible_to_owner",
"type_info": "Bool"
},
{
"ordinal": 34,
"name": "permissioned_as_end_user_email",
"type_info": "Text"
},
{
"ordinal": 35,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid",
"TextArray",
"Jsonb",
"TextArray",
"Jsonb",
"TextArray",
"Text",
"Jsonb"
]
},
"nullable": [
false,
false,
true,
true,
false,
true,
true,
false,
true,
false,
true,
true,
true,
false,
false,
true,
false,
true,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false,
null,
true
]
},
"hash": "6445041033c95fcf52c79c33f34cf6c41fb443f8bd91f12bce0e53f6e91bfb16"
}
@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "SELECT $2 IN (parent_job, root_job, flow_innermost_root_job) FROM v2_job\n WHERE id = $1 AND workspace_id = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Text"
]
},
"nullable": [
null
]
},
"hash": "67db536d06c57f195641f178ce651cbd7b8896984115d55318bb6f4100d72d9a"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 1111111111, 'f/test/error_handler', $1, 'deno', 'script', 'test-user', '{}', 'Error handler script', 'Handles failed job completions', '')\n ",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 1111111111, 'f/test/error_handler', $1, 'bun', 'script', 'test-user', '{}', 'Error handler script', 'Handles failed job completions', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
@@ -10,5 +10,5 @@
},
"nullable": []
},
"hash": "fe17aff543f28cf4d6d09ea7c4c7d18ff6a95a8402468131f5a5f33df91c59e4"
"hash": "69e1c04c246c42a3a1d7202b6fb349d0ac779431993e225945ddfb91489cb927"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO script (\n workspace_id, hash, path, parent_hashes, summary, description, content,\n created_by, created_at, archived, schema, deleted, is_template,\n extra_perms, lock, lock_error_logs, language, kind, tag,\n envs, concurrent_limit, concurrency_time_window_s, cache_ttl,\n dedicated_worker, ws_error_handler_muted, priority, timeout,\n delete_after_use, delete_after_secs, restart_unless_cancelled, concurrency_key,\n visible_to_runner_only, auto_kind, codebase, has_preprocessor,\n on_behalf_of, on_behalf_of_email, assets, modules, job_token_scopes\n )\n SELECT\n $1, hash, path, parent_hashes, summary, description, content,\n created_by, created_at, archived, schema, deleted, is_template,\n extra_perms, lock, lock_error_logs, language, kind, tag,\n envs, concurrent_limit, concurrency_time_window_s, cache_ttl,\n dedicated_worker, ws_error_handler_muted, priority, timeout,\n delete_after_use, delete_after_secs, restart_unless_cancelled, concurrency_key,\n visible_to_runner_only, auto_kind, codebase, has_preprocessor,\n -- Same three forms and the same prefix-first rule as permissioned_as_exists,\n -- superadmin fallback included: one acting outside their workspaces has no usr\n -- row but still authenticates.\n CASE WHEN on_behalf_of LIKE 'u/%' THEN\n (SELECT on_behalf_of WHERE EXISTS (\n SELECT 1 FROM usr u WHERE u.workspace_id = $1::varchar\n AND u.username = substring(on_behalf_of from 3)\n UNION ALL\n SELECT 1 FROM password p WHERE p.super_admin\n AND (p.username = substring(on_behalf_of from 3)\n OR p.email = substring(on_behalf_of from 3))))\n WHEN on_behalf_of LIKE 'g/%' THEN\n (SELECT on_behalf_of WHERE EXISTS (\n SELECT 1 FROM group_ g WHERE g.workspace_id = $1::varchar\n AND g.name = substring(on_behalf_of from 3)))\n ELSE\n (SELECT on_behalf_of WHERE EXISTS (\n SELECT 1 FROM usr u WHERE u.workspace_id = $1::varchar\n AND u.username = on_behalf_of\n UNION ALL\n SELECT 1 FROM password p WHERE p.email = on_behalf_of\n AND p.super_admin))\n END, on_behalf_of_email, assets, modules, job_token_scopes\n FROM script\n WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": []
},
"hash": "706f2227e34971d22a577b33f6aaa7f5755da9997419c4a9d07b30d4da318bea"
}
@@ -0,0 +1,45 @@
{
"db_name": "PostgreSQL",
"query": "WITH deleted AS (\n DELETE FROM v2_job_queue WHERE id = $1\n RETURNING id, workspace_id, started_at, worker, canceled_by, canceled_reason,\n (extras->>'wac_first_started_at')::timestamptz AS first_started_at,\n COALESCE($9::bigint, (EXTRACT('epoch' FROM (now())) - EXTRACT('epoch' FROM (COALESCE(started_at, now()))))*1000)::bigint AS run_ms\n ), completed AS (\n INSERT INTO v2_job_completed AS cj\n ( workspace_id\n , id\n , started_at\n , duration_ms\n , extras\n , result\n , result_columns\n , canceled_by\n , canceled_reason\n , flow_status\n , workflow_as_code_status\n , memory_peak\n , status\n , worker\n )\n SELECT d.workspace_id, d.id, COALESCE(d.first_started_at, d.started_at),\n CASE WHEN d.first_started_at IS NULL THEN d.run_ms\n ELSE EXTRACT('epoch' FROM (now() - d.first_started_at))*1000 END,\n CASE WHEN d.first_started_at IS NOT NULL\n THEN jsonb_build_object('wac_last_segment_ms', d.run_ms) END,\n $3::text::jsonb, $10,\n CASE WHEN $4::BOOL THEN $5 ELSE d.canceled_by END,\n CASE WHEN $4::BOOL THEN $6 WHEN d.canceled_by IS NOT NULL THEN d.canceled_reason END,\n s.flow_status, s.workflow_as_code_status, $8,\n CASE WHEN $4::BOOL OR d.canceled_by IS NOT NULL THEN 'canceled'::job_status\n WHEN $7::BOOL THEN 'skipped'::job_status\n WHEN $2::BOOL THEN 'success'::job_status\n ELSE 'failure'::job_status END,\n d.worker\n FROM deleted d LEFT JOIN v2_job_status s ON s.id = d.id\n ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status, result = $3::text::jsonb,\n canceled_by = CASE WHEN NOT $4::BOOL AND EXCLUDED.canceled_by IS NOT NULL\n THEN EXCLUDED.canceled_by ELSE cj.canceled_by END,\n canceled_reason = CASE WHEN NOT $4::BOOL AND EXCLUDED.canceled_by IS NOT NULL\n THEN EXCLUDED.canceled_reason ELSE cj.canceled_reason END\n RETURNING cj.started_at, cj.duration_ms,\n COALESCE((cj.extras->>'wac_last_segment_ms')::bigint, cj.duration_ms) AS last_run_ms\n ), parent_ping AS (\n UPDATE v2_job_runtime r SET ping = now()\n FROM v2_job_queue q\n WHERE r.id = $11 AND q.id = r.id AND q.workspace_id = $12\n AND EXISTS (SELECT 1 FROM completed)\n )\n SELECT started_at AS \"started_at?\", duration_ms AS \"duration_ms!\",\n last_run_ms AS \"last_run_ms!\" FROM completed",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "started_at?",
"type_info": "Timestamptz"
},
{
"ordinal": 1,
"name": "duration_ms!",
"type_info": "Int8"
},
{
"ordinal": 2,
"name": "last_run_ms!",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid",
"Bool",
"Text",
"Bool",
"Varchar",
"Text",
"Bool",
"Int4",
"Int8",
"TextArray",
"Uuid",
"Text"
]
},
"nullable": [
true,
false,
null
]
},
"hash": "71c9e0c0f1d9eba0f24c8e410ca2f2a64dc559e3228d3b763f68b1ad3491ae6e"
}
@@ -1,38 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n id,\n runnable_path,\n permissioned_as_email,\n parent_job\n FROM v2_job\n WHERE workspace_id = 'test-workspace'\n AND permissioned_as_email = 'success_handler@windmill.dev'\n ORDER BY created_at DESC\n LIMIT 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "runnable_path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "permissioned_as_email",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "parent_job",
"type_info": "Uuid"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
true,
false,
true
]
},
"hash": "71de038f332593e2177f33284854b6c0bfe9bb4999f2c4e9082a4c5f3b341496"
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
{
"db_name": "PostgreSQL",
"query": "SELECT coalesce(flow_version_lite.value, flow_version.value) as \"value!: sqlx::types::Json<Box<RawValue>>\", flow.job_token_scopes FROM flow\n LEFT JOIN flow_version\n ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]\n LEFT JOIN flow_version_lite\n ON flow_version_lite.id = flow_version.id\n WHERE flow.path = $1 AND flow.workspace_id = $2 LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value!: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 1,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null,
true
]
},
"hash": "77e9cb16c25defc2423621a64f020e1e07f7e50df82fb6c33f79e6faa5b77bab"
}
@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "SELECT wp.draining FROM v2_job j\n JOIN v2_job_queue q ON q.id = j.id\n JOIN worker_ping wp ON wp.worker = q.worker\n WHERE j.id = $1 AND j.workspace_id = $2 AND q.running AND q.started_at IS NOT NULL\n AND ($3::text[] IS NULL OR j.tag = ANY($3))",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "draining",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Text",
"TextArray"
]
},
"nullable": [
false
]
},
"hash": "7963eff5f7109874b94c0940eaef7d4b418a9e82be56dfe7dd65d160e0dcfd13"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT restart_unless_cancelled, timeout FROM script WHERE hash = $1 AND workspace_id = $2",
"query": "SELECT restart_unless_cancelled, timeout, job_token_scopes FROM script WHERE hash = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
@@ -12,6 +12,11 @@
"ordinal": 1,
"name": "timeout",
"type_info": "Int4"
},
{
"ordinal": 2,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
@@ -21,9 +26,10 @@
]
},
"nullable": [
true,
true,
true
]
},
"hash": "1debd472c9ffd2fc78877484f93db51f9aabed54f9894eda8ad610053ad76ce6"
"hash": "83e9c830ee816d4e4e7193a67823cab7c9a4461d3bfbdc0fe7dbdd28ae2de924"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', $1, 'f/test/success_script', 'export function main() { return \"ok\"; }', 'deno', 'script', 'test-user', '{}', '', '', '')\n ",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', $1, 'f/test/success_script', 'export function main() { return \"ok\"; }', 'bun', 'script', 'test-user', '{}', '', '', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
@@ -10,5 +10,5 @@
},
"nullable": []
},
"hash": "51f18c817d4014e847486f5a8dbf205ffa0e53d5bd3fdb97777e988389b1d69e"
"hash": "8511e096394edb1433f6572d50b66d8558866af53d829d83fa634f12a90733c0"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO global_settings (name, value) VALUES ($1, 'true'::jsonb) ON CONFLICT (name) DO NOTHING",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar"
]
},
"nullable": []
},
"hash": "8645e610aa35088376d0919132459bce3ad17df617855e5fcf838f6349e68c97"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "WITH RECURSIVE chain(id, parent_job) AS (\n SELECT id, parent_job FROM v2_job WHERE id = $1 AND workspace_id = $2\n UNION ALL\n SELECT j.id, j.parent_job FROM v2_job j\n JOIN chain c ON j.id = c.parent_job AND j.workspace_id = $2\n )\n SELECT\n CASE WHEN a.agent THEN regexp_replace(j.runnable_path, '\\.chat$', '')\n ELSE j.runnable_path END AS runnable_path,\n CASE\n WHEN a.agent THEN 'agents'\n WHEN j.kind IN ('script', 'script_hub', 'unassigned_script') THEN 'scripts'\n WHEN j.kind IN ('flow', 'unassigned_flow') THEN 'flows'\n WHEN j.kind IN ('singlestepflow', 'unassigned_singlestepflow') THEN\n CASE WHEN COALESCE(\n (SELECT m->'value'->>'type'\n FROM jsonb_array_elements(j.raw_flow->'modules') m\n WHERE m->>'id' IN ('a', 'main')\n LIMIT 1),\n 'script'\n ) = 'flow' THEN 'flows' ELSE 'scripts' END\n END AS scope_kind,\n CASE WHEN j.trigger_kind = 'app' THEN j.trigger END AS launched_by_app\n FROM v2_job j JOIN chain c ON c.id = j.id,\n LATERAL (SELECT j.kind = 'flowpreview'\n AND j.raw_flow->'modules'->1 IS NULL\n AND j.raw_flow->'modules'->0->>'id' = '__wm_agent_root' AS agent) a\n WHERE j.workspace_id = $2",
"query": "WITH RECURSIVE chain(id, parent_job) AS (\n SELECT id, parent_job FROM v2_job WHERE id = $1 AND workspace_id = $2\n UNION ALL\n SELECT j.id, j.parent_job FROM v2_job j\n JOIN chain c ON j.id = c.parent_job AND j.workspace_id = $2\n )\n SELECT\n CASE WHEN a.agent THEN regexp_replace(j.runnable_path, '\\.chat$', '')\n ELSE j.runnable_path END AS runnable_path,\n CASE\n WHEN a.agent THEN 'agents'\n WHEN j.kind IN ('script', 'script_hub', 'unassigned_script') THEN 'scripts'\n WHEN j.kind IN ('flow', 'unassigned_flow') THEN 'flows'\n WHEN j.kind IN ('dependencies', 'flowdependencies') THEN 'dependencies'\n WHEN j.kind IN ('singlestepflow', 'unassigned_singlestepflow') THEN\n CASE WHEN COALESCE(\n (SELECT m->'value'->>'type'\n FROM jsonb_array_elements(j.raw_flow->'modules') m\n WHERE m->>'id' IN ('a', 'main')\n LIMIT 1),\n 'script'\n ) = 'flow' THEN 'flows' ELSE 'scripts' END\n END AS scope_kind,\n CASE WHEN j.trigger_kind = 'app' THEN j.trigger END AS launched_by_app\n FROM v2_job j JOIN chain c ON c.id = j.id,\n LATERAL (SELECT j.kind = 'flowpreview'\n AND j.raw_flow->'modules'->1 IS NULL\n AND j.raw_flow->'modules'->0->>'id' = '__wm_agent_root' AS agent) a\n WHERE j.workspace_id = $2",
"describe": {
"columns": [
{
@@ -31,5 +31,5 @@
null
]
},
"hash": "7904ac35748b1de2c7ff764f22787436d0fe74f99f298e5c399233f0d247f2ec"
"hash": "8aef4f9d27ec6df07cd671bcf90bf378e9fac4986cd29f69c1f2b8a83ba515c3"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT ON (path)\n path,\n value as \"value!: sqlx::types::Json<Box<serde_json::value::RawValue>>\",\n created_at,\n typ::text as \"typ!\"\n FROM draft\n WHERE workspace_id = $1\n AND typ IN ('app', 'raw_app')\n AND (email = $2 OR email IS NULL)\n AND NOT EXISTS (\n SELECT 1 FROM app a\n WHERE a.workspace_id = draft.workspace_id\n AND a.path = draft.path\n )\n ORDER BY path, (email IS NULL), created_at DESC",
"query": "SELECT DISTINCT ON (path)\n path,\n value as \"value!: sqlx::types::Json<Box<serde_json::value::RawValue>>\",\n created_at,\n email IS NULL as \"legacy!\"\n FROM draft\n WHERE workspace_id = $1\n AND typ = 'flow'\n AND (email = $2 OR email IS NULL)\n AND NOT EXISTS (\n SELECT 1 FROM flow f\n WHERE f.workspace_id = draft.workspace_id\n AND f.path = draft.path\n )\n ORDER BY path, (email IS NULL)",
"describe": {
"columns": [
{
@@ -20,8 +20,8 @@
},
{
"ordinal": 3,
"name": "typ!",
"type_info": "Text"
"name": "legacy!",
"type_info": "Bool"
}
],
"parameters": {
@@ -37,5 +37,5 @@
null
]
},
"hash": "1860c102a5309a8e1bb7288d0616f48e4330af7fbe61426e999c6073f630d88f"
"hash": "8f5091626054a43be07768f30cdc99bd68f1de8064ace4155f4da2cd45d1b403"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COALESCE(config->'paused' = 'true'::jsonb, false) FROM config WHERE name = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "coalesce",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "91fdd565bd210f8aa4c6d5f5e309573aefaeb5dbc6ac07f5e664bc8fe2cb2683"
}
@@ -1,31 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "WITH deleted AS (\n DELETE FROM v2_job_queue WHERE id = $1\n RETURNING id, workspace_id, started_at, worker, canceled_by, canceled_reason\n ), completed AS (\n INSERT INTO v2_job_completed AS cj\n ( workspace_id\n , id\n , started_at\n , duration_ms\n , result\n , result_columns\n , canceled_by\n , canceled_reason\n , flow_status\n , workflow_as_code_status\n , memory_peak\n , status\n , worker\n )\n SELECT d.workspace_id, d.id, d.started_at,\n COALESCE($9::bigint, (EXTRACT('epoch' FROM (now())) - EXTRACT('epoch' FROM (COALESCE(d.started_at, now()))))*1000),\n $3::text::jsonb, $10,\n CASE WHEN $4::BOOL THEN $5 ELSE d.canceled_by END,\n CASE WHEN $4::BOOL THEN $6 WHEN d.canceled_by IS NOT NULL THEN d.canceled_reason END,\n s.flow_status, s.workflow_as_code_status, $8,\n CASE WHEN $4::BOOL OR d.canceled_by IS NOT NULL THEN 'canceled'::job_status\n WHEN $7::BOOL THEN 'skipped'::job_status\n WHEN $2::BOOL THEN 'success'::job_status\n ELSE 'failure'::job_status END,\n d.worker\n FROM deleted d LEFT JOIN v2_job_status s ON s.id = d.id\n ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status, result = $3::text::jsonb,\n canceled_by = CASE WHEN NOT $4::BOOL AND EXCLUDED.canceled_by IS NOT NULL\n THEN EXCLUDED.canceled_by ELSE cj.canceled_by END,\n canceled_reason = CASE WHEN NOT $4::BOOL AND EXCLUDED.canceled_by IS NOT NULL\n THEN EXCLUDED.canceled_reason ELSE cj.canceled_reason END\n RETURNING duration_ms\n )\n SELECT duration_ms AS \"duration_ms!\" FROM completed",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "duration_ms!",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid",
"Bool",
"Text",
"Bool",
"Varchar",
"Text",
"Bool",
"Int4",
"Int8",
"TextArray"
]
},
"nullable": [
false
]
},
"hash": "9212902d4eb2834ab3b429968a7a85c53c49e4ef0f42c146324d5c71fbd1e21d"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (SELECT 1 FROM v2_job_queue WHERE id = $1 AND workspace_id = $2 AND running)",
"query": "SELECT EXISTS (SELECT 1 FROM global_settings WHERE name = $1)",
"describe": {
"columns": [
{
@@ -11,7 +11,6 @@
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
@@ -19,5 +18,5 @@
null
]
},
"hash": "ee769c78ec0a782de18911cdcb655aad93cf23321cd0f42f7ffa5348bfbea26e"
"hash": "966b065bd6bbbff9e0ca15bee504f9cfe5e3a75427767de41e5b85c797f7d58a"
}
@@ -1,33 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "WITH deleted AS (\n DELETE FROM v2_job_queue WHERE id = $1\n RETURNING id, workspace_id, started_at, worker, canceled_by, canceled_reason\n ), completed AS (\n INSERT INTO v2_job_completed AS cj\n ( workspace_id\n , id\n , started_at\n , duration_ms\n , result\n , result_columns\n , canceled_by\n , canceled_reason\n , flow_status\n , workflow_as_code_status\n , memory_peak\n , status\n , worker\n )\n SELECT d.workspace_id, d.id, d.started_at,\n COALESCE($9::bigint, (EXTRACT('epoch' FROM (now())) - EXTRACT('epoch' FROM (COALESCE(d.started_at, now()))))*1000),\n $3::text::jsonb, $10,\n CASE WHEN $4::BOOL THEN $5 ELSE d.canceled_by END,\n CASE WHEN $4::BOOL THEN $6 WHEN d.canceled_by IS NOT NULL THEN d.canceled_reason END,\n s.flow_status, s.workflow_as_code_status, $8,\n CASE WHEN $4::BOOL OR d.canceled_by IS NOT NULL THEN 'canceled'::job_status\n WHEN $7::BOOL THEN 'skipped'::job_status\n WHEN $2::BOOL THEN 'success'::job_status\n ELSE 'failure'::job_status END,\n d.worker\n FROM deleted d LEFT JOIN v2_job_status s ON s.id = d.id\n ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status, result = $3::text::jsonb,\n canceled_by = CASE WHEN NOT $4::BOOL AND EXCLUDED.canceled_by IS NOT NULL\n THEN EXCLUDED.canceled_by ELSE cj.canceled_by END,\n canceled_reason = CASE WHEN NOT $4::BOOL AND EXCLUDED.canceled_by IS NOT NULL\n THEN EXCLUDED.canceled_reason ELSE cj.canceled_reason END\n RETURNING duration_ms\n ), parent_ping AS (\n UPDATE v2_job_runtime r SET ping = now()\n FROM v2_job_queue q\n WHERE r.id = $11 AND q.id = r.id AND q.workspace_id = $12\n AND EXISTS (SELECT 1 FROM completed)\n )\n SELECT duration_ms AS \"duration_ms!\" FROM completed",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "duration_ms!",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid",
"Bool",
"Text",
"Bool",
"Varchar",
"Text",
"Bool",
"Int4",
"Int8",
"TextArray",
"Uuid",
"Text"
]
},
"nullable": [
false
]
},
"hash": "975158ae72ec12f3f933fba1d9623bf1c925feebe746299cd1f0eda3f8b949d5"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM runnable_job_stats WHERE hour < $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": []
},
"hash": "97d8a9835344b8c72d59afc99d76b681c5120ef29eb09b8626a3fbc43a32cc0e"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT ON (path)\n path,\n value as \"value!: sqlx::types::Json<Box<serde_json::value::RawValue>>\",\n created_at\n FROM draft\n WHERE workspace_id = $1\n AND typ = 'flow'\n AND (email = $2 OR email IS NULL)\n AND NOT EXISTS (\n SELECT 1 FROM flow f\n WHERE f.workspace_id = draft.workspace_id\n AND f.path = draft.path\n )\n ORDER BY path, (email IS NULL)",
"query": "SELECT DISTINCT ON (path)\n path,\n value as \"value!: sqlx::types::Json<Box<serde_json::value::RawValue>>\",\n created_at,\n email IS NULL as \"legacy!\"\n FROM draft\n WHERE workspace_id = $1\n AND typ = 'script'\n AND (email = $2 OR email IS NULL)\n AND NOT EXISTS (\n SELECT 1 FROM script s\n WHERE s.workspace_id = draft.workspace_id\n AND s.path = draft.path\n )\n ORDER BY path, (email IS NULL)",
"describe": {
"columns": [
{
@@ -17,6 +17,11 @@
"ordinal": 2,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 3,
"name": "legacy!",
"type_info": "Bool"
}
],
"parameters": {
@@ -28,8 +33,9 @@
"nullable": [
false,
false,
false
false,
null
]
},
"hash": "5223412e366b22d953867425ed6156a66727e7a469abad1664ee03a3da31078a"
"hash": "9a29bd07a66f31f7414b79cafd8073194c6990eedad4b5b540134dd13d72abb1"
}
@@ -0,0 +1,17 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job_queue\n SET suspend = $3, suspend_until = now() + make_interval(secs => $4), started_at = null,\n extras = CASE WHEN started_at IS NULL OR extras ? 'wac_first_started_at' THEN extras\n ELSE jsonb_set(COALESCE(extras, '{}'::jsonb), '{wac_first_started_at}', to_jsonb(started_at))\n END\n WHERE id = $1 AND workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Text",
"Int4",
"Float8"
]
},
"nullable": []
},
"hash": "9e7a5e1ebba42217092971dd340cd9182a4812b14735e502958eaafeb4c6b33d"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT usr.email, usage.executions\n FROM usr, LATERAL (\n SELECT COALESCE(SUM(c.duration_ms + 1000)/1000 , 0)::BIGINT executions\n FROM v2_job_completed c JOIN v2_job j USING (id)\n WHERE j.workspace_id = $1\n AND j.kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlestepflow')\n AND j.permissioned_as_email = usr.email\n AND now() - '1 week'::interval < j.created_at\n ) usage\n WHERE workspace_id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "executions",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
null
]
},
"hash": "a2f6ca89faaa8d8739f67cd1aae571de793b377dd6058065f51b12c974e5b665"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COALESCE(config->'paused' = 'true'::jsonb, false) FROM config WHERE name = $1 FOR UPDATE",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "coalesce",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "a6d355b3121f199f3827c05aaa7c8f780ab4c9d3d373d3cd0bb489e0d173040c"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, step_name, success, tool_arguments, tool_result, reasoning, attachments)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
"query": "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, turn_job_id, step_name, success, tool_arguments, tool_result, reasoning, attachments)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
"describe": {
"columns": [],
"parameters": {
@@ -20,6 +20,7 @@
},
"Text",
"Uuid",
"Uuid",
"Varchar",
"Bool",
"Text",
@@ -30,5 +31,5 @@
},
"nullable": []
},
"hash": "12329c3359a7944ab5fa3aa27ddca1b26f340ccf574b9fa07641fe88b2d2987c"
"hash": "a6dafb34be6088886b078ed2b554de8c72e312ef8abd5ed29482a59c8ec51dd7"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT q.id AS \"id!\", j.created_by, j.permissioned_as, j.permissioned_as_email, j.trigger, j.trigger_kind AS \"trigger_kind: TriggerKindLabel\", j.preprocessed, j.args AS \"args: sqlx::types::Json<HashMap<String, Box<RawValue>>>\" FROM v2_job_queue q JOIN v2_job j USING (id) JOIN script s ON s.workspace_id = j.workspace_id AND s.hash = j.runnable_id WHERE j.workspace_id = $1 AND j.runnable_path = $2 AND j.kind = 'script' AND j.flow_step_id IS NULL AND j.runnable_id != $3 AND q.canceled_by IS NULL AND s.restart_unless_cancelled",
"query": "SELECT q.id AS \"id!\", j.created_by, j.permissioned_as, j.permissioned_as_email, j.trigger, j.trigger_kind AS \"trigger_kind: TriggerKindLabel\", j.preprocessed, j.args AS \"args: sqlx::types::Json<HashMap<String, Box<RawValue>>>\", p.job_token_scopes AS \"job_token_scopes?\" FROM v2_job_queue q JOIN v2_job j USING (id) JOIN script s ON s.workspace_id = j.workspace_id AND s.hash = j.runnable_id LEFT JOIN job_perms p ON p.job_id = q.id WHERE j.workspace_id = $1 AND j.runnable_path = $2 AND j.kind = 'script' AND j.flow_step_id IS NULL AND j.runnable_id != $3 AND q.canceled_by IS NULL AND s.restart_unless_cancelled",
"describe": {
"columns": [
{
@@ -71,6 +71,11 @@
"ordinal": 7,
"name": "args: sqlx::types::Json<HashMap<String, Box<RawValue>>>",
"type_info": "Jsonb"
},
{
"ordinal": 8,
"name": "job_token_scopes?",
"type_info": "TextArray"
}
],
"parameters": {
@@ -88,8 +93,9 @@
true,
true,
true,
true,
true
]
},
"hash": "df8586283178b0e684b9a0e359efb16e38fd68a5fe2b01cd77f74a725bbf37a3"
"hash": "aed606f8c8d91a924ac457b4eabdf391947d5fc3da90ef98a7b793c2430eb7bc"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', $1, 'f/test/failing_script', $2, 'deno', 'script', 'test-user', '{}', 'Failing test script', 'A script that always fails', '')\n ",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', $1, 'f/test/failing_script', $2, 'bun', 'script', 'test-user', '{}', 'Failing test script', 'A script that always fails', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
@@ -11,5 +11,5 @@
},
"nullable": []
},
"hash": "d2a9a9af4d00c1c05276c14e6f32044437800a4b0c60aa364ab2f362a4fd9a2c"
"hash": "b0c10d17ed684af4dc79db7a199d4438ea003b5762178f25ff12ef23c1a8f46a"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM script WHERE workspace_id = $1 AND hash = $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Int8"
]
},
"nullable": [
null
]
},
"hash": "b159cc3ab6fddcfb561c90d20bee2ff605a1c3721a4cbcc080f98fbb87277c37"
}
@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, job_token_scopes)\n SELECT workspace_id, REGEXP_REPLACE(path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1'), summary, description, archived, extra_perms, dependency_job, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, job_token_scopes\n FROM flow\n WHERE path LIKE ('u/' || $2 || '/%') AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "b40c9e2d637cf0f2f49fd4c720b64eb6af24e8d8aa99b846f21f2ed49c320bdc"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT job_token_scopes FROM script WHERE path = $1 AND workspace_id = $2 AND deleted = false ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
true
]
},
"hash": "b48afe9913423a90955011fc6368b8517561f5b55a30e44801d6a9123a762584"
}
@@ -0,0 +1,102 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, delete_after_secs, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, schema_validation, assets, debounce_key, debounce_delay_s, cache_ignore_s3_path, runnable_settings_handle, modules, labels, on_behalf_of, on_behalf_of_email, job_token_scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Int8",
"Varchar",
"Int8Array",
"Text",
"Text",
"Text",
"Varchar",
"Text",
"Bool",
"Jsonb",
"Text",
{
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang",
"dbt"
]
}
}
},
{
"Custom": {
"name": "script_kind",
"kind": {
"Enum": [
"script",
"trigger",
"failure",
"command",
"approval",
"preprocessor"
]
}
}
},
"Varchar",
"VarcharArray",
"Int4",
"Int4",
"Int4",
"Bool",
"Bool",
"Int2",
"Bool",
"Bool",
"Int4",
"Int4",
"Varchar",
"Bool",
"Varchar",
"Varchar",
"Bool",
"Bool",
"Jsonb",
"Varchar",
"Int4",
"Bool",
"Int8",
"Jsonb",
"TextArray",
"Varchar",
"Text",
"TextArray"
]
},
"nullable": []
},
"hash": "bfd01122256e922b00acf0e86593007c6aeccf76bfd07384ffaccf50a24d13d4"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM token WHERE email = $1 AND label = 'session' AND token_hash != $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "c3c51c3536eaa6a5e702d306344db63d19f1c9ab0366e01c0092aa653ab51877"
}
@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "WITH inserted AS (\n INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, labels, lock_error_logs, job_token_scopes)\n SELECT workspace_id, REGEXP_REPLACE(path, 'u/' || $2 || '/(.*)', $1 || '/\\1'), summary, description, archived, extra_perms, dependency_job, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, labels, lock_error_logs, job_token_scopes\n FROM flow\n WHERE path LIKE ('u/' || $2 || '/%') AND workspace_id = $3\n RETURNING 1\n ) SELECT COUNT(*) FROM inserted",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "c4eaa6e3b1d30a72ef1b54b2b7f28d84f1ca3c91de86d520dce06ac12d557bd5"
}
@@ -0,0 +1,74 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT workspace_id, runnable_path, worker_group,\n SUM(job_count)::bigint AS \"job_count!\",\n SUM(total_duration_ms)::bigint AS \"total_duration_ms!\",\n MAX(max_memory_peak) AS \"max_memory_peak!\",\n SUM(sum_memory_peak)::bigint AS \"sum_memory_peak!\",\n SUM(memory_sample_count)::bigint AS \"memory_sample_count!\",\n SUM(total_cpu_ms)::bigint AS \"total_cpu_ms!\"\n FROM runnable_job_stats\n WHERE hour >= $1\n AND ($2::text IS NULL OR worker_group = $2)\n AND ($3::text IS NULL OR workspace_id = $3)\n GROUP BY workspace_id, runnable_path, worker_group\n ORDER BY CASE $4::text\n WHEN 'max_memory' THEN MAX(max_memory_peak)::numeric\n WHEN 'cpu' THEN SUM(total_cpu_ms)\n ELSE SUM(total_duration_ms)\n END DESC, workspace_id, runnable_path, worker_group\n LIMIT $5\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "runnable_path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "worker_group",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "job_count!",
"type_info": "Int8"
},
{
"ordinal": 4,
"name": "total_duration_ms!",
"type_info": "Int8"
},
{
"ordinal": 5,
"name": "max_memory_peak!",
"type_info": "Int4"
},
{
"ordinal": 6,
"name": "sum_memory_peak!",
"type_info": "Int8"
},
{
"ordinal": 7,
"name": "memory_sample_count!",
"type_info": "Int8"
},
{
"ordinal": 8,
"name": "total_cpu_ms!",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Int8",
"Text",
"Text",
"Text",
"Int8"
]
},
"nullable": [
false,
false,
false,
null,
null,
null,
null,
null,
null
]
},
"hash": "c5971326bdbfaa7dff74689d1365db4f26c41fa56b326dbd02e604c793a13477"
}
@@ -1,33 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO worker_ping (worker_instance, worker, ip, custom_tags, worker_group, dedicated_worker, dedicated_workers, wm_version, vcpus, memory, job_isolation, native_mode) VALUES ($1, $2, COALESCE($3, 'NO IP'), $4, $5, $6, $7, $8, $9, $10, $11, $12) ON CONFLICT (worker)\n DO UPDATE set ping_at = now(), worker_instance = EXCLUDED.worker_instance, ip = COALESCE($3, worker_ping.ip), custom_tags = EXCLUDED.custom_tags, worker_group = EXCLUDED.worker_group, dedicated_worker = EXCLUDED.dedicated_worker, dedicated_workers = EXCLUDED.dedicated_workers, wm_version = EXCLUDED.wm_version, vcpus = COALESCE(EXCLUDED.vcpus, worker_ping.vcpus), memory = COALESCE(EXCLUDED.memory, worker_ping.memory), job_isolation = EXCLUDED.job_isolation, native_mode = EXCLUDED.native_mode, current_job_id = NULL, current_job_workspace_id = NULL\n RETURNING jobs_executed",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "jobs_executed",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Text",
"TextArray",
"Varchar",
"Varchar",
"TextArray",
"Varchar",
"Int8",
"Int8",
"Text",
"Bool"
]
},
"nullable": [
false
]
},
"hash": "c748617e060bc41b5922df4b433f20b6971b993e0671b6ccb45db5ef028550bc"
}
@@ -0,0 +1,65 @@
{
"db_name": "PostgreSQL",
"query": "SELECT email, username, is_admin, is_operator, groups, folders, end_user_email,\n job_token_scopes\n FROM job_perms WHERE job_id = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "username",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "is_admin",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "is_operator",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "groups",
"type_info": "TextArray"
},
{
"ordinal": 5,
"name": "folders",
"type_info": "JsonbArray"
},
{
"ordinal": 6,
"name": "end_user_email",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
true,
true
]
},
"hash": "c921b1a03e3181bbac351545941affc87853ff2d97f567a8817260cfef43e00e"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 5555555555, 'f/test/error_handler', 'export function main() { return \"handled\"; }', 'deno', 'script', 'test-user', '{}', '', '', '')\n ",
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 5555555555, 'f/test/error_handler', 'export function main() { return \"handled\"; }', 'bun', 'script', 'test-user', '{}', '', '', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
@@ -8,5 +8,5 @@
},
"nullable": []
},
"hash": "cdc594b30855e9384481f561b2c16200d4e6dacb1eb274513c8f1795235dfe20"
"hash": "cc719da4da98b6fe9612a4cc2f42dd19834a3e0d0be593ea6bc1239fe5453a74"
}
@@ -0,0 +1,43 @@
{
"db_name": "PostgreSQL",
"query": "WITH deleted AS (\n DELETE FROM v2_job_queue WHERE id = $1\n RETURNING id, workspace_id, started_at, worker, canceled_by, canceled_reason,\n (extras->>'wac_first_started_at')::timestamptz AS first_started_at,\n COALESCE($9::bigint, (EXTRACT('epoch' FROM (now())) - EXTRACT('epoch' FROM (COALESCE(started_at, now()))))*1000)::bigint AS run_ms\n ), completed AS (\n INSERT INTO v2_job_completed AS cj\n ( workspace_id\n , id\n , started_at\n , duration_ms\n , extras\n , result\n , result_columns\n , canceled_by\n , canceled_reason\n , flow_status\n , workflow_as_code_status\n , memory_peak\n , status\n , worker\n )\n SELECT d.workspace_id, d.id, COALESCE(d.first_started_at, d.started_at),\n CASE WHEN d.first_started_at IS NULL THEN d.run_ms\n ELSE EXTRACT('epoch' FROM (now() - d.first_started_at))*1000 END,\n CASE WHEN d.first_started_at IS NOT NULL\n THEN jsonb_build_object('wac_last_segment_ms', d.run_ms) END,\n $3::text::jsonb, $10,\n CASE WHEN $4::BOOL THEN $5 ELSE d.canceled_by END,\n CASE WHEN $4::BOOL THEN $6 WHEN d.canceled_by IS NOT NULL THEN d.canceled_reason END,\n s.flow_status, s.workflow_as_code_status, $8,\n CASE WHEN $4::BOOL OR d.canceled_by IS NOT NULL THEN 'canceled'::job_status\n WHEN $7::BOOL THEN 'skipped'::job_status\n WHEN $2::BOOL THEN 'success'::job_status\n ELSE 'failure'::job_status END,\n d.worker\n FROM deleted d LEFT JOIN v2_job_status s ON s.id = d.id\n ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status, result = $3::text::jsonb,\n canceled_by = CASE WHEN NOT $4::BOOL AND EXCLUDED.canceled_by IS NOT NULL\n THEN EXCLUDED.canceled_by ELSE cj.canceled_by END,\n canceled_reason = CASE WHEN NOT $4::BOOL AND EXCLUDED.canceled_by IS NOT NULL\n THEN EXCLUDED.canceled_reason ELSE cj.canceled_reason END\n RETURNING cj.started_at, cj.duration_ms,\n COALESCE((cj.extras->>'wac_last_segment_ms')::bigint, cj.duration_ms) AS last_run_ms\n )\n SELECT started_at AS \"started_at?\", duration_ms AS \"duration_ms!\",\n last_run_ms AS \"last_run_ms!\" FROM completed",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "started_at?",
"type_info": "Timestamptz"
},
{
"ordinal": 1,
"name": "duration_ms!",
"type_info": "Int8"
},
{
"ordinal": 2,
"name": "last_run_ms!",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid",
"Bool",
"Text",
"Bool",
"Varchar",
"Text",
"Bool",
"Int4",
"Int8",
"TextArray"
]
},
"nullable": [
true,
false,
null
]
},
"hash": "ce39fd9650500b16f7247c8173a40c7e5d2d8a51aea2d36f2bc8c6f86d53a9b8"
}
@@ -0,0 +1,30 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n flow\n SET\n path = $1,\n summary = $2,\n description = $3,\n dependency_job = NULL,\n lock_error_logs = '',\n tag = $4,\n dedicated_worker = $5,\n visible_to_runner_only = $6,\n ws_error_handler_muted = $7,\n value = $8,\n schema = $9::text::json,\n edited_by = $10,\n edited_at = now(),\n labels = COALESCE($13, labels),\n on_behalf_of = $14,\n on_behalf_of_email = $15,\n job_token_scopes = CASE WHEN $16 THEN $17 ELSE job_token_scopes END\n WHERE\n path = $11 AND workspace_id = $12",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text",
"Varchar",
"Bool",
"Bool",
"Bool",
"Jsonb",
"Text",
"Varchar",
"Text",
"Text",
"TextArray",
"Varchar",
"Text",
"Bool",
"TextArray"
]
},
"nullable": []
},
"hash": "ce3bccee14cd107631c4ddb4a467099be925f1058c76c6af31e8a620607cf6a1"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM runnable_job_stats WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "d2fbaaaea6c542342862d8b535673d19dc4ca721ab656a39330bad5ea48999d8"
}
@@ -0,0 +1,159 @@
{
"db_name": "PostgreSQL",
"query": "select hash, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, debounce_key, debounce_delay_s, cache_ttl, cache_ignore_s3_path, runnable_settings_handle, language as \"language: ScriptLang\", dedicated_worker, priority, timeout, on_behalf_of, created_by, labels, job_token_scopes FROM script\n WHERE path = $1 AND workspace_id = $2 AND archived = false AND (lock IS NOT NULL OR $3 = false)\n ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "hash",
"type_info": "Int8"
},
{
"ordinal": 1,
"name": "tag",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "concurrency_key",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "concurrent_limit",
"type_info": "Int4"
},
{
"ordinal": 4,
"name": "concurrency_time_window_s",
"type_info": "Int4"
},
{
"ordinal": 5,
"name": "debounce_key",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "debounce_delay_s",
"type_info": "Int4"
},
{
"ordinal": 7,
"name": "cache_ttl",
"type_info": "Int4"
},
{
"ordinal": 8,
"name": "cache_ignore_s3_path",
"type_info": "Bool"
},
{
"ordinal": 9,
"name": "runnable_settings_handle",
"type_info": "Int8"
},
{
"ordinal": 10,
"name": "language: ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang",
"dbt"
]
}
}
}
},
{
"ordinal": 11,
"name": "dedicated_worker",
"type_info": "Bool"
},
{
"ordinal": 12,
"name": "priority",
"type_info": "Int2"
},
{
"ordinal": 13,
"name": "timeout",
"type_info": "Int4"
},
{
"ordinal": 14,
"name": "on_behalf_of",
"type_info": "Varchar"
},
{
"ordinal": 15,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 16,
"name": "labels",
"type_info": "TextArray"
},
{
"ordinal": 17,
"name": "job_token_scopes",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Bool"
]
},
"nullable": [
false,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false,
true,
true,
true,
true,
false,
true,
true
]
},
"hash": "d51f555e80b27549b884f334087878286dcc2f23101c2e1c8c1d07b6f0deaecd"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM flow_conversation_message WHERE job_id = ANY($1) RETURNING conversation_id",
"query": "DELETE FROM flow_conversation_message WHERE COALESCE(turn_job_id, job_id) = ANY($1)\n RETURNING conversation_id",
"describe": {
"columns": [
{
@@ -18,5 +18,5 @@
false
]
},
"hash": "967f52005f4a044b3a2e9f02ceadf90dad5246681bde6caaa633b85a5e8b2352"
"hash": "d5f1e272af4a428daedafa3453124b1973a48d47c1c563b2213055bfcf688230"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n COUNT(*) FILTER (WHERE NOT operator AND NOT disabled AND NOT is_service_account) AS \"developers!\",\n COUNT(*) FILTER (WHERE operator AND NOT disabled AND NOT is_service_account) AS \"operators!\"\n FROM usr WHERE workspace_id = $1",
"query": "SELECT\n COUNT(*) FILTER (WHERE NOT operator AND NOT disabled AND NOT is_service_account) AS \"developers!\",\n COUNT(*) FILTER (WHERE operator AND NOT disabled AND NOT is_service_account) AS \"operators!\",\n COUNT(*) FILTER (WHERE is_service_account AND NOT disabled) AS \"service_accounts!\"\n FROM usr WHERE workspace_id = $1",
"describe": {
"columns": [
{
@@ -12,6 +12,11 @@
"ordinal": 1,
"name": "operators!",
"type_info": "Int8"
},
{
"ordinal": 2,
"name": "service_accounts!",
"type_info": "Int8"
}
],
"parameters": {
@@ -20,9 +25,10 @@
]
},
"nullable": [
null,
null,
null
]
},
"hash": "ebce1633afe3d3f8a1a68bc8d26adcdd88b137bb892437a3ca67fd716772512b"
"hash": "d61e8523269a26051079b0ee837bf33c1ce2e063aaf80fd155dbbbf99eb2fab3"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT q.id FROM v2_job_queue q\n JOIN native_retry_attempt n ON n.job_id = q.id\n JOIN v2_job r ON r.id = q.id\n JOIN v2_job a ON a.id = r.parent_job\n WHERE q.workspace_id = $2 AND a.parent_job = ANY($1)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"UuidArray",
"Text"
]
},
"nullable": [
false
]
},
"hash": "de1adae1306fb9d877ec6f2d52235b3f57d4fa4c27861b51da6bfe8c74abd429"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow (\n workspace_id, path, summary, description, value, edited_by, edited_at,\n archived, schema, extra_perms, dependency_job, tag,\n ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only,\n concurrency_key, versions, on_behalf_of, on_behalf_of_email, lock_error_logs,\n job_token_scopes\n )\n SELECT $2, path, summary, description, value, edited_by, edited_at,\n archived, schema, extra_perms, NULL, tag,\n ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only,\n concurrency_key, ARRAY[]::bigint[],\n -- Same predicate as clone_scripts.\n CASE WHEN on_behalf_of LIKE 'u/%' THEN\n (SELECT on_behalf_of WHERE EXISTS (\n SELECT 1 FROM usr u WHERE u.workspace_id = $2::varchar\n AND u.username = substring(on_behalf_of from 3)\n UNION ALL\n SELECT 1 FROM password p WHERE p.super_admin\n AND (p.username = substring(on_behalf_of from 3)\n OR p.email = substring(on_behalf_of from 3))))\n WHEN on_behalf_of LIKE 'g/%' THEN\n (SELECT on_behalf_of WHERE EXISTS (\n SELECT 1 FROM group_ g WHERE g.workspace_id = $2::varchar\n AND g.name = substring(on_behalf_of from 3)))\n ELSE\n (SELECT on_behalf_of WHERE EXISTS (\n SELECT 1 FROM usr u WHERE u.workspace_id = $2::varchar\n AND u.username = on_behalf_of\n UNION ALL\n SELECT 1 FROM password p WHERE p.email = on_behalf_of\n AND p.super_admin))\n END, on_behalf_of_email, lock_error_logs, job_token_scopes\n FROM flow\n WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Varchar"
]
},
"nullable": []
},
"hash": "df1fe2e7ef004b8de0e626f40fd737b3b4b662a89148cf6ac70eb3563ad7f0c5"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "WITH prev AS (SELECT started_at FROM v2_job_queue WHERE id = $1)\n UPDATE v2_job_queue q SET running = false, started_at = null\n FROM prev WHERE q.id = $1\n RETURNING (extract(epoch FROM now() - prev.started_at) * 1000)::bigint",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "int8",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "e12f852fa196d16862151ab490b05e6f5c25e23b7c41ce1c0e5a83bf7b118bfd"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE worker_ping SET draining = true WHERE worker = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "e4b9c0e8a46dbfe29bace8d8b12123a98ec175f9d3dc72e40a1cb40e14dec919"
}
@@ -0,0 +1,34 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO worker_ping (worker_instance, worker, ip, custom_tags, worker_group, dedicated_worker, dedicated_workers, wm_version, vcpus, memory, job_isolation, native_mode, draining) VALUES ($1, $2, COALESCE($3, 'NO IP'), $4, $5, $6, $7, $8, $9, $10, $11, $12, COALESCE($13, false)) ON CONFLICT (worker)\n DO UPDATE set ping_at = now(), worker_instance = EXCLUDED.worker_instance, ip = COALESCE($3, worker_ping.ip), custom_tags = EXCLUDED.custom_tags, worker_group = EXCLUDED.worker_group, dedicated_worker = EXCLUDED.dedicated_worker, dedicated_workers = EXCLUDED.dedicated_workers, wm_version = EXCLUDED.wm_version, vcpus = COALESCE(EXCLUDED.vcpus, worker_ping.vcpus), memory = COALESCE(EXCLUDED.memory, worker_ping.memory), job_isolation = EXCLUDED.job_isolation, native_mode = EXCLUDED.native_mode, current_job_id = NULL, current_job_workspace_id = NULL, draining = COALESCE($13, worker_ping.draining)\n RETURNING jobs_executed",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "jobs_executed",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Text",
"TextArray",
"Varchar",
"Varchar",
"TextArray",
"Varchar",
"Int8",
"Int8",
"Text",
"Bool",
"Bool"
]
},
"nullable": [
false
]
},
"hash": "e7a8c0ee68b8626eb45a7eacdd364360a5d5c783d6ca0a3c4123ea126ed0e60b"
}

Some files were not shown because too many files have changed in this diff Show More