Merge remote-tracking branch 'origin/main' into migrate-session-to-fork

# Conflicts:
#	backend/ee-repo-ref.txt
#	frontend/src/lib/components/sessions/SessionWrapper.svelte
#	frontend/src/lib/components/sessions/WorkspaceFamilyPicker.svelte
This commit is contained in:
Guilhem Lemouel
2026-10-23 05:27:00 -07:00
1190 changed files with 71933 additions and 14475 deletions
+34 -15
View File
@@ -84,7 +84,7 @@ pub trait External: Send + Sync + 'static {
async fn prepare_webhook(&self, db, w_id, headers, body, script_path, is_flow) -> Result<PushArgsOwned>;
fn service_config_from_create_response(&self, data, resp) -> Option<serde_json::Value>;
fn additional_routes(&self) -> axum::Router;
async fn http_client_request<T, B>(&self, url, method, workspace_id, tx, db, headers, body) -> Result<T>;
async fn http_client_request<T, B>(&self, url, method, workspace_id, connection_path, db, headers, body) -> Result<T>;
}
```
@@ -115,28 +115,47 @@ Use this when the external_id is known before the create call (e.g., Google gene
Use this when the external_id is assigned by the remote service and the webhook URL needs to be corrected after creation.
### OAuth Token Storage (Three-Table Pattern)
### OAuth App and Connections
OAuth tokens are stored across three tables, NOT in `workspace_integrations.oauth_data` directly:
The OAuth **app** (client) is configured per workspace and service; **connections** (connected
accounts) are many per service. Each trigger acts through one connection, named by
`native_trigger.connection_path`:
| Table | What's Stored |
|-------|---------------|
| `workspace_integrations` | `oauth_data` JSON with `base_url`, `client_id`, `client_secret`, `instance_shared` flag; `resource_path` pointing to the variable |
| `variable` | Encrypted `access_token` (at the path stored in `resource_path`), linked to `account` via `account` column |
| `account` | `refresh_token`, keyed by `workspace_id` + `client` (service name) + `is_workspace_integration = true` |
| `workspace_integrations` | `oauth_data` JSON with `base_url`, `client_id`, `client_secret`, `instance_shared` flag. One row per (workspace, service); it must exist for every connection, since token refresh reads the client from it |
| `variable` | Encrypted `access_token` at the connection path, linked to `account` via its `account` column |
| `account` | `refresh_token`, with `client` = service name and `is_workspace_integration = true` |
| `resource` | The connection's resource at the same path, `{ "token": "$var:<path>" }` |
The `decrypt_oauth_data()` function in `lib.rs` assembles these into a unified struct:
A user may use a connection when they can read its variable (checked with a user transaction,
so the variable's row-level security decides): `resolve_usable_connection` /
`list_usable_connections` in `lib.rs`. The exception is the **workspace connection**: an admin
may share one connection per service (`workspace_integrations.resource_path`, set by
`POST .../workspace_connection`), and every member may then use it without reading its token.
Renames carry the marker along; disconnecting clears it. Background work (sync, renewal, rename re-registration,
webhook handling) uses the stored `connection_path` directly.
`decrypt_oauth_data(db, w_id, service, connection_path)` assembles these into one struct, and
every service's `OAuthData` carries `connection_path` so `http_client_request` can refresh and
write back the right connection:
```rust
pub struct OAuthConfig {
pub base_url: String,
pub access_token: String, // decrypted from variable
pub refresh_token: Option<String>, // from account table
pub access_token: String, // decrypted from the connection's variable
pub refresh_token: Option<String>, // from its account
pub client_id: String, // from oauth_data or instance settings
pub client_secret: String, // from oauth_data or instance settings
pub connection_path: String,
}
```
Instance-level sharing: when `oauth_data.instance_shared == true`, `client_id` and `client_secret` are read from global settings instead of workspace_integrations.
A refreshed token is written back by connection path and account id, never by service: providers
like Nextcloud rotate refresh tokens, so writing one onto another account breaks its next refresh.
Instance-level sharing: when the workspace has no OAuth app of its own and the instance admin
shares one (`share_with_workspaces` in the `oauths` setting; not available for Nextcloud), the
connect flow uses it and records `{"instance_shared": true}` in `workspace_integrations`.
### URL Resolution
@@ -311,7 +330,7 @@ impl External for NewService {
});
let response: CreateTriggerResponse = self
.http_client_request(&url, Method::POST, w_id, tx, db, None, Some(&payload))
.http_client_request(&url, Method::POST, w_id, &oauth_data.connection_path, db, None, Some(&payload))
.await?;
Ok(response)
@@ -343,7 +362,7 @@ impl External for NewService {
});
let _: serde_json::Value = self
.http_client_request(&url, Method::PUT, w_id, tx, db, None, Some(&payload))
.http_client_request(&url, Method::PUT, w_id, &oauth_data.connection_path, db, None, Some(&payload))
.await?;
// Fetch back the updated state to get the resolved config
@@ -361,7 +380,7 @@ impl External for NewService {
tx: &mut PgConnection,
) -> Result<Self::TriggerData> {
let url = format!("{}/api/webhooks/{}", oauth_data.base_url, external_id);
self.http_client_request::<_, ()>(&url, Method::GET, w_id, tx, db, None, None).await
self.http_client_request::<_, ()>(&url, Method::GET, w_id, &oauth_data.connection_path, db, None, None).await
}
async fn delete(
@@ -374,7 +393,7 @@ impl External for NewService {
) -> Result<()> {
let url = format!("{}/api/webhooks/{}", oauth_data.base_url, external_id);
let _: serde_json::Value = self
.http_client_request::<_, ()>(&url, Method::DELETE, w_id, tx, db, None, None)
.http_client_request::<_, ()>(&url, Method::DELETE, w_id, &oauth_data.connection_path, db, None, None)
.await
.or_else(|e| match &e {
Error::InternalErr(msg) if msg.contains("404") => Ok(serde_json::Value::Null),
@@ -749,7 +768,7 @@ pub async fn prepare_native_trigger_args(service_name, db, w_id, headers, body)
When `workspace_integrations.oauth_data.instance_shared == true`, `decrypt_oauth_data()` reads `client_id` and `client_secret` from instance-level global settings instead of workspace-level. This allows admins to share OAuth app credentials across workspaces.
The frontend handles this via the `generate_instance_connect_url` endpoint in `workspace_integrations.rs`.
`generate_connect_url` picks the client (`resolve_oauth_client`): the workspace's own app when configured, the instance's otherwise. A GitHub OAuth app only redirects below its single registered callback, so connections made with the instance GitHub app land on `/oauth/callback/github/native_trigger` instead of the workspace settings page.
---
+2 -2
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.13.0/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.4/uv-installer.sh | sh && mv /usr/local/cargo/bin/uv /usr/local/bin/uv
ENV TZ=Etc/UTC
@@ -42,7 +42,7 @@ RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VER
RUN /usr/local/bin/python3 -m pip install pip-tools
# Bun
COPY --from=oven/bun:1.4.0 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.4.4 /usr/local/bin/bun /usr/bin/bun
# Install windmill CLI
RUN bun install -g windmill-cli \
+9 -1
View File
@@ -46,7 +46,15 @@ runs:
env:
IMAGE: ${{ inputs.image }}
DIGEST: ${{ inputs.digest }}
run: cosign sign --yes --recursive "${IMAGE}@${DIGEST}"
# Fulcio and Rekor return transient 5xx often enough to fail a release;
# re-signing the same digest only adds a signature, so retrying is safe.
run: |
for attempt in 1 2 3 4 5; do
cosign sign --yes --recursive "${IMAGE}@${DIGEST}" && exit 0
echo "::warning::cosign sign failed (attempt $attempt/5)"
[ "$attempt" -lt 5 ] && sleep $((attempt * 30))
done
exit 1
- name: SLSA provenance (GitHub artifact attestation)
uses: actions/attest-build-provenance@v4
+1 -1
View File
@@ -61,7 +61,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.0
bun-version: 1.4.4
- uses: actions/setup-node@v7
with:
+2 -2
View File
@@ -46,7 +46,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.0
bun-version: 1.4.4
- id: matrix
env:
@@ -93,7 +93,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.0
bun-version: 1.4.4
- uses: actions/setup-node@v7
with:
+1 -1
View File
@@ -75,7 +75,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.0
bun-version: 1.4.4
- uses: actions/setup-node@v7
with:
+4 -4
View File
@@ -73,7 +73,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.0
bun-version: 1.4.4
- uses: actions/setup-node@v7
with:
@@ -81,7 +81,7 @@ jobs:
- uses: astral-sh/setup-uv@v7
with:
version: "0.13.0"
version: "0.13.4"
- uses: shivammathur/setup-php@v2
with:
@@ -139,8 +139,8 @@ jobs:
run: |
cargo build --release -p windmill_duckdb_ffi_internal
New-Item -ItemType Directory -Path ..\target\debug -Force
Copy-Item target\release\windmill_duckdb_ffi_internal.dll ..\target\debug\
# duckdb is bundled (~2GB of build artifacts); the DLL is the only
Copy-Item target\release\windmill_duckdb_runner.exe ..\target\debug\
# duckdb is bundled (~2GB of build artifacts); the runner is the only
# thing we need from this excluded-crate target dir.
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue target
Get-PSDrive C | Select-Object Used,Free | Format-Table -AutoSize
+11 -4
View File
@@ -58,13 +58,13 @@ jobs:
go-version: 1.21.5
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.0
bun-version: 1.4.4
- uses: actions/setup-node@v7
with:
node-version: "24"
- uses: astral-sh/setup-uv@v7
with:
version: "0.13.0"
version: "0.13.4"
- uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
@@ -83,9 +83,16 @@ jobs:
chmod +x "$HOME/.local/bin/wmill"
echo "$HOME/.local/bin" >> $GITHUB_PATH
working-directory: /
- name: Install PowerShell, mold and clang
- name: Install PowerShell, mold, clang and the latest pg_dump
# PGDG's `postgresql-client` is its newest major, Ubuntu's is not: the `postgres` service
# image floats, and pg_dump refuses a server newer than itself. `/usr/bin/pg_dump` picks
# the version of the runner's own preinstalled cluster, so the newest bin dir goes first.
run: |
sudo apt-get update && sudo apt-get install -y powershell mold clang libcurl4-openssl-dev
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y
sudo apt-get update && sudo apt-get install -y powershell mold clang libcurl4-openssl-dev postgresql-client
PG_BIN="/usr/lib/postgresql/$(ls /usr/lib/postgresql | sort -n | tail -1)/bin"
echo "$PG_BIN" >> "$GITHUB_PATH"
"$PG_BIN/pg_dump" --version
working-directory: /
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
+6 -6
View File
@@ -83,17 +83,17 @@ jobs:
# Extract arm64 binary (include deps/ for hard link resolution)
mkdir -p /tmp/arm64
crane export --platform linux/arm64 ${{ steps.meta-ee-public.outputs.tags }} - \
| tar -xf - -C /tmp/arm64 windmill/target/release/ usr/src/app/libwindmill_duckdb_ffi_internal.so
| tar -xf - -C /tmp/arm64 windmill/target/release/ usr/src/app/windmill_duckdb_runner
cp /tmp/arm64/windmill/target/release/windmill extracted/windmill-ee-arm64-rhel9
cp /tmp/arm64/usr/src/app/libwindmill_duckdb_ffi_internal.so extracted/libwindmill_duckdb_ffi_internal-arm64.so
cp /tmp/arm64/usr/src/app/windmill_duckdb_runner extracted/windmill_duckdb_runner-arm64
rm -rf /tmp/arm64
# Extract amd64 binary
mkdir -p /tmp/amd64
crane export --platform linux/amd64 ${{ steps.meta-ee-public.outputs.tags }} - \
| tar -xf - -C /tmp/amd64 windmill/target/release/ usr/src/app/libwindmill_duckdb_ffi_internal.so
| tar -xf - -C /tmp/amd64 windmill/target/release/ usr/src/app/windmill_duckdb_runner
cp /tmp/amd64/windmill/target/release/windmill extracted/windmill-ee-amd64-rhel9
cp /tmp/amd64/usr/src/app/libwindmill_duckdb_ffi_internal.so extracted/libwindmill_duckdb_ffi_internal-amd64.so
cp /tmp/amd64/usr/src/app/windmill_duckdb_runner extracted/windmill_duckdb_runner-amd64
rm -rf /tmp/amd64
- uses: actions/upload-artifact@v4
@@ -109,9 +109,9 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: RHEL9-arm64 dynamic libraries build
path: extracted/libwindmill_duckdb_ffi_internal-arm64.so
path: extracted/windmill_duckdb_runner-arm64
- uses: actions/upload-artifact@v4
with:
name: RHEL9-amd64 dynamic libraries build
path: extracted/libwindmill_duckdb_ffi_internal-amd64.so
path: extracted/windmill_duckdb_runner-amd64
@@ -103,7 +103,7 @@ jobs:
id: extract-duckdb-ffi-internal
with:
image: ${{ steps.meta-ee-public.outputs.tags}}-amd64
path: "/usr/src/app/libwindmill_duckdb_ffi_internal.so"
path: "/usr/src/app/windmill_duckdb_runner"
# - uses: shrink/actions-docker-extract@v3
# id: extract-ee-arm64
@@ -124,7 +124,7 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: RHEL8-amd64 dynamic libraries build
path: ${{ steps.extract-duckdb-ffi-internal.outputs.destination }}/libwindmill_duckdb_ffi_internal.so
path: ${{ steps.extract-duckdb-ffi-internal.outputs.destination }}/windmill_duckdb_runner
# - uses: actions/upload-artifact@v4
# with:
+2 -2
View File
@@ -81,5 +81,5 @@ jobs:
- name: Upload dynamic libraries artifact
uses: actions/upload-artifact@v4
with:
name: windmill_duckdb_ffi_internal.dll
path: ./backend/windmill-duckdb-ffi-internal/target/release/windmill_duckdb_ffi_internal.dll
name: windmill_duckdb_runner.exe
path: ./backend/windmill-duckdb-ffi-internal/target/release/windmill_duckdb_runner.exe
+44 -43
View File
@@ -197,49 +197,43 @@ jobs:
ARCH: amd64
steps:
- uses: actions/checkout@v4
- run: |
# pulling docker image with desired arch so that actions-docker-extract doesn't do it
docker pull --platform "linux/$ARCH" ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}
docker pull --platform "linux/$ARCH" ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee@${{ needs.build_ee.outputs.digest }}
- run: |
# Checks the image is in docker prior to running actions-docker-extract. It fails if not
# Also useful to visually check that the arch is the right opencontainers
docker image inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}
docker image inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee@${{ needs.build_ee.outputs.digest }}
- uses: shrink/actions-docker-extract@v3
id: extract
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}
path: "/usr/src/app/windmill"
- uses: shrink/actions-docker-extract@v3
id: extract-duckdb-ffi-internal
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}
path: "/usr/src/app/libwindmill_duckdb_ffi_internal.so"
- uses: shrink/actions-docker-extract@v3
id: extract-ee
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee@${{ needs.build_ee.outputs.digest }}
path: "/usr/src/app/windmill"
- name: Rename binary with corresponding architecture
# The runner disk cannot hold the CE and EE images at once, so each image
# is pulled, extracted from and removed before the next one is pulled.
- name: Extract binaries
env:
CE_IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}
EE_IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee@${{ needs.build_ee.outputs.digest }}
run: |
mv "${{ steps.extract.outputs.destination }}/windmill" "${{ steps.extract.outputs.destination }}/windmill-${ARCH}"
mv "${{ steps.extract-ee.outputs.destination }}/windmill" "${{ steps.extract-ee.outputs.destination }}/windmill-ee-${ARCH}"
set -euo pipefail
mkdir -p release
# extract <image> (<path in image> <release file name>)...
extract() {
local image=$1 cid
shift
docker pull --platform "linux/$ARCH" "$image"
docker image inspect --format '{{.Os}}/{{.Architecture}}' "$image"
cid=$(docker create --platform "linux/$ARCH" "$image")
while [ $# -gt 0 ]; do
docker cp "$cid:$1" "release/$2"
shift 2
done
docker rm "$cid"
docker rmi "$image"
df -h /
}
extract "$CE_IMAGE" \
/usr/src/app/windmill "windmill-$ARCH" \
/usr/src/app/windmill_duckdb_runner windmill_duckdb_runner
extract "$EE_IMAGE" /usr/src/app/windmill "windmill-ee-$ARCH"
ls -la release
- name: Attach binary to release
uses: softprops/action-gh-release@v2
with:
files: |
${{ steps.extract.outputs.destination }}/*
${{ steps.extract-ee.outputs.destination }}/*
${{ steps.extract-duckdb-ffi-internal.outputs.destination }}/*
files: release/*
attach_ee_debug_to_release:
upload_ee_debug_to_s3:
needs: [build_ee]
runs-on: ubicloud
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
@@ -284,14 +278,21 @@ jobs:
WM_BUILD_VERSION=${{ github.sha }}
outputs: type=local,dest=./debuginfo
- name: Rename debug file with corresponding architecture
# The debug file names every EE function with its source file and line, so it
# goes to a private bucket, never to the public release.
- name: Upload debug file to private bucket
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: us-east-1
TAG: ${{ github.ref_name }}
ARCH: ${{ matrix.arch }}
run: |
mv ./debuginfo/windmill.debug ./debuginfo/windmill-ee-${{ matrix.arch }}.debug
- name: Attach debug file to release
uses: softprops/action-gh-release@v2
with:
files: ./debuginfo/windmill-ee-${{ matrix.arch }}.debug
aws --version
aws configure set default.s3.multipart_chunksize 64MB
aws s3 cp ./debuginfo/windmill.debug \
"s3://windmill-ee-debuginfo/$TAG/windmill-ee-$ARCH.debug" \
--storage-class GLACIER_IR --only-show-errors
# attach_arm64_binary_to_release:
# needs: [build, build_ee]
+1 -1
View File
@@ -135,7 +135,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.0
bun-version: 1.4.4
- uses: denoland/setup-deno@v2
with:
+2 -2
View File
@@ -72,8 +72,8 @@ jobs:
files: |
./backend/target/release/windmill-ee.exe
- name: Attach dynamic libraries to release
- name: Attach the DuckDB runner to release
uses: softprops/action-gh-release@v2
with:
files: |
./backend/windmill-duckdb-ffi-internal/target/release/windmill_duckdb_ffi_internal.dll
./backend/windmill-duckdb-ffi-internal/target/release/windmill_duckdb_runner.exe
+1 -1
View File
@@ -1,3 +1,3 @@
{
".": "1.833.0"
".": "1.847.0"
}
+7
View File
@@ -33,11 +33,17 @@ 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
- **Fork object storage**: `docs/fork-object-storage.md` — how a fork's object keys map under
`__wm_forks/<segment>/` with read-through to its ancestors, where the mapping must be applied,
and why `__wm_forks/` is reachable only through a workspace's own chain
- **Data table viewer roles**: `docs/datatable-viewer-roles.md`, on what a connection naming no
role holds: the default role as a floor, whose roles are added (the job's own, or its viewer's
for an inline app runnable that opts in), why an admin's roles are not added, 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
- **Workspace roles**: `docs/workspace-roles.md` — instance-defined roles with per-workspace
overrides, the capabilities a role holds, why `ApiAuthed::is_operator` must be derived from the
role, and the `role_seat` table billing reads
- **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
@@ -60,6 +66,7 @@ Open-source platform for internal tools, workflows, API integrations, background
- **Domain vocabulary**: `CONTEXT.md` — the words this codebase uses for its own concepts (step, step setting, trigger step, …). Name things the way it does.
- **CLI commands**: when adding/modifying/removing a command, subcommand, option, or description in `cli/src/commands/`, run `python system_prompts/generate.py` to refresh `system_prompts/auto-generated/` and `cli/src/guidance/skills.gen.ts`. The CLI docs the agents use to operate `wmill` are derived from the source — stale generated files give agents the wrong flags.
- **AI guidance** (chat prompts and CLI skills): what the AI knows about Windmill itself — how flows, scripts, apps, pipelines and resources work — is written once, in `system_prompts/base/` and `system_prompts/languages/`, and `system_prompts/generate.py` builds both the chat's `$system_prompts` exports and the CLI's skills from it. Add or change such guidance there, never inline in one consumer: a sentence only one side should see goes in a `<!-- cli-only -->` / `<!-- chat-only -->` block, and a new file reaches both through the `TOPICS` table. The chat prompt builders under `frontend/src/lib/components/copilot/chat/` add only tool plumbing and runtime values, and shared markdown names no chat tool, since it reaches every chat mode. Rerun `generate.py` after editing; `system_prompts/README.md` has the details.
- **Windmill MCP server**: `/api/mcp` gives a token with `mcp:all` the AI session's GLOBAL toolset (`backend/windmill-api/src/mcp/session/`), and a token scoped to a selection of scripts and flows the tools server's per-runnable tools, without endpoint tools. The tools server's own URLs, `/api/mcp/w/{workspace}/mcp` and `/api/mcp/gateway`, keep serving existing tokens, endpoint scopes included. Every tool takes a `workspace_id`; the token bounds which (its bound workspace, the `mcp:workspaces:` list, or all of its owner's). What a model reads there (tool names, descriptions, input schemas, instructions, `get_instructions` texts) is generated from the session's TypeScript into `session/gen/`: after changing a GLOBAL tool definition, the global system prompt or `system_prompts/`, run `npm run gen:mcp-session` from `frontend/` (`mcpSessionGen.test.ts` fails otherwise). What a tool *does* is written twice, in `chat/global/core.ts` and in a Rust handler: a behaviour change on one side must be mirrored on the other, and a new session tool is either implemented in Rust or added to `EDITOR_ONLY` (a `cargo test` in `session/mod.rs` fails otherwise).
- **Session recorder**: `frontend/src/lib/components/recording/` is also the recorder `wmill app dev --recording` serves, vendored into the CLI as `cli/src/commands/app/devRecorderBundle.gen.ts`. After changing `rawAppSnapshot.ts` or `rawAppRecording.svelte.ts`, run `bun run gen:dev-recorder` from `cli/` (`cli/test/dev_recorder_bundle_unit.test.ts` fails otherwise).
- **Raw-app policy**: `frontend/src/lib/components/raw_apps/rawAppPolicy.ts` also derives the policy the server's raw-app deploy stores, vendored into the bundle job as `backend/windmill-api/src/apps_raw_policy.gen.js`. After changing it or anything it imports, run `bun run gen:app-policy` from `cli/` (`cli/test/app_policy_bundle_unit.test.ts` fails otherwise). It rides in the job rather than being read from the CLI the job runs because the images install `windmill-cli` unpinned, so an image can carry one older than its server.
+256
View File
@@ -1,5 +1,261 @@
# Changelog
## [1.847.0](https://github.com/windmill-labs/windmill/compare/v1.846.1...v1.847.0) (2026-10-22)
### Features
* add job_id and flow_path to flow step error objects ([#11941](https://github.com/windmill-labs/windmill/issues/11941)) ([eeb48f0](https://github.com/windmill-labs/windmill/commit/eeb48f0c26ccc5162430eddec24adc2601eb5f99))
* chat with a saved agent from a raw app through an agent runnable ([#11921](https://github.com/windmill-labs/windmill/issues/11921)) ([c6a93a9](https://github.com/windmill-labs/windmill/commit/c6a93a9b565752da6c8b55d383e5bee88f00f229))
* let native triggers act through per-user or shared connections ([#11352](https://github.com/windmill-labs/windmill/issues/11352)) ([dc1fb50](https://github.com/windmill-labs/windmill/commit/dc1fb5087be7169045aad57e955dabe3e29de82e))
* slack agents through a workspace's own slack app ([#11912](https://github.com/windmill-labs/windmill/issues/11912)) ([34de8bc](https://github.com/windmill-labs/windmill/commit/34de8bc06d2b04f7929bb8cf35f9a34d0e0071fa))
* worker group toggle to keep the worker's proxy out of jobs ([#11958](https://github.com/windmill-labs/windmill/issues/11958)) ([8a0318a](https://github.com/windmill-labs/windmill/commit/8a0318a28f5cfda7557b0f94db20ef17b0664ee4))
### Bug Fixes
* compare a null resource description as empty ([#11947](https://github.com/windmill-labs/windmill/issues/11947)) ([8a7b148](https://github.com/windmill-labs/windmill/commit/8a7b1481bd270df3a98c9db5e7824d13b8cd37b6))
* compare fork secret variables by decrypted value ([#11952](https://github.com/windmill-labs/windmill/issues/11952)) ([0dd131b](https://github.com/windmill-labs/windmill/commit/0dd131b38074423de5c769cae478c6ea0ae365c2))
* hold home's ai composer space with a matching placeholder ([#11936](https://github.com/windmill-labs/windmill/issues/11936)) ([9202a74](https://github.com/windmill-labs/windmill/commit/9202a74071ba424ad6cfc1cfded518ee7db002dc))
* link a variable to its OAuth account only in the connect flow ([#11361](https://github.com/windmill-labs/windmill/issues/11361)) ([d6adac8](https://github.com/windmill-labs/windmill/commit/d6adac8b7579ad6c3df5caab9a735451c1ddd896))
* stop audit inserts from silently rolling back saves ([#11938](https://github.com/windmill-labs/windmill/issues/11938)) ([5ef19a8](https://github.com/windmill-labs/windmill/commit/5ef19a88a90b3a4fe05a78547416082dc51763f5))
## [1.846.1](https://github.com/windmill-labs/windmill/compare/v1.846.0...v1.846.1) (2026-10-21)
### Bug Fixes
* home recent cards include items opened on their own page ([#11934](https://github.com/windmill-labs/windmill/issues/11934)) ([5019fab](https://github.com/windmill-labs/windmill/commit/5019fab5a5f996796a07524c770f86309a7a3500))
* home search suggests filters whose name matches the typed text ([#11933](https://github.com/windmill-labs/windmill/issues/11933)) ([bf1eb85](https://github.com/windmill-labs/windmill/commit/bf1eb85577419cc08482158c1835d5262ebb87d2))
## [1.846.0](https://github.com/windmill-labs/windmill/compare/v1.845.0...v1.846.0) (2026-10-21)
### Features
* home list settings menu with sort, library and user-folder toggles ([#11928](https://github.com/windmill-labs/windmill/issues/11928)) ([73f655d](https://github.com/windmill-labs/windmill/commit/73f655db98dd0f0fd03881c36e6c9310fb2687a2))
### Bug Fixes
* home's acting-on pick switches the current workspace ([#11929](https://github.com/windmill-labs/windmill/issues/11929)) ([cdaddcc](https://github.com/windmill-labs/windmill/commit/cdaddcce594378bf502f80e8f225f16b5def5eb4))
## [1.845.0](https://github.com/windmill-labs/windmill/compare/v1.844.0...v1.845.0) (2026-10-21)
### Features
* home and empty ai sessions share one session composer ([#11635](https://github.com/windmill-labs/windmill/issues/11635)) ([56b2e10](https://github.com/windmill-labs/windmill/commit/56b2e106daedb5ae381052d3116346a88ba3f206))
## [1.844.0](https://github.com/windmill-labs/windmill/compare/v1.843.0...v1.844.0) (2026-10-21)
### Features
* serve the ai session toolset over mcp at /api/mcp ([#11738](https://github.com/windmill-labs/windmill/issues/11738)) ([892334f](https://github.com/windmill-labs/windmill/commit/892334f008d5b6b73de38fdf2831b1a63eeb0a51))
## [1.843.0](https://github.com/windmill-labs/windmill/compare/v1.842.0...v1.843.0) (2026-10-21)
### Features
* configurable workspace roles with per-workspace overrides ([#11821](https://github.com/windmill-labs/windmill/issues/11821)) ([21d2a49](https://github.com/windmill-labs/windmill/commit/21d2a49971b858ff8aef2776a36989b57ba49415))
* move the open in AI session button to the page header ([#11888](https://github.com/windmill-labs/windmill/issues/11888)) ([34db239](https://github.com/windmill-labs/windmill/commit/34db23952a765bbb9c912d74d2a37092703f50f7))
* ship php only on the full images ([#11922](https://github.com/windmill-labs/windmill/issues/11922)) ([b874861](https://github.com/windmill-labs/windmill/commit/b87486141df5b4f9b93900c0ee3264cf4b4610ec))
* workspace roles settings UI and capability-based gating ([#11824](https://github.com/windmill-labs/windmill/issues/11824)) ([8dbdfa1](https://github.com/windmill-labs/windmill/commit/8dbdfa194912bf36a705392899b9f84b5a54fd55))
### Bug Fixes
* compact the AI chat history between tool iterations ([#11911](https://github.com/windmill-labs/windmill/issues/11911)) ([17de2ba](https://github.com/windmill-labs/windmill/commit/17de2ba983bee5cb7df700476ec8a0169c97ecbd))
* refuse restarting a flow past an approval that was never granted ([#11920](https://github.com/windmill-labs/windmill/issues/11920)) ([2c6bcc0](https://github.com/windmill-labs/windmill/commit/2c6bcc09c9b6f768592b31ec540d727263a807cc))
* remove horizontal scroll in the new workspace form ([#11909](https://github.com/windmill-labs/windmill/issues/11909)) ([d35c868](https://github.com/windmill-labs/windmill/commit/d35c86896fa4f5f9936a9f61735553e2ff42b218))
* revoke mcp oauth grants on password change and reset ([#11908](https://github.com/windmill-labs/windmill/issues/11908)) ([c044777](https://github.com/windmill-labs/windmill/commit/c04477723c9d7544ea9c595e33fdcff5cce0c79d))
* **worker:** render TEMP_SCRIPT_REFS placeholder in Python runner-group loader.py ([#11915](https://github.com/windmill-labs/windmill/issues/11915)) ([78fb800](https://github.com/windmill-labs/windmill/commit/78fb800904351f6b549b8b2227cb9c0d5dafd55d))
## [1.842.0](https://github.com/windmill-labs/windmill/compare/v1.841.0...v1.842.0) (2026-10-20)
### Features
* let AI agents answer in Slack ([#11630](https://github.com/windmill-labs/windmill/issues/11630)) ([35b250e](https://github.com/windmill-labs/windmill/commit/35b250e76739a1e6f543971b099d5796a44d0c89))
* name the action on chat tool confirmation buttons ([#11795](https://github.com/windmill-labs/windmill/issues/11795)) ([7d01d25](https://github.com/windmill-labs/windmill/commit/7d01d252b526987f8f0b86695de2f9c90de64519))
### Bug Fixes
* align collapsed conversations sidebar chat icon with the buttons above ([#11873](https://github.com/windmill-labs/windmill/issues/11873)) ([24238d4](https://github.com/windmill-labs/windmill/commit/24238d4062801558f90728b17e3d70e980c733dd))
* align sidebar home with the header when ai sessions is off ([#11882](https://github.com/windmill-labs/windmill/issues/11882)) ([1874808](https://github.com/windmill-labs/windmill/commit/18748084705dc48994b7378217e0df1e8bfbfe3f))
* give the agent page's API and Slack sections tabs on small screens ([#11901](https://github.com/windmill-labs/windmill/issues/11901)) ([394d345](https://github.com/windmill-labs/windmill/commit/394d345e0c8d9d7da87371e8da090d3becc77ce7))
* keep schedule push, flow advance, wac approval and scim on one pool connection ([#11904](https://github.com/windmill-labs/windmill/issues/11904)) ([8afe060](https://github.com/windmill-labs/windmill/commit/8afe0607abd6bb689a0644916fcdc39fb7df2fe3))
* keep the flow chat mounted when leaving the chat tab ([#11872](https://github.com/windmill-labs/windmill/issues/11872)) ([ed58996](https://github.com/windmill-labs/windmill/commit/ed589963f4d7b7d50a69cacdede443f2bb7efd18))
* let devops users reach instance pages without a workspace ([#11876](https://github.com/windmill-labs/windmill/issues/11876)) ([a3a4fa5](https://github.com/windmill-labs/windmill/commit/a3a4fa503804eb9f031699b60e00a196d223cbe6))
* **mcp:** escape JSON inlined in the MCP OAuth callback page ([#11880](https://github.com/windmill-labs/windmill/issues/11880)) ([5d0a8a9](https://github.com/windmill-labs/windmill/commit/5d0a8a9c15cd54032f930f8a21a0c2c3b517d60d))
* refresh oauth tokens without holding a pool connection ([#11905](https://github.com/windmill-labs/windmill/issues/11905)) ([8ddb358](https://github.com/windmill-labs/windmill/commit/8ddb358198e834642f259197aa5f6d96bd7740d3))
* spell the schedule pause time the way the picker writes it ([#11875](https://github.com/windmill-labs/windmill/issues/11875)) ([4186fff](https://github.com/windmill-labs/windmill/commit/4186ffff841d5905d308aa6bae8159aba3794c1c))
* stop holding a pool connection while waiting for another ([#11902](https://github.com/windmill-labs/windmill/issues/11902)) ([2c559b4](https://github.com/windmill-labs/windmill/commit/2c559b452f38cc86fe45bcdb98574245fd2cf187))
* write a push's runnable settings before it opens its transaction ([#11897](https://github.com/windmill-labs/windmill/issues/11897)) ([e6c8ef1](https://github.com/windmill-labs/windmill/commit/e6c8ef18a11f079083138a991543f7e273d4e511))
### Performance Improvements
* show the AI sessions composer before the chat code loads ([#11886](https://github.com/windmill-labs/windmill/issues/11886)) ([613adb5](https://github.com/windmill-labs/windmill/commit/613adb5287812cf428a74b10e1ef9362d78751b8))
## [1.841.0](https://github.com/windmill-labs/windmill/compare/v1.840.0...v1.841.0) (2026-10-18)
### Features
* let agent workers authenticate with a workload identity token ([#11858](https://github.com/windmill-labs/windmill/issues/11858)) ([be23abb](https://github.com/windmill-labs/windmill/commit/be23abb3602ed9c45f1c66c98d5f84e7676dccfa))
* let ALLOW_PRIVATE_MCP_SERVER_URLS name the private hosts it allows ([#11869](https://github.com/windmill-labs/windmill/issues/11869)) ([5c205fa](https://github.com/windmill-labs/windmill/commit/5c205fa46915de9e5fde731a117ba8571cfa56f7))
* probe nsjail with a real jail and add a gVisor compat mode ([#11865](https://github.com/windmill-labs/windmill/issues/11865)) ([69d36f7](https://github.com/windmill-labs/windmill/commit/69d36f77daceb25cc903c7ea014ba8d487650b18))
### Bug Fixes
* insert ApiAuthed into request extensions in no-auth mode ([#11868](https://github.com/windmill-labs/windmill/issues/11868)) ([a7561fd](https://github.com/windmill-labs/windmill/commit/a7561fd8bde5c4a766a050507c2d9b9823c08bcc))
* reject out-of-range integer args to narrow SQL types instead of wrapping ([#11864](https://github.com/windmill-labs/windmill/issues/11864)) ([19ec5d3](https://github.com/windmill-labs/windmill/commit/19ec5d3cd8a36600c8896a895d0e566735f729a9))
* warn when an autoscaled worker group has no tags to count ([#11859](https://github.com/windmill-labs/windmill/issues/11859)) ([8b14a78](https://github.com/windmill-labs/windmill/commit/8b14a78822f95fb045d80940dfd9197f79ea88cc))
## [1.840.0](https://github.com/windmill-labs/windmill/compare/v1.839.0...v1.840.0) (2026-10-17)
### Features
* add a no_network annotation for sandboxed jobs ([#11844](https://github.com/windmill-labs/windmill/issues/11844)) ([feb7b1a](https://github.com/windmill-labs/windmill/commit/feb7b1ad906046f4cf6ea53a85506f42b1b66e93))
* warn at worker startup when WHITELIST_ENVS forwards a secret-shaped variable ([#11838](https://github.com/windmill-labs/windmill/issues/11838)) ([16c8be2](https://github.com/windmill-labs/windmill/commit/16c8be2355b919878091769810749c54c2f0a09d))
### Bug Fixes
* keep script and flow deploys off a second pool connection ([#11843](https://github.com/windmill-labs/windmill/issues/11843)) ([2684156](https://github.com/windmill-labs/windmill/commit/268415623b515280b99bd5d9e32876868821dc4f))
* let ALLOW_PRIVATE_AI_BASE_URLS name the private hosts it allows ([#11841](https://github.com/windmill-labs/windmill/issues/11841)) ([b0c97b3](https://github.com/windmill-labs/windmill/commit/b0c97b34caa6343db278a9c5c09228248acf970c))
* mount python script modules into the nsjail sandbox ([#11846](https://github.com/windmill-labs/windmill/issues/11846)) ([7a8cb62](https://github.com/windmill-labs/windmill/commit/7a8cb62fa135bff04522f4bbd93aba194e33b121))
* refuse dot segments in AI proxy paths ([#11837](https://github.com/windmill-labs/windmill/issues/11837)) ([89f36a7](https://github.com/windmill-labs/windmill/commit/89f36a73d16675fd5f0d57daa2baf616ee95cbf5))
* run bun and npm installs under nsjail sandboxing ([#11845](https://github.com/windmill-labs/windmill/issues/11845)) ([6646c86](https://github.com/windmill-labs/windmill/commit/6646c86351f188d9b7e355dfb46e87bfa5c81846))
* scope delete_jobs side-table deletes to the request workspace ([#11836](https://github.com/windmill-labs/windmill/issues/11836)) ([09a5911](https://github.com/windmill-labs/windmill/commit/09a59110d941a8c306a0d89e99d34d509545059f))
* skip the fork lock when a fork creation has no storage to purge ([#11842](https://github.com/windmill-labs/windmill/issues/11842)) ([0b54ebc](https://github.com/windmill-labs/windmill/commit/0b54ebc73d3d9541d2521857adc27766c4342000))
### Performance Improvements
* clone sqlx test databases from a migrated template ([#11848](https://github.com/windmill-labs/windmill/issues/11848)) ([4ed6c1a](https://github.com/windmill-labs/windmill/commit/4ed6c1a6ce1b6d53ea9ee965214da0c3adb3f3bd))
## [1.839.0](https://github.com/windmill-labs/windmill/compare/v1.838.0...v1.839.0) (2026-10-16)
### Features
* add a Require isolated forks protection rule ([#11834](https://github.com/windmill-labs/windmill/issues/11834)) ([ab4e790](https://github.com/windmill-labs/windmill/commit/ab4e790a216b92f789e130955d7cd180b394d1fe))
* isolate fork object storage under a per-fork prefix ([#11829](https://github.com/windmill-labs/windmill/issues/11829)) ([9375805](https://github.com/windmill-labs/windmill/commit/9375805fdf7501347a4dfb37e58f1be7fa2c5658))
* one Entra app for the Teams bot and ms_teams Graph connect ([#11718](https://github.com/windmill-labs/windmill/issues/11718)) ([e7088e7](https://github.com/windmill-labs/windmill/commit/e7088e7f4766cd662890cdf61f2b6a5a0fce06a8))
* route python S3 client settings through the S3 proxy ([#11819](https://github.com/windmill-labs/windmill/issues/11819)) ([de340ee](https://github.com/windmill-labs/windmill/commit/de340eed6f5520414b59166f8dc16938f7ac6c36))
### Bug Fixes
* verify Bot Framework JWT on incoming Teams activities ([#11818](https://github.com/windmill-labs/windmill/issues/11818)) ([0b1935f](https://github.com/windmill-labs/windmill/commit/0b1935f251605926760565fb7693f345f1a56312))
## [1.838.0](https://github.com/windmill-labs/windmill/compare/v1.837.0...v1.838.0) (2026-10-16)
### Features
* accept Ed25519-signed license keys alongside RSA ([#11810](https://github.com/windmill-labs/windmill/issues/11810)) ([33d4049](https://github.com/windmill-labs/windmill/commit/33d4049db029e1dc478b1251c562232f0127fc8a))
* make the frontend installable as a progressive web app ([#11805](https://github.com/windmill-labs/windmill/issues/11805)) ([b86909f](https://github.com/windmill-labs/windmill/commit/b86909fc81b21447414266f47a83a43492204e50))
* name mcp script and flow tools after their last path segment ([#11817](https://github.com/windmill-labs/windmill/issues/11817)) ([d1a13d9](https://github.com/windmill-labs/windmill/commit/d1a13d9054d5994b5ed9c0f8566b86154662caa0))
* route dev workspace and fork jobs to their own worker groups ([#11811](https://github.com/windmill-labs/windmill/issues/11811)) ([6e565b0](https://github.com/windmill-labs/windmill/commit/6e565b0dcb0fb56b69131c262d482c82bb6c527b))
### Bug Fixes
* **ai-chat:** tell the session chat that an agent is an ai_agent resource ([#11798](https://github.com/windmill-labs/windmill/issues/11798)) ([a521548](https://github.com/windmill-labs/windmill/commit/a52154877caa5c3e473ee56c1eaf040b7da2375f))
* emit a single email claim in job OIDC tokens ([#11804](https://github.com/windmill-labs/windmill/issues/11804)) ([2ef0c0d](https://github.com/windmill-labs/windmill/commit/2ef0c0d8e14fcd5ff1c06f6113ffaf2792b9d4c9))
* give inline script runs their own job dir ([#11822](https://github.com/windmill-labs/windmill/issues/11822)) ([6aec448](https://github.com/windmill-labs/windmill/commit/6aec4488ebe8f377b4ea9bb4948649831cba0dbc))
* hold mcp token references to resource reference scopes ([#11803](https://github.com/windmill-labs/windmill/issues/11803)) ([c09038b](https://github.com/windmill-labs/windmill/commit/c09038b10698042209fd6aa26c466fb53d6dc7d0))
* let deployed low-code apps run database studio queries again ([#11816](https://github.com/windmill-labs/windmill/issues/11816)) ([7c63a30](https://github.com/windmill-labs/windmill/commit/7c63a30edd650f49eff85066dcc7916cec1b7010))
* truncate long row titles instead of wrapping ([#11815](https://github.com/windmill-labs/windmill/issues/11815)) ([153a871](https://github.com/windmill-labs/windmill/commit/153a871550e3ae9ad6282aa59b3a4f9897fec6c1))
* use the session workspace's user in three AI session places ([#11808](https://github.com/windmill-labs/windmill/issues/11808)) ([19fc07f](https://github.com/windmill-labs/windmill/commit/19fc07faa95a8a2247e726f9d0a2adc3cfa42bd2))
## [1.837.0](https://github.com/windmill-labs/windmill/compare/v1.836.0...v1.837.0) (2026-10-15)
### Features
* agents run on behalf of their deployer ([#11430](https://github.com/windmill-labs/windmill/issues/11430)) ([0b98054](https://github.com/windmill-labs/windmill/commit/0b980546b104cf46f385133af553dfbe5f533eca))
## [1.836.0](https://github.com/windmill-labs/windmill/compare/v1.835.0...v1.836.0) (2026-10-15)
### Features
* **cli:** sync an app's custom path as a workspace-specific file ([#11786](https://github.com/windmill-labs/windmill/issues/11786)) ([718aad7](https://github.com/windmill-labs/windmill/commit/718aad7396397fe12295a27a947c76221f37ad10))
* let operators save resource and variable drafts ([#11736](https://github.com/windmill-labs/windmill/issues/11736)) ([8c0185d](https://github.com/windmill-labs/windmill/commit/8c0185d55a1a8c6fbc5e41b8b9d77865563f515b))
* let raw app backend runnables import each other ([#11777](https://github.com/windmill-labs/windmill/issues/11777)) ([526da60](https://github.com/windmill-labs/windmill/commit/526da60da92832cc6e9c2942cea1f7729b3a05fd))
* let the session agent read folder and group permissions ([#11796](https://github.com/windmill-labs/windmill/issues/11796)) ([eda43dd](https://github.com/windmill-labs/windmill/commit/eda43ddc41c10b3f7263103016275926a33bf768))
* resolve canceled jobs and re-run them in limited batches ([#11797](https://github.com/windmill-labs/windmill/issues/11797)) ([f827ba0](https://github.com/windmill-labs/windmill/commit/f827ba05667e3ca5bcd3bc89dac7f51b85dd32b3))
* run duckdb jobs out of process under job isolation, drop the engine fork, bump to 1.5.6 ([#11780](https://github.com/windmill-labs/windmill/issues/11780)) ([f9513e8](https://github.com/windmill-labs/windmill/commit/f9513e82eed3721ecbfd87004d1cd385ac740903))
* run previews as the runnable's on_behalf_of identity ([#11778](https://github.com/windmill-labs/windmill/issues/11778)) ([4f71231](https://github.com/windmill-labs/windmill/commit/4f712318c3b52366b03bf7f941ecae4730fbf967))
* sandbox new low-code and raw apps by default ([#11760](https://github.com/windmill-labs/windmill/issues/11760)) ([813c080](https://github.com/windmill-labs/windmill/commit/813c080d4684eecd144ef82706b04339c8f8d35a))
* share AI sessions read-only by link, optionally public ([#11799](https://github.com/windmill-labs/windmill/issues/11799)) ([a9aa2b8](https://github.com/windmill-labs/windmill/commit/a9aa2b8229da0d54ed68eb40e4426e6983ff631e))
### Bug Fixes
* **cli:** include script modules in wmill dev previews ([#11787](https://github.com/windmill-labs/windmill/issues/11787)) ([b563f5c](https://github.com/windmill-labs/windmill/commit/b563f5cb5121c431f525c2e0266994c6d655185b))
* let raw app SDK tokens read the viewer's identity without a toggle ([#11790](https://github.com/windmill-labs/windmill/issues/11790)) ([7da2344](https://github.com/windmill-labs/windmill/commit/7da234481333fcbdc348215589e2d3bfe5394b4a))
* let Teams handlers post with job tokens again ([#11792](https://github.com/windmill-labs/windmill/issues/11792)) ([64e1630](https://github.com/windmill-labs/windmill/commit/64e1630d497af1b50a772aa66ef123f675ea6bb1))
* relock apps in place so imported script changes reach them ([#11789](https://github.com/windmill-labs/windmill/issues/11789)) ([aca7fed](https://github.com/windmill-labs/windmill/commit/aca7fed33ddffa17b0e78d50a39ded032f6d8ba2))
* relock scripts and flow steps whose code changed on deploy ([#11794](https://github.com/windmill-labs/windmill/issues/11794)) ([1f1df12](https://github.com/windmill-labs/windmill/commit/1f1df1254ebc417a8344801b571c4be8e98636c4))
* send Azure Foundry gpt-5.5+ models to the Responses API ([#11788](https://github.com/windmill-labs/windmill/issues/11788)) ([ab89835](https://github.com/windmill-labs/windmill/commit/ab8983543b0641c96a8b4a2cbd829cc4040e9f41))
* show the app's summary in the app viewer's page header ([#11782](https://github.com/windmill-labs/windmill/issues/11782)) ([3bee9c9](https://github.com/windmill-labs/windmill/commit/3bee9c94012474b7bb230d719fa34df0c0a6c25e))
### Performance Improvements
* drive schedule already-exists check from an indexed queue lookup ([#11783](https://github.com/windmill-labs/windmill/issues/11783)) ([7eee210](https://github.com/windmill-labs/windmill/commit/7eee210d761d332f8165b4f8a6f0ee6f1ec8864f))
## [1.835.0](https://github.com/windmill-labs/windmill/compare/v1.834.0...v1.835.0) (2026-10-14)
### Features
* allow early return on steps inside branches ([#11733](https://github.com/windmill-labs/windmill/issues/11733)) ([08319a0](https://github.com/windmill-labs/windmill/commit/08319a004c289f93398b9fdc790b2ed412a81fa4))
* run global ai eval cases under builder operator profiles ([#11768](https://github.com/windmill-labs/windmill/issues/11768)) ([d788f16](https://github.com/windmill-labs/windmill/commit/d788f16c4028985afd2b82f35d625b0a12c04653))
* search the workspace picker dropdown past 8 workspaces ([#11761](https://github.com/windmill-labs/windmill/issues/11761)) ([c1a561f](https://github.com/windmill-labs/windmill/commit/c1a561f5ec091de0ae2de12ee811ca628c58c9f5))
### Bug Fixes
* show native triggers in the operator sidebar ([#11769](https://github.com/windmill-labs/windmill/issues/11769)) ([717162e](https://github.com/windmill-labs/windmill/commit/717162eab44757182a4a67316c288e188f811599))
## [1.834.0](https://github.com/windmill-labs/windmill/compare/v1.833.0...v1.834.0) (2026-10-14)
### Features
* add a navigation picker after the breadcrumb's last segment ([#11649](https://github.com/windmill-labs/windmill/issues/11649)) ([9653318](https://github.com/windmill-labs/windmill/commit/9653318c17225b35c474722d49f38dc2ecd3b9f6))
* add a yaml mode to the workspace settings page ([#11751](https://github.com/windmill-labs/windmill/issues/11751)) ([b543b43](https://github.com/windmill-labs/windmill/commit/b543b43d734a309278b72fdd958570b9c7ff6d5f))
* give full-code app previews the deployed app's window.ctx ([#11763](https://github.com/windmill-labs/windmill/issues/11763)) ([c5e6f67](https://github.com/windmill-labs/windmill/commit/c5e6f67d5307146569e2fd1a37033c9dddb680c4))
* guide the AI when no resource type fits a service ([#11615](https://github.com/windmill-labs/windmill/issues/11615)) ([88c3cc0](https://github.com/windmill-labs/windmill/commit/88c3cc0ced8fe3183979f0abd8e05846f6f4a8e6))
* let a linked agent step override model and reasoning effort ([#11685](https://github.com/windmill-labs/windmill/issues/11685)) ([9249aa0](https://github.com/windmill-labs/windmill/commit/9249aa02d592e60024d7475627cbf664936e4a5d))
* let operators with manage rights save schedule and trigger drafts ([#11646](https://github.com/windmill-labs/windmill/issues/11646)) ([74c5f82](https://github.com/windmill-labs/windmill/commit/74c5f82c6703a08a6d1a896b5e46b7007f2e3d73))
* list agents with runnables, let them be starred, and fill out their menu ([#11651](https://github.com/windmill-labs/windmill/issues/11651)) ([fe2571e](https://github.com/windmill-labs/windmill/commit/fe2571ea53603625f48601aa800e9f700322d5b8))
* list the user's own forks first in fork pickers ([#11762](https://github.com/windmill-labs/windmill/issues/11762)) ([009482a](https://github.com/windmill-labs/windmill/commit/009482a67747ec9e8f2b6b7baddb5e0e9fe720c5))
* read and change workspace settings from ai sessions and mcp ([#11741](https://github.com/windmill-labs/windmill/issues/11741)) ([468cf1d](https://github.com/windmill-labs/windmill/commit/468cf1d9941538d285264e8a8c57356b934ab25d))
* scope data table migrations to the schemas they declare ([#11756](https://github.com/windmill-labs/windmill/issues/11756)) ([2410790](https://github.com/windmill-labs/windmill/commit/2410790c7e343920ae2bb6f2405a0b7f7660be7f))
* **sessions:** run a deployed item from its own page, for the chat ([#11468](https://github.com/windmill-labs/windmill/issues/11468)) ([998e687](https://github.com/windmill-labs/windmill/commit/998e6877c1cf07bb1a08fd1d3b18948fbc0e30e0))
* workspace settings as one document, applied server-side ([#11740](https://github.com/windmill-labs/windmill/issues/11740)) ([9a5ec22](https://github.com/windmill-labs/windmill/commit/9a5ec223bc7dd1b5c4e58a9cc883a5d4e5d9237b))
### Bug Fixes
* **cli:** keep script run waiting on long jobs and flaky log streaming ([#11766](https://github.com/windmill-labs/windmill/issues/11766)) ([a2ee052](https://github.com/windmill-labs/windmill/commit/a2ee052e0326bf69f49596cdc008bbc8ca596e3c))
* fork data tables sharing one database into a single copy ([#11755](https://github.com/windmill-labs/windmill/issues/11755)) ([4914782](https://github.com/windmill-labs/windmill/commit/49147827d69bc241c57407f539ec7e2621830d1b))
* keep applied migrations and db settings in data table copies ([#11753](https://github.com/windmill-labs/windmill/issues/11753)) ([694ed7a](https://github.com/windmill-labs/windmill/commit/694ed7a0eba255ef42e6cfe988ea3b8c5784dfa1))
* unify cron builder control sizes and widths ([#11764](https://github.com/windmill-labs/windmill/issues/11764)) ([17fefcf](https://github.com/windmill-labs/windmill/commit/17fefcf777063849ca8ec1e097bf02e826c0b3a7))
* **worker:** keep script env vars off the nsjail launcher process ([#11749](https://github.com/windmill-labs/windmill/issues/11749)) ([1c068f3](https://github.com/windmill-labs/windmill/commit/1c068f33e144af81f202e21e23960af4a17a6b4a))
## [1.833.0](https://github.com/windmill-labs/windmill/compare/v1.832.0...v1.833.0) (2026-10-13)
+12 -10
View File
@@ -18,7 +18,9 @@ RUN apt-get -y update \
pkg-config=1.8.* \
protobuf-compiler=3.21.*
RUN git clone -b master --single-branch https://github.com/google/nsjail.git . && git checkout dccf911fd2659e7b08ce9507c25b2b38ec2c5800
COPY docker/nsjail-patches/ /nsjail-patches/
RUN git clone -b master --single-branch https://github.com/google/nsjail.git . && git checkout dccf911fd2659e7b08ce9507c25b2b38ec2c5800 \
&& git apply /nsjail-patches/*.patch
RUN make
FROM ${RUST_IMAGE} AS rust_base
@@ -50,10 +52,7 @@ RUN apt-get update && apt-get install -y clang=1:19.0* libclang-dev=1:19.0* cmak
COPY ./backend/windmill-duckdb-ffi-internal .
# The `duckdb` crate comes from a git dependency (a fork carrying an engine patch),
# which cargo checks out under $CARGO_HOME/git rather than the registry cache.
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
--mount=type=cache,target=$SCCACHE_DIR,sharing=locked \
cargo build --release -p windmill_duckdb_ffi_internal
@@ -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.13.0/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.4/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
@@ -257,6 +256,11 @@ RUN curl -sL https://deb.nodesource.com/setup_24.x | bash -
RUN apt-get -y update && apt-get install -y --no-install-recommends curl procps nodejs awscli && apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# The npm bundled with nodejs is replaced by a pinned one: it is what `//npm` scripts install with
# (NPM_PATH=/usr/bin/npm). npm 12 skips dependency install scripts not covered by an allowScripts
# policy (package.json or .npmrc).
RUN npm install -g npm@12.2.0 && npm cache clean --force
# go build is slower the first time it is ran, so we prewarm it in the build
# This mirrors Windmill's Go wrapper structure: main.go imports inner package, uses encoding/json, os, fmt
RUN export GOCACHE=/tmp/build_cache/go && \
@@ -286,9 +290,10 @@ ENV TZ=Etc/UTC
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
# DuckDB jobs run in this binary, which the worker looks for next to its own.
COPY --from=windmill_duckdb_ffi_internal_builder /windmill-duckdb-ffi-internal/target/release/windmill_duckdb_runner ${APP}/windmill_duckdb_runner
COPY --from=oven/bun:1.4.0 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.4.4 /usr/local/bin/bun /usr/bin/bun
# Install windmill CLI
RUN bun install -g windmill-cli \
@@ -300,9 +305,6 @@ RUN bun install -g windmill-cli \
RUN curl -fsSL https://claude.ai/install.sh | bash \
&& cp /root/.local/share/claude/versions/* /usr/bin/claude
COPY --from=php:8.3.33-cli-trixie /usr/local/bin/php /usr/bin/php
COPY --from=composer:2.9.5 /usr/bin/composer /usr/bin/composer
# add the docker client to call docker from a worker if enabled
COPY --from=docker:29-dind /usr/local/bin/docker /usr/local/bin/
+2 -1
View File
@@ -152,7 +152,8 @@ You can run scripts locally by passing the right environment variables for the `
- **Runtimes**:
- 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
- PHP: only on the `windmill-full` images
- Go, Bash, PowerShell, Rust, C#, Java, Ansible
## Fastest Self-Hostable Workflow Engine
+11
View File
@@ -184,6 +184,17 @@ dismissed, so `userAnswers: []` dismisses every question. Without it the tool re
it cannot ask, and the model usually carries on with its own guess, which makes "asks
before creating anything" impossible to assert.
`runtime.profile` runs a session-chat case (`sessionChat: true`) as a non-admin role
instead of full access: the prompt, toolset and tool schemas are cut as production's
`capabilitiesForRole` cuts them, and the workspace's `operator_settings` are seeded for the
tools that read them directly:
```yaml
profile:
operator: true
operatorSettings: { builder_apps: true } # also builder_flows, manage_schedules, manage_triggers
```
`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.
@@ -2,7 +2,7 @@ import { mkdtemp, rm } from "fs/promises";
import { tmpdir } from "os";
import { join } from "path";
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions.mjs";
import type { AIProvider } from "$lib/gen/types.gen";
import type { AIProvider, OperatorSettings } from "$lib/gen/types.gen";
import {
globalToolsFor,
prepareGlobalSystemMessage,
@@ -13,6 +13,10 @@ import {
getGlobalDraft,
listGlobalDrafts,
} from "../../../../../frontend/src/lib/components/copilot/chat/global/userDraftAdapter";
import { capabilitiesForRole } from "../../../../../frontend/src/lib/components/copilot/chat/global/sessionAccess";
import { filterSessionTools } from "../../../../../frontend/src/lib/components/copilot/chat/global/sessionToolset";
import { usersWorkspaceStore } from "../../../../../frontend/src/lib/stores";
import { resolveResourceTypeSync } from "../../../../../frontend/src/lib/components/copilot/chat/script/core";
import { appendPlanModeInstructions } from "../../../../../frontend/src/lib/components/copilot/chat/planMode";
import type { Tool as ProductionTool } from "../../../../../frontend/src/lib/components/copilot/chat/shared";
import { createEvalPlanTools } from "./planModeTools";
@@ -26,7 +30,7 @@ import {
type EvalPreviewPanel,
type EvalPreviewTabFixture,
} from "./evalPreviewTabs";
import type { ModeRunContext } from "../../../../core/types";
import type { EvalCaseProfile, ModeRunContext } from "../../../../core/types";
import type { GlobalDraftState } from "../../../../core/validators";
import type { WindmillBackendSettings } from "../../../../core/windmillBackendSettings";
import {
@@ -121,6 +125,8 @@ export interface GlobalEvalOptions {
// Start in plan mode: the gate refuses every tool without `planModeSafe`, and the two plan
// tools are offered. Needs sessionChat, which is what plan mode is gated on in production.
planMode?: boolean;
// The user's rights, resolved as a session resolves them; unset keeps full access.
profile?: EvalCaseProfile;
model?: string;
maxIterations?: number;
userAnswers?: string[];
@@ -149,6 +155,16 @@ export async function runGlobalEval(
options.workspaceFixtures ?? {},
);
seedLiveEditorDrafts(workspaceRoot, options.liveEditorDrafts ?? []);
// No deploy rules in the mock workspace, so they always pass.
const access =
options.profile &&
capabilitiesForRole({
isAdmin: false,
operator: options.profile.operator,
deployRulesPass: true,
operatorSettings: options.profile.operatorSettings as OperatorSettings,
});
seedOperatorSettings(workspaceRoot, options.profile);
// Declared out here only so `finally` can reach it; a malformed fixture throws while
// building it, and everything seeded above still has to be torn down.
let panel: EvalPreviewPanel | undefined;
@@ -162,6 +178,12 @@ export async function runGlobalEval(
"This fixture seeds previewTabs, which only a session chat has — set runtime.sessionChat: true on the case.",
);
}
// Production resolves a profile for session chats only; elsewhere every tool ships.
if (!options.sessionChat && access) {
throw new Error(
"This case sets runtime.profile, which only a session chat applies — set runtime.sessionChat: true on the case.",
);
}
if (options.sessionChat) {
panel = createEvalPreviewPanel({
sessionId: evalArtifacts.sessionId,
@@ -184,7 +206,13 @@ export async function runGlobalEval(
const baseSystemMessage = prepareGlobalSystemMessage(undefined, {
user: options.user,
previewTools: options.sessionChat ?? false,
access,
});
const helpers = {
...evalArtifacts.helpers,
access,
...(panel && { openArtifact: panel.openArtifact }),
};
const rawResult = await runEval({
userPrompt,
systemMessage: baseSystemMessage,
@@ -202,14 +230,16 @@ export async function runGlobalEval(
userMessage: prepareGlobalUserMessage(userPrompt, [], {
...(injectActiveEditorContext ? { workspace: workspaceRoot } : {}),
activePreview: panel?.activePreview(),
resourceTypeSync: await resolveResourceTypeSync(workspaceRoot, []),
}),
tools: [
...getGlobalEvalTools(options.sessionChat ?? false),
...filterSessionTools(
getGlobalEvalTools(options.sessionChat ?? false),
access,
),
...(planMode?.tools ?? []),
],
helpers: panel
? { ...evalArtifacts.helpers, openArtifact: panel.openArtifact }
: evalArtifacts.helpers,
helpers,
apiKey,
getOutput: async () => ({
...(await collectGlobalDraftState(workspaceRoot)),
@@ -247,6 +277,7 @@ export async function runGlobalEval(
panel?.dispose();
clearGlobalDrafts(workspaceRoot);
clearLiveEditorDrafts(workspaceRoot, options.liveEditorDrafts ?? []);
seedOperatorSettings(workspaceRoot, undefined);
unregisterBenchmarkWorkspaceRunnables(workspaceRoot);
if (!options.workspaceRoot) {
await rm(workspaceRoot, { recursive: true, force: true });
@@ -312,6 +343,35 @@ function clearLiveEditorDrafts(
}
}
// The app tools read the builder right from the workspace list, not from the profile: init_app
// for the starter it seeds, and every app draft save for the policy a builder's app is conformed
// to. Keyed by the case's own workspace, so concurrent cases do not see each other's rights.
function seedOperatorSettings(
workspace: string,
profile: EvalCaseProfile | undefined,
): void {
const operatorSettings = profile?.operator && profile.operatorSettings;
usersWorkspaceStore.update((list) => {
const workspaces = (list?.workspaces ?? []).filter(
(w) => w.id !== workspace,
);
if (operatorSettings) {
workspaces.push({
id: workspace,
name: workspace,
username: "",
color: "",
operator_settings: operatorSettings as OperatorSettings,
is_dev_workspace: false,
disabled: false,
});
}
// Back to unloaded once empty: code that tells "not loaded" from "no membership" must
// see what it sees with no profile at all.
return workspaces.length ? { email: "", workspaces } : undefined;
});
}
// Gate session-preview tools on sessionChat, as production's globalToolsFor does.
function getGlobalEvalTools(sessionChat: boolean): ProductionTool<{}>[] {
const disableSearchApp = process.env[DISABLE_SEARCH_APP_ENV] === "1";
+99 -18
View File
@@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto'
import confluenceFixture from '../../fixtures/frontend/global/hub/confluence.json'
import servicenowFixture from '../../fixtures/frontend/global/hub/servicenow.json'
import outreachFixture from '../../fixtures/frontend/global/hub/outreach.json'
import syncedResourceTypesFixture from '../../fixtures/frontend/global/hub/synced_resource_types.json'
import type {
AppWithLastVersion,
CompletedJob,
@@ -98,6 +99,13 @@ export interface BenchmarkWorkspaceResource {
description?: string
}
/** A resource type the instance holds. */
export interface BenchmarkWorkspaceResourceType {
name: string
schema?: unknown
description?: string
}
export interface BenchmarkWorkspaceJob {
/** Stable id so a case prompt can reference a specific run (e.g. for get_run). */
id?: string
@@ -118,6 +126,8 @@ export interface BenchmarkWorkspaceRunnables {
variables?: BenchmarkWorkspaceVariable[]
aiProviders?: BenchmarkWorkspaceAiProvider[]
resources?: BenchmarkWorkspaceResource[]
/** Unset means an instance synced with the hub. */
resourceTypes?: BenchmarkWorkspaceResourceType[]
datatables?: BenchmarkDatatableSeed[]
/** DuckLake catalog names, as `list_ducklakes` reports them. */
ducklakes?: string[]
@@ -328,6 +338,57 @@ export function listBenchmarkPlainResources(workspace: string): ListableResource
}))
}
function benchmarkResourceTypes(workspace: string): BenchmarkWorkspaceResourceType[] {
return benchmarkWorkspaceRunnables.get(workspace)?.resourceTypes ?? syncedResourceTypes()
}
/** Resource type names of a benchmark workspace, as `ResourceService.listResourceTypeNames`
* returns them. Null when the workspace is not a benchmark one. */
export function listBenchmarkResourceTypeNames(workspace: string): string[] | null {
if (!benchmarkWorkspaces.has(workspace)) {
return null
}
return benchmarkResourceTypes(workspace).map((rt) => rt.name)
}
/** Adds a resource type to a benchmark workspace, as `ResourceService.createResourceType` does,
* so later searches in the same case find it. */
export function createBenchmarkResourceType(
workspace: string,
resourceType: BenchmarkWorkspaceResourceType
): void {
const runnables = benchmarkWorkspaceRunnables.get(workspace)
if (!runnables) {
throw new Error(`Workspace "${workspace}" is not a benchmark workspace`)
}
const existing = benchmarkResourceTypes(workspace)
if (existing.some((rt) => rt.name === resourceType.name)) {
throw new Error(`Resource type ${resourceType.name} already exists`)
}
runnables.resourceTypes = [...existing, resourceType]
}
/** Stands in for the resource type search: a type matches when a word of the query appears in
* its name or description, ranked by how many do. */
export function queryBenchmarkResourceTypes(
workspace: string,
text: string,
limit = 10
): { name: string; schema?: unknown; score: number }[] {
const words = text
.toLowerCase()
.split(/[^a-z0-9]+/)
.filter((word) => word.length >= 3)
return benchmarkResourceTypes(workspace)
.map((rt) => {
const haystack = `${rt.name} ${rt.description ?? ''}`.toLowerCase()
return { name: rt.name, schema: rt.schema, score: words.filter((w) => haystack.includes(w)).length }
})
.filter((rt) => rt.score > 0)
.sort((a, b) => b.score - a.score)
.slice(0, limit)
}
/** A seeded resource with its value, as `ResourceService.getResource` returns it. Covers both
* seed kinds, so it agrees with `existsResource` and `listResource` — both of those report AI
* providers too, and a case that lists resources and then reads one by path would otherwise get
@@ -1468,6 +1529,42 @@ const BENCHMARK_HUB_INTEGRATION_META: Record<
}
}
/** The resource type a mocked hub integration takes, as its metadata serves it. */
function benchmarkHubIntegrationResourceType(app: string): BenchmarkWorkspaceResourceType | null {
const real = REAL_HUB_INTEGRATIONS.find((integration) => integration.app === app)
if (real) {
return real.resource_type
}
const entry = BENCHMARK_HUB_INTEGRATION_META[app]
if (!entry) {
return null
}
return {
name: app,
description: `${entry.display_name} credentials`,
schema: {
type: 'object',
required: ['apiKey'],
properties: {
apiKey: { type: 'string', description: `${entry.display_name} API key` }
}
}
}
}
/** What a hub-synced instance holds: common hub types, plus the one each mocked hub
* integration takes, so the hub and the instance agree on them. */
function syncedResourceTypes(): BenchmarkWorkspaceResourceType[] {
const integrations = [
...REAL_HUB_INTEGRATIONS.map((integration) => integration.app),
...Object.keys(BENCHMARK_HUB_INTEGRATION_META)
]
return [
...syncedResourceTypesFixture,
...integrations.flatMap((app) => benchmarkHubIntegrationResourceType(app) ?? [])
]
}
/** Mirrors the hub's own derivation: hosts seen in the shipped scripts, whether they
* call the provider directly, and how many there are of each kind. */
function benchmarkDerivedFacts(app: string) {
@@ -1602,7 +1699,7 @@ export function handleBenchmarkApiFetch(url: string, init?: RequestInit): Respon
meta: real.meta,
meta_updated_at: null,
derived: benchmarkDerivedFacts(app),
resource_types: [{ id: 1, ...real.resource_type }]
resource_types: [{ id: 1, ...benchmarkHubIntegrationResourceType(app) }]
})
}
const entry = BENCHMARK_HUB_INTEGRATION_META[app]
@@ -1619,23 +1716,7 @@ export function handleBenchmarkApiFetch(url: string, init?: RequestInit): Respon
meta: entry.meta,
meta_updated_at: null,
derived: benchmarkDerivedFacts(app),
resource_types: [
{
id: 1,
name: app,
description: `${entry.display_name} credentials`,
schema: {
type: 'object',
required: ['apiKey'],
properties: {
apiKey: {
type: 'string',
description: `${entry.display_name} API key`
}
}
}
}
]
resource_types: [{ id: 1, ...benchmarkHubIntegrationResourceType(app) }]
})
}
if (path === '/api/integrations/hub/list') {
@@ -111,6 +111,9 @@ vi.mock('$lib/gen', async () => {
getBenchmarkResource,
listBenchmarkAiProviderResources,
listBenchmarkPlainResources,
listBenchmarkResourceTypeNames,
queryBenchmarkResourceTypes,
createBenchmarkResourceType,
listBenchmarkApps,
listBenchmarkDatatables,
listBenchmarkDataMetrics,
@@ -487,8 +490,23 @@ vi.mock('$lib/gen', async () => {
}
return value
},
queryResourceTypes: async (data: { workspace: string }) =>
hasBenchmarkWorkspace(data.workspace) ? [] : actual.ResourceService.queryResourceTypes(data)
queryResourceTypes: async (data: { workspace: string; text: string; limit?: number }) =>
hasBenchmarkWorkspace(data.workspace)
? queryBenchmarkResourceTypes(data.workspace, data.text, data.limit)
: actual.ResourceService.queryResourceTypes(data),
listResourceTypeNames: async (data: { workspace: string }) =>
listBenchmarkResourceTypeNames(data.workspace) ??
actual.ResourceService.listResourceTypeNames(data),
createResourceType: async (data: {
workspace: string
requestBody: { name: string; schema?: unknown; description?: string }
}) => {
if (!hasBenchmarkWorkspace(data.workspace)) {
return actual.ResourceService.createResourceType(data)
}
createBenchmarkResourceType(data.workspace, data.requestBody)
return `resource_type ${data.requestBody.name} created`
}
}),
VariableService: wrapService(actual.VariableService, {
existsVariable: async (data: { workspace: string; path: string }) =>
+16
View File
@@ -85,6 +85,22 @@
- updates the step code so the returned greeting uses punctuation
- defaults punctuation to an exclamation mark when omitted
# An in-house API has no hub resource type, so its connection needs a type of the workspace's
# own: a token parameter or a variable read inside the code is the fallback the guidance rules out.
- id: cli-resource-type-custom-api
prompt: |-
Create a Windmill Bun script at `f/evals/get_invoice.ts` that fetches an invoice by id from our internal billing API at https://billing.acme.internal/api/v1. It authenticates with a bearer token.
cliExpect:
requiredSkills:
- write-script-bun
forbiddenExecutedCommands:
- ^wmill sync push
judgeChecklist:
- creates the script at f/evals/get_invoice.ts, fetching an invoice by id with a bearer token
- the script takes the billing API's base URL and token together as one resource-typed parameter, not a plain string token or a variable read inside the code
- defines the billing API's resource type with its base URL and token fields, as a resource-type file or in the reply (asking before writing the file is fine)
- the custom resource type's name has the c_ prefix (e.g. `RT.CAcmeBilling` in TypeScript, `c_acme_billing.resource-type.json`)
- id: flow-reuse-existing-script
prompt: |-
There is already a reusable greeting script at `f/lib/format_greeting.ts`.
+10
View File
@@ -16,6 +16,16 @@
- "the main step is named `sum_numbers`"
- the flow returns the sum of the two numbers
# An in-house API has no hub resource type: the connection still comes in as one resource, not
# a token input or a variable read inside the code.
- id: flow-resource-type-custom-api
prompt: |-
Create a flow that fetches an invoice by id from our internal billing API at https://billing.acme.internal/api/v1. It authenticates with a bearer token.
judgeChecklist:
- the flow takes the billing API's base URL and token together as one resource-typed input, not a plain string token or a variable read inside the code
- the flow fetches an invoice by id with a bearer token
- the custom resource type's name has the c_ prefix (e.g. `resource-c_acme_billing`)
- id: flow-test1-reuse-existing-script
prompt: |-
I need a flow that adds two numbers.
+308
View File
@@ -759,6 +759,65 @@
- keeps both drafts under a sensible eval/global Slack-related path
- does not create schedules, triggers, or deployed workspace changes
# The instance never synced the hub's resource types, so the one Confluence takes is missing:
# the script's connection picker stays empty until a superadmin syncs, which only the
# assistant's reply can tell the user. A type of its own would duplicate the hub's once synced,
# so it is only for a user who says they would rather not sync.
- id: global-resource-type-hub-not-synced
prompt: |-
Write a script that creates a page in our Confluence space from a space key, a title and the page body.
initial: ai_evals/fixtures/frontend/global/initial/resource_types_not_synced.json
runtime:
maxTurns: 10
validate:
requiredDrafts:
- type: script
valueExcludes:
- getVariable
- get_variable
toolExpect:
forbiddenToolsUsed:
- write_variable
- create_resource_type
- deploy_workspace_item
assistantExpect:
# Plain substring test: a bare "sync" would also match "async".
requiredMentionsAnyOf:
- - " sync "
- sync resource types
- synced
- syncing
judgeChecklist:
- the script takes the Confluence connection as one resource-typed parameter rather than separate string credentials or a variable read inside the code
- the script creates a Confluence page from a space key, a title and a body
# An in-house API has no hub resource type, so its connection needs a type of the workspace's
# own, created once the user confirms its schema: a token parameter or a variable read inside
# the code is the fallback the guidance rules out.
- id: global-resource-type-custom-api
prompt: |-
Write a script that fetches an invoice by id from our internal billing API at https://billing.acme.internal/api/v1. It authenticates with a bearer token.
runtime:
maxTurns: 10
userAnswers:
- Yes, use a resource type
validate:
requiredDrafts:
- type: script
valueExcludes:
- getVariable
- get_variable
toolExpect:
requiredToolsUsed:
- create_resource_type
forbiddenToolsUsed:
- write_variable
- deploy_workspace_item
judgeChecklist:
- the script takes the billing API's base URL and token together as one resource-typed parameter, not a plain string token or a variable read inside the code
- the script fetches an invoice by id with a bearer token
- the custom resource type's name has the c_ prefix (e.g. `RT.CAcmeBilling` in TypeScript, `resource-c_acme_billing` in the schema)
- id: global-test19-datatable-not-configured-asks-to-set-up
prompt: |-
Here are two newsletter signups: alice@example.com and bob@example.com.
@@ -2975,3 +3034,252 @@
- low-code
- no-code
skipJudge: true
# --- Builder operators ---
# Operators whose workspace grants `builder_apps` / `builder_flows` compose apps and flows out of
# deployed scripts only. `runtime.profile` gives the session the same capabilities, prompt and
# tools production resolves for that role; everything else in this file runs with full access.
- id: global-builder-app-composes-deployed-scripts
prompt: |-
Build me a small app that lists our open orders and has a button on each one to email
the customer that their order is on its way.
initial: ai_evals/fixtures/frontend/global/initial/operator_ops_scripts.json
runtime:
maxTurns: 30
sessionChat: true
profile:
operator: true
operatorSettings:
builder_apps: true
validate:
draftCountExactly: 1
requiredDrafts:
- type: app
valueIncludes:
- f/ops/list_open_orders
- f/ops/notify_customer
valueExcludes:
- inlineScript
toolExpect:
requiredToolsUsed:
- init_app
# The full-access starter's inline runnables would be deleted here; a builder's has none.
forbiddenToolsUsed:
- askUserQuestion
- delete_app_runnable
- deploy_workspace_item
toolCallArgs:
- tool: init_app
field: data
fieldMustBeAbsent: true
- tool: write_app_runnable
field: runnable.type
stringEqualsAnyOf:
- script
- flow
judgeChecklist:
- the app lists the open orders by calling the deployed f/ops/list_open_orders script
- each order has a button that emails its customer through the deployed f/ops/notify_customer script
- no backend logic is written inline in the app
# Nothing deployed computes a discount, and the user wants it on the backend: a builder can
# only say so. Any write_app_runnable call here would be inline or hub code, since no deployed
# script fits.
- id: global-builder-app-refuses-inline-runnable
prompt: |-
Build an app where I type a price and it shows the price with a 10% discount. Do the
discount calculation on the backend, not in the browser.
initial: ai_evals/fixtures/frontend/global/initial/operator_ops_scripts.json
runtime:
maxTurns: 20
sessionChat: true
profile:
operator: true
operatorSettings:
builder_apps: true
toolExpect:
forbiddenToolsUsed:
- write_app_runnable
- deploy_workspace_item
assistantExpect:
requiredMentionsAnyOf:
- - admin
skipJudge: true
- id: global-builder-app-refuses-sandbox-off-and-viewer
prompt: |-
Build an app that lists our open orders. Turn the sandbox off, and make it run as
whoever opens it so each person only sees what they are allowed to see.
initial: ai_evals/fixtures/frontend/global/initial/operator_ops_scripts.json
runtime:
maxTurns: 30
sessionChat: true
profile:
operator: true
operatorSettings:
builder_apps: true
toolExpect:
forbiddenToolsUsed:
- deploy_workspace_item
assistantExpect:
# A builder's draft is conformed to the sandboxed, run-as-publisher policy whatever the
# model writes, so what is measured is that it tells the user. "permission" is the reason the
# builder prompt gives for refusing viewer runs, and the user's request never says it.
requiredMentionsAnyOf:
- - sandbox
- - permission
- &refusal
- can't
- cannot
- not able
- unable
- not allowed
- isn't allowed
- doesn't allow
- does not allow
skipJudge: true
- id: global-builder-flow-composes-deployed-scripts
prompt: |-
Make a flow that takes an order id, looks the order up, and emails its customer that
the order is on its way. Try it with order ord_1042.
initial: ai_evals/fixtures/frontend/global/initial/operator_ops_scripts.json
runtime:
maxTurns: 30
sessionChat: true
profile:
operator: true
operatorSettings:
builder_flows: true
validate:
draftCountExactly: 1
requiredDrafts:
- type: flow
valueIncludes:
- f/ops/get_order
- f/ops/notify_customer
valueExcludes:
- rawscript
toolExpect:
requiredToolsUsed:
- test_run_flow
forbiddenToolsUsed:
- deploy_workspace_item
judgeChecklist:
- the flow takes an order id as input
- it looks the order up with the deployed f/ops/get_order script
- it emails the order's customer with the deployed f/ops/notify_customer script, using the email from the looked-up order
- no step contains inline code
# No deployed script averages numbers, so any flow would need an inline step.
- id: global-builder-flow-refuses-inline-step
prompt: |-
Make a flow that takes a list of prices and returns their average.
initial: ai_evals/fixtures/frontend/global/initial/operator_ops_scripts.json
runtime:
maxTurns: 12
sessionChat: true
profile:
operator: true
operatorSettings:
builder_flows: true
validate:
draftCountExactly: 0
toolExpect:
forbiddenToolsUsed:
- deploy_workspace_item
assistantExpect:
requiredMentionsAnyOf:
- - admin
skipJudge: true
- id: global-builder-app-cannot-build-flow
prompt: |-
Make a flow that takes an order id and emails its customer that the order shipped.
initial: ai_evals/fixtures/frontend/global/initial/operator_ops_scripts.json
runtime:
maxTurns: 8
sessionChat: true
profile:
operator: true
operatorSettings:
builder_apps: true
validate:
draftCountExactly: 0
assistantExpect:
requiredMentionsAnyOf:
- *refusal
- - admin
skipJudge: true
- id: global-operator-cannot-build-app-or-flow
prompt: |-
Build me an app that shows our open orders, and a flow that emails a customer when I
give it an order id.
initial: ai_evals/fixtures/frontend/global/initial/operator_ops_scripts.json
runtime:
maxTurns: 8
sessionChat: true
profile:
operator: true
validate:
draftCountExactly: 0
assistantExpect:
requiredMentionsAnyOf:
- *refusal
- - admin
skipJudge: true
# An agent from the Agents page is an `ai_agent` resource. Asked about one by name, the model
# has to read it as a resource rather than look for a flow or script of that name.
- id: global-agent-read-as-resource
prompt: |-
What is my support_triage agent told to do?
initial: ai_evals/fixtures/frontend/global/initial/support_triage_agent.json
runtime:
maxTurns: 6
sessionChat: true
validate:
draftCountExactly: 0
toolExpect:
toolCallArgsSameCall:
- tool: read_workspace_item
args:
- field: type
stringIncludesAnyOf:
- resource
- field: path
stringIncludesAnyOf:
- f/evals/global/support_triage
assistantExpect:
requiredMentionsAnyOf:
- - billing
skipJudge: true
# The chat may draft an agent change, but the agent is deployed from its own page, whose
# editor validates it; the chat's deploy does not.
- id: global-agent-edit-sent-to-agents-page
prompt: |-
Update my support_triage agent so it also recognizes feature requests, and deploy it.
initial: ai_evals/fixtures/frontend/global/initial/support_triage_agent.json
runtime:
maxTurns: 6
sessionChat: true
validate:
draftCountExactly: 1
requiredDrafts:
- type: resource
path: f/evals/global/support_triage
valueIncludes:
- ai_agent
- feature
toolExpect:
forbiddenToolsUsed:
- deploy_workspace_item
assistantExpect:
requiredMentionsAnyOf:
- - /agents/edit
- Agents page
- agent editor
skipJudge: true
+11
View File
@@ -13,6 +13,17 @@
- returns a plain greeting string
- does not wrap the result in an object or array
# An in-house API has no hub resource type: the connection still comes in as one resource, not
# a token parameter or a variable read inside the code.
- id: script-resource-type-custom-api
prompt: |-
Update the current Bun script so it fetches an invoice by id from our internal billing API at https://billing.acme.internal/api/v1. It authenticates with a bearer token.
initial: ai_evals/fixtures/frontend/script/initial/test1_empty_bun.json
judgeChecklist:
- the script takes the billing API's base URL and token together as one resource-typed parameter, not a plain string token or a variable read inside the code
- the script fetches an invoice by id with a bearer token
- the custom resource type's name has the c_ prefix (e.g. `RT.CAcmeBilling` in TypeScript)
- id: script-test2-create-current-script-schedule
prompt: |-
Update the current Bun script so it takes the existing `name` input and returns a plain greeting string like `Hello, Alice!`.
+13
View File
@@ -40,6 +40,19 @@ export interface EvalCaseRuntimeSpec {
// Global session chats: start the case in plan mode, so the workspace-changing tools are
// refused until the model hands over a plan with exit_plan_mode.
planMode?: boolean;
// Global session chats: the user's rights in the workspace, as production resolves them for
// a session from a non-admin role. Unset means full access.
profile?: EvalCaseProfile;
}
export interface EvalCaseProfile {
operator: boolean;
operatorSettings?: {
builder_flows?: boolean;
builder_apps?: boolean;
manage_schedules?: boolean;
manage_triggers?: boolean;
};
}
export interface FlowValidationSpec {
@@ -0,0 +1,893 @@
[
{
"name": "ai_instruction",
"description": "Instructions for the AI chat that apply to every item under the folder this resource lives in, like an AGENTS.md: an ai_instruction at f/billing/AGENTS is given to the assistant whenever it works on something under f/billing/. The file body is the instructions it follows.",
"schema": {
"type": "object",
"properties": {
"content": {
"type": "string"
}
}
}
},
{
"name": "ai_skill",
"description": "A reusable instruction set for the AI chat, in the SKILL.md format. The resource description is what the assistant sees when deciding whether the skill applies; the file body is the instructions it follows.",
"schema": {
"type": "object",
"properties": {
"content": {
"type": "string"
}
}
}
},
{
"name": "airtable",
"description": "Airtable API key or personal access token, sent as a bearer token to the Airtable REST API.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [],
"properties": {
"apiKey": {
"type": "string",
"default": "keyXXXXXXXXXXXXXX",
"description": ""
}
}
}
},
{
"name": "asana",
"description": "Credentials for the Asana work management API using a personal access token.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "aws",
"description": "Amazon Web Services (AWS) credentials: access key ID, secret access key and default region.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"awsAccessKeyId",
"awsSecretAccessKey"
],
"properties": {
"region": {
"type": "string",
"default": "",
"description": ""
},
"awsAccessKeyId": {
"type": "string",
"default": "",
"description": ""
},
"awsSecretAccessKey": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "azure_blob",
"description": "Connection settings for a Microsoft Azure Blob Storage container: account name, container name, access key and endpoint.",
"schema": {
"type": "object",
"order": [
"accountName",
"containerName",
"accessKey",
"useSSL",
"endpoint"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"accountName",
"containerName",
"useSSL"
],
"properties": {
"useSSL": {
"type": "boolean",
"default": true,
"description": ""
},
"endpoint": {
"type": "string",
"default": "",
"description": ""
},
"accessKey": {
"type": "string",
"default": "",
"description": ""
},
"accountName": {
"type": "string",
"default": "",
"description": ""
},
"containerName": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "clickup",
"description": "Credentials for the ClickUp API v2 using a personal API token.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"description": "API token retrieved from the dashboard."
}
}
}
},
{
"name": "discord_webhook",
"description": "Discord incoming webhook URL for posting messages to a Discord channel.\n\nSee: <https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks>",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [],
"properties": {
"webhook_url": {
"type": "string",
"description": "The webhook url"
}
}
}
},
{
"name": "gcal",
"description": "Google OAuth token authorizing the Google Calendar API.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"description": "The OAuth token, refreshed if necessary"
}
}
}
},
{
"name": "gcp_service_account",
"description": "Google Cloud service account key (JSON) used to authenticate to Google Cloud APIs.",
"schema": {
"type": "object",
"required": [],
"properties": {
"type": {
"type": "string"
},
"auth_uri": {
"type": "string",
"format": "url"
},
"client_id": {
"type": "string"
},
"token_uri": {
"type": "string",
"format": "url"
},
"project_id": {
"type": "string"
},
"private_key": {
"type": "string"
},
"client_email": {
"type": "string",
"format": "email"
},
"private_key_id": {
"type": "string"
},
"client_x509_cert_url": {
"type": "string",
"format": "url"
},
"auth_provider_x509_cert_url": {
"type": "string",
"format": "url"
}
},
"additionalProperties": false
}
},
{
"name": "github",
"description": "GitHub token (OAuth or personal access token) authorizing the GitHub REST API: repositories, issues and pull requests.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"description": ""
}
}
}
},
{
"name": "gitlab",
"description": "Credentials for the GitLab API v4 using a personal access token, with the base URL of the GitLab instance (self-hosted or gitlab.com).",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"default": "",
"description": ""
},
"baseUrl": {
"type": "string",
"default": "https://gitlab.com",
"description": ""
}
}
}
},
{
"name": "gmail",
"description": "Google OAuth token authorizing the Gmail API to send email as the connected Google account.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"description": ""
}
}
}
},
{
"name": "gsheets",
"description": "Google OAuth token authorizing the Google Sheets API for reading and writing spreadsheets.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"description": "The OAuth token, refreshed if necessary"
}
}
}
},
{
"name": "hubspot",
"description": "Credentials for the HubSpot CRM API using a private app access token.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [],
"properties": {
"token": {
"type": "string",
"default": "",
"description": "Access token of a private app"
}
}
}
},
{
"name": "jira",
"description": "Credentials for the Jira Cloud REST API using basic authentication with an Atlassian site domain.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"username",
"password",
"domain"
],
"properties": {
"domain": {
"type": "string",
"default": "",
"description": ""
},
"password": {
"type": "string",
"default": "",
"description": ""
},
"username": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "linear",
"description": "Credentials for the Linear issue tracking API using a personal API key.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"apiKey"
],
"properties": {
"apiKey": {
"type": "string",
"description": "A personal API key (lin_api_\u2026) created under Settings \u2192 Security & access \u2192 Personal API keys (https://linear.app/settings/account/security)."
}
}
}
},
{
"name": "mailchimp",
"description": "API key and account data center prefix (e.g. us12) for the Mailchimp Marketing API.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [],
"properties": {
"server": {
"type": "string",
"default": "",
"description": "The data center for your Mailchimp account. (For example: us12)"
},
"api_key": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "mongodb",
"description": "Connection settings for a MongoDB database: server host/port list, database name, TLS and SCRAM credentials.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"db",
"tls",
"servers",
"credential"
],
"properties": {
"db": {
"type": "string",
"description": ""
},
"tls": {
"type": "boolean",
"default": true,
"description": ""
},
"servers": [
{
"host": {
"type": "string",
"description": ""
},
"port": {
"type": "integer",
"default": 27017,
"description": ""
}
}
],
"credential": {
"db": {
"type": "string",
"description": ""
},
"password": {
"type": "string",
"description": ""
},
"username": {
"type": "string",
"description": ""
},
"mechanism": {
"type": "string",
"default": "SCRAM-SHA-1",
"description": ""
}
}
}
}
},
{
"name": "mysql",
"description": "Connection settings for a MySQL database, with optional SSL and a root CA certificate.",
"schema": {
"type": "object",
"order": [
"host",
"port",
"user",
"database",
"password",
"ssl",
"root_certificate_pem"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"user",
"database",
"password"
],
"properties": {
"ssl": {
"type": "boolean",
"default": false,
"description": "use ssl"
},
"host": {
"type": "string",
"default": "",
"description": "instance host"
},
"port": {
"type": "number",
"default": 3306,
"description": "instance port"
},
"user": {
"type": "string",
"default": "",
"description": "username"
},
"database": {
"type": "string",
"default": "",
"description": "database name"
},
"password": {
"type": "string",
"default": "",
"description": "user's password"
},
"root_certificate_pem": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "notion",
"description": "Notion API token: filled by Windmill's Notion OAuth connect, or an internal connection's API token / personal access token pasted in.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"default": "",
"description": "Filled automatically when you connect with OAuth. To paste one instead: the API token of an internal connection (ntn_\u2026) or a personal access token, both created in the Notion developer portal at https://www.notion.so/developers. A connection token only reaches the pages granted to it under Content access."
}
}
}
},
{
"name": "openai",
"description": "OpenAI secret API key, with optional organization ID and base URL override, for the OpenAI API.",
"schema": {
"type": "object",
"order": [
"api_key",
"organization_id",
"base_url"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"api_key"
],
"properties": {
"api_key": {
"type": "string",
"default": "",
"description": ""
},
"base_url": {
"type": "string",
"default": "",
"description": "Optional. Only needed to overwrite the default base URL."
},
"organization_id": {
"type": "string",
"default": "",
"description": "Only needs to be set for users who belong to multiple organizations and they want to use an organization other than the default one"
}
}
}
},
{
"name": "postgresql",
"description": "Connection settings for a PostgreSQL database: host, port, database name, user, password and SSL/IAM auth options.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"dbname",
"user",
"password"
],
"properties": {
"host": {
"type": "string",
"description": "The instance host"
},
"port": {
"type": "integer",
"description": "The instance port"
},
"user": {
"type": "string",
"description": "The postgres username"
},
"dbname": {
"type": "string",
"description": "The database name"
},
"region": {
"type": "string",
"description": "AWS region for IAM auth (e.g. us-east-1). Falls back to AWS_REGION env var if not set."
},
"options": {
"type": "string",
"description": "Startup options sent to the server (the libpq options parameter), such as endpoint=<endpoint-id> for a Neon pooled or private connection, or -c search_path=myschema"
},
"sslmode": {
"enum": [
"disable",
"allow",
"prefer",
"require",
"verify-ca",
"verify-full"
],
"type": "string",
"description": "Most cloud databases (Heroku, AWS, Supabase, etc.) require SSL. Self-hosted databases typically don't."
},
"password": {
"type": "string",
"description": "The postgres users password"
},
"use_iam_auth": {
"type": "boolean",
"default": false,
"description": "Use IAM authentication (AWS RDS/Aurora). When enabled, the password field is ignored and a short-lived IAM token is generated instead."
},
"accept_invalid_certs": {
"type": "boolean",
"default": false,
"showExpr": "fields.sslmode == 'verify-ca' || fields.sslmode == 'verify-full'",
"description": "Accept any certificate presented by the server, which disables TLS certificate verification and is not recommended. Only applies to verify-ca/verify-full."
},
"root_certificate_pem": {
"type": "string",
"default": "",
"description": "The root certificate in pe format"
}
}
}
},
{
"name": "s3",
"description": "Connection settings for an Amazon S3 (AWS) bucket: endpoint, region, bucket name and access keys.",
"schema": {
"type": "object",
"order": [
"endPoint",
"region",
"pathStyle",
"bucket",
"accessKey",
"secretKey",
"port",
"useSSL"
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"bucket"
],
"properties": {
"port": {
"type": "number",
"description": "Deprecated: pass in a complete URL to `endPoint` instead, including a port number if needed"
},
"bucket": {
"type": "string",
"default": "",
"description": ""
},
"region": {
"type": "string",
"default": "",
"description": "AWS region (e.g. us-east-1). Used to auto-generate the S3 endpoint URL when endPoint is not specified"
},
"useSSL": {
"type": "boolean",
"default": true,
"description": "Deprecated: pass in a complete URL to `endPoint` instead, including 'https://' or 'http://'"
},
"endPoint": {
"type": "string",
"default": "",
"description": "The full URL of the S3 endpoint (e.g. https://s3.us-east-1.amazonaws.com)"
},
"accessKey": {
"type": "string",
"default": "",
"description": ""
},
"pathStyle": {
"type": "boolean",
"default": true,
"description": "<host>/<bucket>/<path> instead of <bucket>.<host>/<path>"
},
"secretKey": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "salesforce",
"description": "Salesforce OAuth Authorization Code credential. The token is populated by Windmill's OAuth flow; instance_url pins every REST call to the org's data host, api_version selects the REST API version.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token",
"instance_url"
],
"properties": {
"token": {
"type": "string",
"description": "OAuth access token. Populated by Windmill's OAuth flow."
},
"api_version": {
"type": "string",
"description": "Salesforce REST API version path segment, e.g. v60.0. Optional \u2014 scripts default to v60.0 when left blank."
},
"instance_url": {
"type": "string",
"description": "Org data host returned in the OAuth token response, e.g. https://acme.my.salesforce.com (production) or https://acme--sandbox.sandbox.my.salesforce.com (sandbox). Every REST call is made against this host, not login.salesforce.com."
}
}
}
},
{
"name": "sendgrid",
"description": "Twilio SendGrid API key for the SendGrid v3 API: transactional email, contacts, marketing lists and bounces.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token"
],
"properties": {
"token": {
"type": "string",
"default": "",
"description": "API token"
}
}
}
},
{
"name": "shopify",
"description": "Credentials for the Shopify Admin API using a store name and access token.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"store_name",
"token"
],
"properties": {
"token": {
"type": "string",
"default": "",
"description": ""
},
"store_name": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "slack",
"description": "Slack bot or user OAuth token authorizing the Slack Web API (messages, channels, users and files).",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [],
"properties": {
"token": {
"type": "string",
"description": "The slack token"
}
}
}
},
{
"name": "smtp",
"description": "Connection settings for an SMTP mail server used to send email.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"host"
],
"properties": {
"host": {
"type": "string",
"default": "mail.smtpbucket.com",
"description": "SMTP host address"
},
"port": {
"type": "integer",
"default": 8025,
"description": "port number on which to connect"
},
"user": {
"type": "string",
"description": ""
},
"password": {
"type": "string",
"description": ""
}
}
}
},
{
"name": "stripe",
"description": "Stripe secret API key for the Stripe payments API.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [],
"properties": {
"token": {
"type": "string",
"description": ""
}
}
}
},
{
"name": "supabase",
"description": "Supabase project URL and API key for the Supabase REST, auth and storage APIs.\n\nRetrieve both values in \"Project Settings -> API\".",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [],
"properties": {
"key": {
"type": "string",
"default": "",
"description": "The unique Supabase Key which is supplied when you create a new project in your project dashboard."
},
"url": {
"type": "string",
"default": "",
"description": "The unique Supabase URL which is supplied when you create a new project in your project dashboard."
}
}
}
},
{
"name": "twilio",
"description": "Credentials for the Twilio messaging and voice API using an Account SID and auth token.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"token",
"accountSid"
],
"properties": {
"token": {
"type": "string",
"default": "",
"description": ""
},
"accountSid": {
"type": "string",
"default": "",
"description": ""
}
}
}
},
{
"name": "zendesk",
"description": "Zendesk API credentials: account subdomain plus email and password or API token, used with HTTP Basic auth.",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"username",
"subdomain",
"password"
],
"properties": {
"password": {
"type": "string",
"default": "",
"description": "password or api token"
},
"username": {
"type": "string",
"default": "",
"description": "email or \"{email}/token\" if using an api token"
},
"subdomain": {
"type": "string",
"default": "",
"description": ""
}
}
}
}
]
@@ -0,0 +1,57 @@
{
"user": {
"username": "op",
"is_admin": false,
"folders": [],
"folders_read": ["ops"]
},
"workspace": {
"scripts": [
{
"path": "f/ops/list_open_orders",
"summary": "List open orders",
"description": "Returns every order that has not shipped yet, newest first.",
"language": "bun",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {},
"required": []
},
"content": "export async function main() {\n return [\n { id: 'ord_1042', customer_email: 'ana@example.com', total: 129.9, status: 'open' },\n { id: 'ord_1041', customer_email: 'li@example.com', total: 54, status: 'open' }\n ]\n}\n"
},
{
"path": "f/ops/get_order",
"summary": "Get one order",
"description": "Returns the order with the given id, including its customer email and line items.",
"language": "bun",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"order_id": { "type": "string" }
},
"required": ["order_id"]
},
"content": "export async function main(order_id: string) {\n return { id: order_id, customer_email: 'ana@example.com', total: 129.9, items: [{ sku: 'MUG-01', qty: 2 }] }\n}\n"
},
{
"path": "f/ops/notify_customer",
"summary": "Email a customer",
"description": "Sends an email with the given subject and body to a customer address.",
"language": "bun",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"email": { "type": "string" },
"subject": { "type": "string" },
"body": { "type": "string" }
},
"required": ["email", "subject", "body"]
},
"content": "export async function main(email: string, subject: string, body: string) {\n return { sent: true, email }\n}\n"
}
]
}
}
@@ -0,0 +1,5 @@
{
"workspace": {
"resourceTypes": [{ "name": "ai_skill" }, { "name": "ai_instruction" }]
}
}
@@ -0,0 +1,18 @@
{
"workspace": {
"resources": [
{
"path": "f/evals/global/support_triage",
"resource_type": "ai_agent",
"description": "Triages incoming support tickets",
"value": {
"provider": { "kind": "anthropic", "model": "claude-sonnet-5", "resource": "" },
"output_type": "text",
"system_prompt": "Classify each ticket as billing, bug or question, then reply with the label only.",
"memory": { "kind": "off" },
"tools": []
}
}
]
}
}
+1
View File
@@ -53,6 +53,7 @@ export function createGlobalModeRunner(
previewTabs: initial?.previewTabs,
sessionChat: context.evalCase?.runtime?.sessionChat,
planMode: context.evalCase?.runtime?.planMode,
profile: context.evalCase?.runtime?.profile,
maxIterations: context.evalCase?.runtime?.maxTurns,
userAnswers: context.evalCase?.runtime?.userAnswers,
provider: modelConfig.provider,
+11 -1
View File
@@ -24,4 +24,14 @@ rustflags = [
]
[net]
git-fetch-with-cli = true
git-fetch-with-cli = true
[env]
# `#[sqlx::test]` clones each test database from a template migrated once, instead of running
# every migration per test. The `_sqlx_tmpl_*` databases it leaves on the server are reused.
SQLX_TEST_TEMPLATE = "true"
# All `#[sqlx::test]` pools of a test binary share this many connections, and each keeps the
# ones it took until it ends: below 5 per test thread, concurrent tests can split them all and
# wait on each other until their acquire times out. 50 covers CI's `--test-threads=10`; a run
# with more threads over a binary of more than 10 tests needs 5 per thread.
SQLX_TEST_MAX_CONNECTIONS = "50"
+1 -1
View File
@@ -10,4 +10,4 @@ windmill-api/openapi-*.*
*ee.rs
generate_mcp_endpoints_tools/venv
bacon.toml
libwindmill_duckdb_ffi_internal.so
windmill_duckdb_runner
@@ -1,14 +0,0 @@
{
"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\"); }', 'bun', 'script', 'test-user', '{}', '', '', E'{}\\n//bun.lock\\n<empty>', true)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": []
},
"hash": "009fd85c1aa55ea36454eafffbf62505461eb1cc8b9af85a2e2ab6e7dbe950c6"
}
@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE native_trigger SET connection_path = $1 WHERE workspace_id = $2 AND connection_path = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "00ac2ddf7c3f6b2c4e9a47c6a237ef9e7e6b6b793147b1752ff07e800415bfa9"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM variable WHERE workspace_id = $1 AND account = ANY($2) RETURNING path",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Int4Array"
]
},
"nullable": [
false
]
},
"hash": "00b32f6cd59154d9e529c8577072f000ae6cf37928508a82f51d3b3a325f3d1a"
}
@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM variable WHERE workspace_id = $1 AND path = $2 AND account = $3)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Int4"
]
},
"nullable": [
null
]
},
"hash": "086866581c8f253a611d85cc9464e63767da94af0fcb6d660cd6fb0479b9a99d"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT parent_job FROM v2_job WHERE id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "parent_job",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
true
]
},
"hash": "0997b46bae6e2374b568e8367898d6fc79c331431326250c1a59674054ceaabd"
}
@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE account SET refresh_error = $1 WHERE workspace_id = $2 AND id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Int4"
]
},
"nullable": []
},
"hash": "09e2a19435068f9e9bfd5bcb44b4e283c71729f81550f6f7156ce4970345cc07"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT slack_oauth_client_secret FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "slack_oauth_client_secret",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "0d04ec377bef28416a5721a43d2c687681b5d36ff1918ed9e495c5596f2ba9f2"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) FROM workspace_settings WHERE ($1::text IS NULL OR workspace_id = $1) AND (\n jsonb_typeof(auto_invite) = 'object' AND COALESCE(auto_invite->>'role',\n CASE WHEN (auto_invite->>'operator')::boolean THEN 'operator' ELSE 'developer' END) = $2\n OR EXISTS (SELECT 1 FROM jsonb_each_text(\n CASE WHEN jsonb_typeof(auto_invite->'instance_groups_roles') = 'object'\n THEN auto_invite->'instance_groups_roles' ELSE '{}'::jsonb END) g\n WHERE g.value = $2))",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "0d419f09cce9f33fecfabc62b17e8848ac8184d61d3f7cde126a56080aef643c"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) FROM workspace_settings WHERE ($1::text IS NOT NULL AND workspace_id = $1\n OR $1::text IS NULL AND NOT COALESCE(role_overrides ? $2, false)) AND (\n auto_invite->>'role' = $2\n OR EXISTS (SELECT 1 FROM jsonb_each_text(\n CASE WHEN jsonb_typeof(auto_invite->'instance_groups_roles') = 'object'\n THEN auto_invite->'instance_groups_roles' ELSE '{}'::jsonb END) g\n WHERE g.value = $2))",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "0d69f5f6d2e3a4b7b801c6feea92a383e841fa7c3f1c5e2849481c6057ab1e84"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET role_overrides =\n (SELECT role_overrides FROM workspace_settings WHERE workspace_id = $2)\n WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "0d73210f3ce58d0dd8fd850c1df8d16414daad90ad8b0ea35a769d78626039aa"
}
@@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "SELECT config FROM config WHERE name LIKE 'worker\\_\\_%'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "config",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": []
},
"nullable": [
true
]
},
"hash": "0fb0fea54a1580d4b7ffd37ca43e169f51dbbdc3584d3522f25e97e180e307fd"
}
@@ -1,15 +0,0 @@
{
"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, 'bun', 'script', 'test-user', '{}', 'Simple test script', 'A simple test script', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Text"
]
},
"nullable": []
},
"hash": "1043947475822c27f73b5357e6ec0d527d999f2865ff5de75186b49004a3565e"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT role_overrides FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "role_overrides",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "104b8d267f8f904122973d20629473ac77fad069e7c805cf3c2352bd72f8ffb6"
}
@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "WITH a AS (DELETE FROM slack_answered_message WHERE created_at < now() - interval '1 day')\n DELETE FROM slack_thread_agent WHERE created_at < now() - interval '90 days'",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "127d1d6a9cec24f34ff91718cf62befb986da3c1081b08a3a650435c53a88df5"
}
@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT error_handler->>'path' FROM workspace_settings WHERE workspace_id = 'test-workspace'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Text"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "12c3101e02f197ad731b66f539fe677ad25520fcc9c5a2378a293122956bed4c"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO job_resolution (job_id, workspace_id, resolved_by, note, automatic)\n SELECT c.id, c.workspace_id, $4, COALESCE($5, $7), false\n FROM v2_job_completed c\n JOIN v2_job j ON j.id = c.id\n WHERE c.id = ANY($1)\n AND c.workspace_id = $2\n AND ($3::TEXT[] IS NULL OR j.tag = ANY($3))\n AND c.status = 'failure'\n -- Resolution is a top-level triage state: a step resolved on its own\n -- would render orange inside a flow whose status is still red.\n AND j.flow_step_id IS NULL\n -- A supersession claim has to be proven, not trusted: a later success of the\n -- same identified runnable, itself visible to the caller. An unproven claim\n -- resolves nothing, so the caller learns it was rejected instead of having\n -- the fiction recorded as provenance.\n AND ($6::UUID IS NULL OR EXISTS (\n SELECT 1 FROM v2_job_completed sc\n JOIN v2_job sj ON sj.id = sc.id\n WHERE sc.id = $6\n AND sc.workspace_id = $2\n -- Tag scope is a read restriction enforced outside RLS, so it has\n -- to bind the evidence as well: otherwise the result reveals\n -- whether an out-of-scope run succeeded.\n AND ($3::TEXT[] IS NULL OR sj.tag = ANY($3))\n AND sc.status = 'success'\n AND sc.completed_at >= c.completed_at\n AND (j.runnable_id IS NOT NULL OR j.runnable_path IS NOT NULL)\n AND sj.runnable_id IS NOT DISTINCT FROM j.runnable_id\n AND sj.runnable_path IS NOT DISTINCT FROM j.runnable_path\n ))\n ON CONFLICT (job_id) DO UPDATE SET\n resolved_at = now(),\n -- Both COALESCEd: `resolution_attribution` returns NULLs outside EE and once the\n -- licence lapses, and bulk selections routinely include already-resolved rows,\n -- so overwriting would erase metadata recorded while it was valid. Clear either\n -- by unresolving first.\n resolved_by = COALESCE($4, job_resolution.resolved_by),\n -- A person's explanation replaces what was there; machine provenance only fills\n -- a blank, so re-running an already-explained failure never erases their words.\n note = COALESCE($5, job_resolution.note, $7),\n -- A human taking over an automatic resolution makes it no longer automatic.\n automatic = false\n RETURNING job_id",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "job_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"UuidArray",
"Text",
"TextArray",
"Varchar",
"Text",
"Uuid",
"Text"
]
},
"nullable": [
false
]
},
"hash": "13d8e65ffd3ef6bcfb963525fc3ec0859463b1c153950f894a830a4b5ec33fcc"
}
@@ -0,0 +1,29 @@
{
"db_name": "PostgreSQL",
"query": "SELECT resource_type, value AS \"value: sqlx::types::Json<Box<RawValue>>\"\n FROM resource WHERE workspace_id = $1 AND path = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "resource_type",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "value: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false,
true
]
},
"hash": "15f53f40a49b538ca0d4456f69b8d801e8c121f1e0cd904a77ce55bcf9bc5053"
}
@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET error_handler = '{\"path\": \"script/f/test/error_handler\", \"extra_args\": {\"notify\": true}, \"muted_on_cancel\": true, \"muted_on_user_path\": false}'::jsonb\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "18d1a6ac94f2c87d5ea8c48a228f061135be4065dca33fbc429d8b0186c5ccb3"
}
@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM variable v\n JOIN account a ON a.workspace_id = v.workspace_id AND a.id = v.account\n WHERE v.workspace_id = $1 AND v.path = $2 AND a.client = $3\n AND a.is_workspace_integration = true)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "1966a1c4776492599de66d6d189d399c37957f832485156f703f59bd39cdc2bb"
}
@@ -0,0 +1,36 @@
{
"db_name": "PostgreSQL",
"query": "SELECT c.workspace_id, c.agent_path, c.is_default FROM slack_agent_channel c\n JOIN workspace_settings ws ON ws.workspace_id = c.workspace_id\n AND ws.slack_team_id = c.slack_team_id\n WHERE c.slack_team_id = $1 AND c.channel_id = $2\n AND ws.workspace_id = ANY($3)\n ORDER BY c.agent_path",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "agent_path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "is_default",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"TextArray"
]
},
"nullable": [
false,
false,
false
]
},
"hash": "19b9173fad68c2bde71a70d1ce947c20773dd4c44f19b47e73e24438f5c78ab3"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT format('rawscript/%s', code_sha256) as \"path!: String\"\n FROM app_script WHERE id = $1 LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path!: String",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": [
null
]
},
"hash": "1bae415f9440cc1334f24ce3009242cf3a6287e7b4548c7f01ad888230c27013"
}
@@ -0,0 +1,17 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE usr SET workspace_role = $1, operator = $2 WHERE username = $3 AND workspace_id = $4",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Bool",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "1c97bf1af258b43fb8dedd3417d0e086996d5fcc3c270e5c1cc9824c30d82726"
}
@@ -0,0 +1,47 @@
{
"db_name": "PostgreSQL",
"query": "SELECT v.path, r.created_by AS \"owner?\", true AS \"workspace!\"\n FROM workspace_integrations wi\n JOIN variable v ON v.workspace_id = wi.workspace_id AND v.path = wi.resource_path\n JOIN account a ON a.workspace_id = v.workspace_id AND a.id = v.account\n LEFT JOIN resource r ON r.workspace_id = v.workspace_id AND r.path = v.path\n WHERE wi.workspace_id = $1 AND wi.service_name = $2\n AND a.client = $3 AND a.is_workspace_integration = true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "owner?",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "workspace!",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
{
"Custom": {
"name": "native_trigger_service",
"kind": {
"Enum": [
"nextcloud",
"google",
"github"
]
}
}
},
"Text"
]
},
"nullable": [
false,
true,
null
]
},
"hash": "1e0751bef92b5628b8d54448da171d56af87b5b263f8484c886e7f51e0198409"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM v2_job WHERE workspace_id = $1 AND id = ANY($2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text",
"UuidArray"
]
},
"nullable": [
false
]
},
"hash": "1f21ef9dfa502b425b85d2acb6b3af1694ee60157089ce0c823d6c1351b8ed2c"
}
@@ -0,0 +1,52 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n workspace_invite.workspace_id,\n workspace_invite.email,\n workspace_invite.is_admin,\n workspace_invite.operator,\n COALESCE(workspace_invite.workspace_role, CASE WHEN workspace_invite.operator THEN 'operator' ELSE 'developer' END) AS \"role!\",\n workspace.parent_workspace_id\n FROM workspace_invite JOIN workspace ON workspace_invite.workspace_id = workspace.id\n WHERE workspace_id = $1\n ORDER BY workspace_invite.email",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "is_admin",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "operator",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "role!",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "parent_workspace_id",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
null,
true
]
},
"hash": "1fbb8493d20eacea2ac78c4473a85f96bd91de548185238f9fd66ac2b4a1e0a0"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) FROM usr t WHERE ($1::text IS NULL OR t.workspace_id = $1) AND\n COALESCE(t.workspace_role, CASE WHEN t.operator THEN 'operator' ELSE 'developer' END) = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "205f2fb7629382294e53869aa5d2f722f631882929086c453b5825ab4b9c1cb8"
}
@@ -17,7 +17,8 @@
"script",
"flow",
"raw_app",
"asset"
"asset",
"agent"
]
}
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT expires_at FROM account WHERE workspace_id = $1 AND id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "expires_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text",
"Int4"
]
},
"nullable": [
false
]
},
"hash": "23b2a39e37e93ca9367e954eba94b1a6f432edb76320c50e0d07088937c17a01"
}
@@ -0,0 +1,25 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (\n SELECT 1 FROM v2_job_queue q\n CROSS JOIN LATERAL (\n SELECT trigger_kind, trigger, runnable_path, parent_job\n FROM v2_job WHERE id = q.id OFFSET 0\n ) j\n WHERE q.workspace_id = $1 AND q.scheduled_for = $3\n AND j.trigger_kind = 'schedule' AND j.trigger = $2 AND j.runnable_path = $4\n AND j.parent_job IS NULL\n )",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Timestamptz",
"Text"
]
},
"nullable": [
null
]
},
"hash": "250ac2b81a8d9a6900d8b54322fe21ef62eddd307717b24aa4fc03c0297e8f59"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT user_email FROM mcp_oauth_refresh_token WHERE refresh_token = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "user_email",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "257b3bc19f738fe36e3c995c5ba239e1f2855cf39f9fe7a92d722732653fd98b"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO usr (workspace_id, username, email, is_admin, created_at, operator, disabled, role, workspace_role) SELECT $1, username, email, is_admin, created_at, operator, disabled, role, workspace_role FROM usr WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": []
},
"hash": "25b09b592b6917214fd7cfabfece48d266b2d5dc11236c2bb41b1a927ede63d8"
}
@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT (error_handler->>'muted_on_cancel')::boolean FROM workspace_settings WHERE workspace_id = 'test-workspace'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "bool",
"type_info": "Bool"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "25bf3956b4365a4d4f96368bcc6e33817ae284ab26c195eee53d988d74263e86"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO workspace_integrations (\n workspace_id,\n service_name,\n oauth_data,\n resource_path,\n created_by,\n created_at,\n updated_at\n ) VALUES (\n $1, $2, $3, $4, $5, now(), now()\n )\n ON CONFLICT (workspace_id, service_name)\n DO UPDATE SET\n oauth_data = $3,\n resource_path = $4,\n updated_at = now()\n ",
"query": "\n INSERT INTO workspace_integrations (\n workspace_id,\n service_name,\n oauth_data,\n created_by,\n created_at,\n updated_at\n ) VALUES (\n $1, $2, $3, $4, now(), now()\n )\n ON CONFLICT (workspace_id, service_name)\n DO UPDATE SET\n oauth_data = $3,\n updated_at = now()\n ",
"describe": {
"columns": [],
"parameters": {
@@ -19,11 +19,10 @@
}
},
"Jsonb",
"Text",
"Varchar"
]
},
"nullable": []
},
"hash": "a588f4caa014008b50eccd09122b09f8a098e58791893bacaaf2ff67a30c031c"
"hash": "2602402bedcdbc45cdc0d64a76ce075c6ae51404037b0a7d4d33faf6a7d6a6d8"
}
@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT (error_handler->>'muted_on_user_path')::boolean FROM workspace_settings WHERE workspace_id = 'test-workspace'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "bool",
"type_info": "Bool"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "28b8264a427e8c19be823d2b8e40736a7b7675780672b503d91737cd0c617657"
}
@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET success_handler = '{\"path\": \"script/f/test/success_handler\", \"extra_args\": {\"key\": \"value\"}}'::jsonb\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "28f3dfb70aed943ad3d64da608168c027c645afb73dfc2360245b68ba593cab4"
}
@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM slack_agent_channel\n WHERE workspace_id = $1 AND agent_path = $2 AND channel_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "2b39b2273d05ebe6e99be5b9051c153a170f5387831cd27e8cdbe5d052f839d0"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT value FROM variable WHERE workspace_id = $1 AND path = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false
]
},
"hash": "2c0ab7571e1a7c4290315bc3efccb4db9e0c9aee05596a594f81975a0cdb74d1"
}
@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET success_handler = NULL\n WHERE workspace_id = 'test-workspace'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "2c2ed5c91a4893966e94305df8b9f8ac904c8d0781a83fdea66c918320fb5601"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT config FROM config WHERE name = $1 FOR UPDATE",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "config",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "2d22fe27288580cb727e43b2abe3be2e6e6e3b03e61ce8f2879627115224c8cf"
}
@@ -0,0 +1,94 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace.id, workspace.name, usr.username, workspace_settings.color, workspace.parent_workspace_id,\n workspace.is_dev_workspace, workspace.dev_workspace_label,\n workspace.owner AS \"created_by?\",\n usr.is_admin, usr.operator, usr.workspace_role,\n usr.disabled, usr.is_service_account\n FROM workspace\n JOIN usr ON usr.workspace_id = workspace.id\n JOIN workspace_settings ON workspace_settings.workspace_id = workspace.id\n WHERE usr.email = $1 AND workspace.deleted = false",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "username",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "color",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "parent_workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "is_dev_workspace",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "dev_workspace_label",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "created_by?",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "is_admin",
"type_info": "Bool"
},
{
"ordinal": 9,
"name": "operator",
"type_info": "Bool"
},
{
"ordinal": 10,
"name": "workspace_role",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "disabled",
"type_info": "Bool"
},
{
"ordinal": 12,
"name": "is_service_account",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
true,
true,
false,
true,
false,
false,
false,
true,
false,
false
]
},
"hash": "2e8a53e73c3b5c2662efd0e2876f168c2f79258fb900199e8575973d5b3d32bb"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n oauth_data as \"oauth_data: sqlx::types::Json<WorkspaceOAuthConfig>\",\n service_name as \"service_name!: ServiceName\",\n resource_path\n FROM\n workspace_integrations\n WHERE\n workspace_id = $1\n ",
"query": "\n SELECT\n oauth_data as \"oauth_data: sqlx::types::Json<WorkspaceOAuthConfig>\",\n service_name as \"service_name!: ServiceName\"\n FROM\n workspace_integrations\n WHERE\n workspace_id = $1\n ",
"describe": {
"columns": [
{
@@ -23,11 +23,6 @@
}
}
}
},
{
"ordinal": 2,
"name": "resource_path",
"type_info": "Text"
}
],
"parameters": {
@@ -37,9 +32,8 @@
},
"nullable": [
true,
false,
true
false
]
},
"hash": "0010ef26da16facd1c2c832601ac687c4c27de46a90f45496b8446af1a9d0578"
"hash": "30b1021260b5ec83a04be1f3dbea08cc81ee85cf98696d9e29a34557587eaf86"
}
@@ -0,0 +1,30 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id, agent_path FROM slack_thread_agent\n WHERE slack_team_id = $1 AND channel_id = $2 AND thread_ts = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "agent_path",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": [
false,
false
]
},
"hash": "3164d5bc31dc128e59f9108c63ab8c11f7fe26ef16c5e6bfbd13bd081fc00ba3"
}
@@ -1,12 +0,0 @@
{
"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\"; }', 'bun', 'script', 'test-user', '{}', '', '', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "344c08104d62d9bcd3f9117abb574e73a6fb364e4ab3e3916958c2e493673b1d"
}
@@ -0,0 +1,34 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id, slack_oauth_client_id IS NOT NULL AS \"own_app!\",\n slack_signing_secret\n FROM workspace_settings WHERE slack_team_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "own_app!",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "slack_signing_secret",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
null,
true
]
},
"hash": "35238a186adbe0583010dbe8e298a907f16d9e88f648705f2372dfe7c0523879"
}
@@ -53,7 +53,7 @@
false,
false,
false,
false,
true,
false,
false,
true,
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO workspace_settings (workspace_id, slack_team_id, slack_name, slack_command_script, slack_email, customer_id, plan, webhook, ai_config, large_file_storage, git_sync, default_app, default_scripts, deploy_ui, mute_critical_alerts, color, operator_settings, role_overrides, teams_command_script, teams_team_id, teams_team_name, git_app_installations, git_credentials, ducklake, dbt_warehouses, slack_oauth_client_id, slack_oauth_client_secret, datatable, teams_team_guid, auto_invite, error_handler, success_handler, public_app_execution_limit_per_minute, error_handler_fallback_to_instance_alerts, guest_access_enabled, guest_jwt_public_key, guest_jwt_jwks_url, add_admins_and_developers_to_forks, remote_deploy_target, remote_deploy_target_changed_at) SELECT $1, slack_team_id, slack_name, slack_command_script, slack_email, customer_id, plan, webhook, ai_config, large_file_storage, git_sync, default_app, default_scripts, deploy_ui, mute_critical_alerts, color, operator_settings, role_overrides, teams_command_script, teams_team_id, teams_team_name, git_app_installations, git_credentials, ducklake, dbt_warehouses, slack_oauth_client_id, slack_oauth_client_secret, datatable, teams_team_guid, auto_invite, error_handler, success_handler, public_app_execution_limit_per_minute, error_handler_fallback_to_instance_alerts, guest_access_enabled, guest_jwt_public_key, guest_jwt_jwks_url, add_admins_and_developers_to_forks, remote_deploy_target, remote_deploy_target_changed_at FROM workspace_settings WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": []
},
"hash": "37275b26b092ed3ae1a11b78da5227a40a49d9435107e71033740f11cc8d2417"
}
@@ -1,42 +1,62 @@
{
"db_name": "PostgreSQL",
"query": "SELECT client, refresh_token, grant_type, cc_client_id, cc_client_secret, cc_token_url, scopes FROM account WHERE workspace_id = $1 AND id = $2",
"query": "SELECT mcp_server_url, is_workspace_integration, client, refresh_token, grant_type,\n cc_client_id, cc_client_secret, cc_token_url, scopes, expires_at,\n now() > expires_at AS \"expired!\"\n FROM account WHERE workspace_id = $1 AND id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "mcp_server_url",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "is_workspace_integration",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "client",
"type_info": "Varchar"
},
{
"ordinal": 1,
"ordinal": 3,
"name": "refresh_token",
"type_info": "Varchar"
},
{
"ordinal": 2,
"ordinal": 4,
"name": "grant_type",
"type_info": "Varchar"
},
{
"ordinal": 3,
"ordinal": 5,
"name": "cc_client_id",
"type_info": "Varchar"
},
{
"ordinal": 4,
"ordinal": 6,
"name": "cc_client_secret",
"type_info": "Varchar"
},
{
"ordinal": 5,
"ordinal": 7,
"name": "cc_token_url",
"type_info": "Varchar"
},
{
"ordinal": 6,
"ordinal": 8,
"name": "scopes",
"type_info": "TextArray"
},
{
"ordinal": 9,
"name": "expires_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "expired!",
"type_info": "Bool"
}
],
"parameters": {
@@ -46,14 +66,18 @@
]
},
"nullable": [
true,
false,
false,
false,
false,
true,
true,
true,
true
true,
false,
null
]
},
"hash": "63c48fde8c0c0fff9abffc3be27e9948556b636b70b818cc31c2d50921a27366"
"hash": "3829559733fa087201f935ee10a5cecf2cec4f1646015ed7cf476efaba67707f"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM resource WHERE workspace_id = $1 AND path = $2 AND resource_type = 'ai_agent')",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "392b256dd7f36ec3736fc2f9d564dc198a6b69d62fb244691af0601e542b6ac3"
}
@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (\n SELECT 1 FROM v2_job j JOIN v2_job_queue USING (id)\n WHERE j.workspace_id = $1 AND trigger_kind = 'schedule' AND trigger = $2 AND runnable_path = $4\n AND parent_job IS NULL\n AND scheduled_for = $3\n )",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Timestamptz",
"Text"
]
},
"nullable": [
null
]
},
"hash": "3a47d8ec0f4ba1644951f0c88504c9f769ffe5004871a049e4232e0092532062"
}
@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO group_ (workspace_id, name, summary, extra_perms)\n VALUES ('test-workspace', 'success_handler', 'The group the success handler acts on behalf of', '{\"u/test-user\": true}')\n ON CONFLICT DO NOTHING\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "3a71ab02239d8dd4e2f440a35155459a7d5091c125a0998e79d89f8c560a3fd3"
}
@@ -0,0 +1,19 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO usr (workspace_id, username, email, is_admin, operator, added_via, workspace_role) VALUES ($1, $2, $3, false, $4, $5, $6) ON CONFLICT DO NOTHING",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Varchar",
"Bool",
"Jsonb",
"Varchar"
]
},
"nullable": []
},
"hash": "3b01c43a828ec5d61ed92a27bdb16b526db8e60887d6279b0e66197da686fbf8"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO app_version\n (app_id, value, created_by, raw_app)\n SELECT app_id, value, created_by, raw_app\n FROM app_version WHERE id = $1\n RETURNING id",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": [
false
]
},
"hash": "3d38720e807b379645d8f3ab61c6a968143d42c3014152608f7d1b252cd8085c"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n workspace_id,\n service_name AS \"service_name!: ServiceName\",\n oauth_data,\n resource_path,\n created_at,\n updated_at,\n created_by\n FROM\n workspace_integrations\n WHERE\n workspace_id = $1\n AND service_name = $2\n ",
"query": "\n SELECT\n workspace_id,\n service_name AS \"service_name!: ServiceName\",\n oauth_data,\n created_at,\n updated_at,\n created_by\n FROM\n workspace_integrations\n WHERE\n workspace_id = $1\n AND service_name = $2\n ",
"describe": {
"columns": [
{
@@ -31,21 +31,16 @@
},
{
"ordinal": 3,
"name": "resource_path",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 5,
"ordinal": 4,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"ordinal": 5,
"name": "created_by",
"type_info": "Varchar"
}
@@ -71,11 +66,10 @@
false,
false,
true,
true,
false,
false,
false
]
},
"hash": "7443ba1f922e190bb9a0ca313847f8d27c35a6ee3aff20157d6285e73aa923ef"
"hash": "3e5bdc2e071fc2f1e3c7971736272f20bb5a0aa921a614bd02898d3f162660c2"
}
@@ -0,0 +1,40 @@
{
"db_name": "PostgreSQL",
"query": "SELECT c.channel_id, c.channel_name, c.agent_path, c.is_default\n FROM slack_agent_channel c\n JOIN resource r ON r.workspace_id = c.workspace_id AND r.path = c.agent_path\n WHERE c.workspace_id = $1 ORDER BY c.channel_name, c.agent_path",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "channel_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "channel_name",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "agent_path",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "is_default",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "3e9f4f055c26a36ff60bf40f0c93a6ad1935e18cd09e08c3bd29d2ad7e2ae5dd"
}
@@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (SELECT 1 FROM workspace_diff\n WHERE fork_workspace_id = 'wm-fork-renamed' AND kind = 'script'\n AND path = 'u/admin/inline' AND fork_last_event_kind = 'write')",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "420707b82c44c7a30719c4419bdd3b4382f863d7c84f18af64e1d3930890a210"
}
@@ -1,14 +0,0 @@
{
"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, 'bun', 'script', 'test-user', '{}', 'Success handler script', 'Handles successful job completions', E'{}\\n//bun.lock\\n<empty>')\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "42250637493a623850ca76fe5a705fe4acef039f38a5e76da8d09f2f7e755779"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM slack_thread_agent WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "429004f6f71a06a93e8cdd688510ef502c1fc11ee23dec437e0f85f7b1e60a92"
}
@@ -0,0 +1,27 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO app_script (app, hash, lock, code, code_sha256, modules)\n VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (hash) DO UPDATE SET app = EXCLUDED.app -- trivial update to return the id\n RETURNING id",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Int8",
"Bpchar",
"Text",
"Text",
"Bpchar",
"Jsonb"
]
},
"nullable": [
false
]
},
"hash": "4448d2cc6bc73635bb8c252ab9f4efaa33600c3ecd266e8339b9bfb32ae18499"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (SELECT 1 FROM fork_storage_namespace WHERE workspace_id = ANY($1))\n AND EXISTS (SELECT 1 FROM workspace WHERE parent_workspace_id = $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"TextArray",
"Text"
]
},
"nullable": [
null
]
},
"hash": "45b73345f2009122142f3410736b2d57a07e2047a704d9a7d8eab3416ff1d9d5"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM variable WHERE account = $1 AND workspace_id = $2)",
"query": "SELECT EXISTS (SELECT 1 FROM fork_storage_namespace WHERE workspace_id = $1)",
"describe": {
"columns": [
{
@@ -11,7 +11,6 @@
],
"parameters": {
"Left": [
"Int4",
"Text"
]
},
@@ -19,5 +18,5 @@
null
]
},
"hash": "7aa589db3199d7f727cc69e63e1281b7ed329ff0c9d1617747f4ccd6014720cf"
"hash": "4640ac69b297127cd0f5c369fa4a49857237cd57134dbc467b53601c1ec942d2"
}
@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO usr (workspace_id, username, email, is_admin, created_at, operator, disabled, role, is_service_account, added_via, workspace_role)\n SELECT $1, username, email, is_admin, created_at, operator, disabled, role, is_service_account,\n CASE WHEN $3 THEN NULL ELSE added_via END, workspace_role\n FROM usr WHERE workspace_id = $2\n AND (NOT $3 OR (NOT operator AND NOT disabled AND NOT is_service_account))\n ON CONFLICT DO NOTHING",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "464286216add454cb64dba810d964c4b6a41d96df223b6d3d1d1bc972ab10d42"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT external_id, webhook_token_hash FROM native_trigger WHERE workspace_id = $1 AND service_name = $2",
"query": "SELECT external_id, script_path FROM native_trigger\n WHERE workspace_id = $1 AND service_name = $2 AND connection_path = $3",
"describe": {
"columns": [
{
@@ -10,7 +10,7 @@
},
{
"ordinal": 1,
"name": "webhook_token_hash",
"name": "script_path",
"type_info": "Varchar"
}
],
@@ -28,7 +28,8 @@
]
}
}
}
},
"Text"
]
},
"nullable": [
@@ -36,5 +37,5 @@
false
]
},
"hash": "6c75c89fb215c646f54f2036c40a86a4f4ea8880cc5d0b511aa70b6fd50072c5"
"hash": "4c12e63ddcf4e8cfe2227421db8869c4fb77e2fa3b98d6b054995875f3fd5a10"
}
@@ -0,0 +1,19 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO usr\n (workspace_id, email, username, is_admin, operator, workspace_role)\n VALUES ($1, $2, $3, $4, $5, $6)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Varchar",
"Bool",
"Bool",
"Varchar"
]
},
"nullable": []
},
"hash": "4c74a75d99f8d6689470da1d57d3db8bf47f11969a0c026a35a6673574e074d8"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM resource WHERE workspace_id = $1 AND path = ANY($2)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"TextArray"
]
},
"nullable": []
},
"hash": "4d48a34016cc642fe3b3b24220615a59165009048a7c93942ee2ecd78524fb5a"
}
@@ -0,0 +1,29 @@
{
"db_name": "PostgreSQL",
"query": "SELECT result AS \"result: sqlx::types::Json<serde_json::Value>\",\n status = 'success' AS \"success!\"\n FROM v2_job_completed WHERE id = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "result: sqlx::types::Json<serde_json::Value>",
"type_info": "Jsonb"
},
{
"ordinal": 1,
"name": "success!",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
true,
null
]
},
"hash": "4e14b95c57c6f987f020376f76ad4dd0ff0d043b3eff62863c8f8db89ad34a4e"
}

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