Merge branch 'main' into dieri/triggers-queue-mode

This commit is contained in:
dieriba
2025-11-09 11:15:07 +01:00
33 changed files with 237 additions and 130 deletions
+20
View File
@@ -1,5 +1,25 @@
# Changelog
## [1.574.1](https://github.com/windmill-labs/windmill/compare/v1.574.0...v1.574.1) (2025-11-08)
### Bug Fixes
* make get_logs work even for partial flow jobs ([d6421c2](https://github.com/windmill-labs/windmill/commit/d6421c2ea79993ef7815c50cf035d3b3425e271e))
## [1.574.0](https://github.com/windmill-labs/windmill/compare/v1.573.5...v1.574.0) (2025-11-07)
### Features
* env var in flow ([#6852](https://github.com/windmill-labs/windmill/issues/6852)) ([c59183f](https://github.com/windmill-labs/windmill/commit/c59183f5c39f853d9679c00dd5aa755ef171d735))
### Bug Fixes
* **cli:** add automatic handler of .node files for codebase bundler ([62ffe9f](https://github.com/windmill-labs/windmill/commit/62ffe9ffce6d070c81794e8483ab83b431aee9ea))
* teams selector svelte5 ([#7087](https://github.com/windmill-labs/windmill/issues/7087)) ([6045f0c](https://github.com/windmill-labs/windmill/commit/6045f0c40654a88e93be688bcdfab874cfc0b267))
## [1.573.5](https://github.com/windmill-labs/windmill/compare/v1.573.4...v1.573.5) (2025-11-07)
@@ -15,7 +15,7 @@
]
},
"nullable": [
true
null
]
},
"hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55"
@@ -1,11 +1,11 @@
{
"db_name": "PostgreSQL",
"query": "SELECT j.created_by AS \"created_by!\", CONCAT(coalesce(job_logs.logs, '')) as logs, job_logs.log_offset, job_logs.log_file_index\n FROM v2_job j\n LEFT JOIN job_logs ON job_logs.job_id = j.id\n WHERE j.id = $1 AND j.workspace_id = $2 AND ($3::text[] IS NULL OR j.tag = ANY($3))",
"query": "SELECT j.created_by AS \"created_by\", coalesce(job_logs.logs, '') as logs, COALESCE(job_logs.log_offset, 0) as log_offset, job_logs.log_file_index\n FROM v2_job j\n LEFT JOIN job_logs ON job_logs.job_id = j.id\n WHERE j.id = $1 AND j.workspace_id = $2 AND ($3::text[] IS NULL OR j.tag = ANY($3))",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "created_by!",
"name": "created_by",
"type_info": "Varchar"
},
{
@@ -34,9 +34,9 @@
"nullable": [
false,
null,
false,
null,
true
]
},
"hash": "35061719d01929a7146c80de4b637abdad3198d3340ec7c04ed671baff0a4d0b"
"hash": "5e7cadffbee74b11e224b60322b102b9899b4a97b8e557692c0085a9b472b8a7"
}
+31 -31
View File
@@ -9071,9 +9071,9 @@ dependencies = [
[[package]]
name = "openssl"
version = "0.10.74"
version = "0.10.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654"
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
dependencies = [
"bitflags 2.9.4",
"cfg-if",
@@ -9112,9 +9112,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.110"
version = "0.9.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2"
checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
dependencies = [
"cc",
"libc",
@@ -15137,7 +15137,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windmill"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"aws-sdk-config",
@@ -15197,7 +15197,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"argon2",
@@ -15317,7 +15317,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"base64 0.22.1",
"chrono",
@@ -15332,7 +15332,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"chrono",
"lazy_static",
@@ -15346,7 +15346,7 @@ dependencies = [
[[package]]
name = "windmill-autoscaling"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"axum",
@@ -15365,7 +15365,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -15450,7 +15450,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"regex",
"serde",
@@ -15465,7 +15465,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"bytes",
@@ -15489,7 +15489,7 @@ dependencies = [
[[package]]
name = "windmill-macros"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"itertools 0.14.0",
"lazy_static",
@@ -15501,7 +15501,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -15510,7 +15510,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15522,7 +15522,7 @@ dependencies = [
[[package]]
name = "windmill-parser-csharp"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"serde_json",
@@ -15534,7 +15534,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"gosyn",
@@ -15546,7 +15546,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15558,7 +15558,7 @@ dependencies = [
[[package]]
name = "windmill-parser-java"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"serde_json",
@@ -15570,7 +15570,7 @@ dependencies = [
[[package]]
name = "windmill-parser-nu"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"nu-parser",
@@ -15581,7 +15581,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -15592,7 +15592,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -15604,7 +15604,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -15627,7 +15627,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ruby"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15641,7 +15641,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -15658,7 +15658,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15672,7 +15672,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15690,7 +15690,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"serde",
@@ -15701,7 +15701,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -15735,7 +15735,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"wasm-bindgen",
"wasm-bindgen-test",
@@ -15745,7 +15745,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.573.5"
version = "1.574.1"
dependencies = [
"anyhow",
"async-once-cell",
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.573.5"
version = "1.574.1"
authors.workspace = true
edition.workspace = true
@@ -33,7 +33,7 @@ members = [
exclude = ["./windmill-duckdb-ffi-internal"]
[workspace.package]
version = "1.573.5"
version = "1.574.1"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
+1 -1
View File
@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.573.5
version: 1.574.1
title: Windmill API
contact:
+18 -4
View File
@@ -1468,7 +1468,7 @@ async fn get_job_logs(
.flatten();
let record = sqlx::query!(
"SELECT j.created_by AS \"created_by!\", CONCAT(coalesce(job_logs.logs, '')) as logs, job_logs.log_offset, job_logs.log_file_index
"SELECT j.created_by AS \"created_by\", coalesce(job_logs.logs, '') as logs, COALESCE(job_logs.log_offset, 0) as log_offset, job_logs.log_file_index
FROM v2_job j
LEFT JOIN job_logs ON job_logs.job_id = j.id
WHERE j.id = $1 AND j.workspace_id = $2 AND ($3::text[] IS NULL OR j.tag = ANY($3))",
@@ -1497,11 +1497,21 @@ async fn get_job_logs(
.await?;
#[cfg(all(feature = "enterprise", feature = "parquet"))]
if let Some(r) = get_logs_from_store(record.log_offset, &logs, &record.log_file_index).await
if let Some(r) = get_logs_from_store(
record.log_offset.unwrap_or(0),
&logs,
&record.log_file_index,
)
.await
{
return r.map(content_plain);
}
if let Some(r) = get_logs_from_disk(record.log_offset, &logs, &record.log_file_index).await
if let Some(r) = get_logs_from_disk(
record.log_offset.unwrap_or(0),
&logs,
&record.log_file_index,
)
.await
{
return r.map(content_plain);
}
@@ -4285,7 +4295,11 @@ pub async fn run_script_by_path_inner(
timeout,
None,
// If the job has a parent job, set priority to 2 as it may be ran synchronously and block a current worker until being executed. Flow steps have a priority of 1 so this is higher.
if run_query.parent_job.is_some() || run_query.root_job.is_some() { Some(2) } else { None },
if run_query.parent_job.is_some() || run_query.root_job.is_some() {
Some(2)
} else {
None
},
push_authed.as_ref(),
false,
None,
+37 -32
View File
@@ -192,7 +192,7 @@ fn try_exact_property_access(
let suffix = &expr[access_pattern_pos..];
let maybe_key_name = if suffix.starts_with(DOT_PATTERN) {
let key_name_pos = DOT_PATTERN.len();
Some(&expr[key_name_pos..])
Some(&suffix[key_name_pos..])
} else if suffix.starts_with(START_BRACKET_PATTERN) {
let key_name_pos = START_BRACKET_PATTERN.len();
let suffix = &suffix[key_name_pos..];
@@ -220,36 +220,40 @@ fn try_exact_property_access(
}
async fn handle_full_regex(
captures: regex::Captures<'_>,
expr: &str,
authed_client: &AuthedClient,
by_id: &IdContext,
) -> anyhow::Result<Box<RawValue>> {
let obj_name = captures.get(1).unwrap().as_str();
let obj_key = captures.get(2).unwrap().as_str();
let idx_o = captures.get(3).map(|y| y.as_str());
let rest = captures.get(4).map(|y| y.as_str());
let query = if let Some(idx) = idx_o {
match rest {
Some(rest) => Some(format!("{}{}", idx, rest)),
None => Some(idx.to_string()),
}
} else {
rest.map(|x| x.trim_start_matches('.').to_string())
};
) -> Option<anyhow::Result<Box<RawValue>>> {
if let Some(captures) = RE_FULL.captures(&expr) {
let obj_name = captures.get(1).unwrap().as_str();
let obj_key = captures.get(2).unwrap().as_str();
let idx_o = captures.get(3).map(|y| y.as_str());
let rest = captures.get(4).map(|y| y.as_str());
let query = if let Some(idx) = idx_o {
match rest {
Some(rest) => Some(format!("{}{}", idx, rest)),
None => Some(idx.to_string()),
}
} else {
rest.map(|x| x.trim_start_matches('.').to_string())
};
let result = if obj_name == "results" {
authed_client
.get_result_by_id(&by_id.flow_job.to_string(), obj_key, query)
.await
} else if obj_name == "flow_env" {
authed_client
.get_flow_env_by_flow_job_id(&by_id.flow_job.to_string(), obj_key, query)
.await
} else {
unreachable!();
};
let result = if obj_name == "results" {
authed_client
.get_result_by_id(&by_id.flow_job.to_string(), obj_key, query)
.await
} else if obj_name == "flow_env" {
authed_client
.get_flow_env_by_flow_job_id(&by_id.flow_job.to_string(), obj_key, query)
.await
} else {
unreachable!();
};
return result;
return Some(result);
}
return None;
}
pub async fn eval_timeout(
@@ -299,8 +303,8 @@ pub async fn eval_timeout(
}
if let (Some(by_id), Some(authed_client)) = (by_id, authed_client) {
if let Some(captures) = RE_FULL.captures(&expr) {
return handle_full_regex(captures, authed_client, by_id).await;
if let Some(result) = handle_full_regex(&expr, authed_client, by_id).await {
return result;
}
}
@@ -444,9 +448,10 @@ fn replace_with_await(expr: String, fn_name: &str) -> String {
s
}
lazy_static! {
static ref RE: Regex =
Regex::new(r#"(?m)(?P<r>(?:results|flow_env)(?:\?)?(?:(?:\.[a-zA-Z_0-9]+)|(?:\[\".*?\"\])))"#)
.unwrap();
static ref RE: Regex = Regex::new(
r#"(?m)(?P<r>(?:results|flow_env)(?:\?)?(?:(?:\.[a-zA-Z_0-9]+)|(?:\[\".*?\"\])))"#
)
.unwrap();
static ref RE_FULL: Regex = Regex::new(
r"(?m)^(results|flow_env)(?:\?)?\.([a-zA-Z_0-9]+)(?:\[(\d+)\])?((?:\.[a-zA-Z_0-9]+)+)?$"
)
+1 -1
View File
@@ -2,7 +2,7 @@ import { sleep } from "https://deno.land/x/sleep@v1.2.1/mod.ts";
import * as windmill from "https://deno.land/x/windmill@v1.174.0/mod.ts";
import * as api from "https://deno.land/x/windmill@v1.174.0/windmill-api/index.ts";
export const VERSION = "v1.573.5";
export const VERSION = "v1.574.1";
export async function login(email: string, password: string): Promise<string> {
return await windmill.UserService.login({
+56 -12
View File
@@ -180,6 +180,14 @@ export async function handleScriptMetadata(
}
}
export interface OutputFile {
path: string
contents: Uint8Array
hash: string
/** "contents" as text (changes automatically with "contents") */
readonly text: string
}
export async function handleFile(
path: string,
workspace: Workspace,
@@ -210,7 +218,9 @@ export async function handleFile(
let bundleContent: string | Tarball | undefined = undefined;
let forceTar = false;
if (codebase) {
let outputFiles: OutputFile[] = [];
if (codebase.customBundler) {
log.info(`Using custom bundler ${codebase.customBundler} for ${path}`);
bundleContent = execSync(
@@ -232,35 +242,42 @@ export async function handleFile(
external: codebase.external,
inject: codebase.inject,
define: codebase.define,
loader: codebase.loader ?? { ".node": "file" },
outdir: '/',
platform: "node",
packages: "bundle",
target: format == "cjs" ? "node20.15.1" : "esnext",
});
const endTime = performance.now();
bundleContent = out.outputFiles[0].text;
outputFiles = out.outputFiles;
log.info(
`Finished bundling ${path}: ${(bundleContent.length / 1024).toFixed(
0
)}kB (${(endTime - startTime).toFixed(0)}ms)`
);
}
if (Array.isArray(codebase.assets) && codebase.assets.length > 0) {
if (outputFiles.length > 1) {
const archiveNpm = await import("npm:@ayonli/jsext/archive");
log.info(
`Using the following asset configuration for ${path}: ${JSON.stringify(
codebase.assets
)}`
`Found multiple output files for ${path}, creating a tarball... ${outputFiles.map((file) => file.path).join(", ")}`
);
forceTar = true;
const startTime = performance.now();
const tarball = new archiveNpm.Tarball();
const mainPath = path.split(SEP).pop()?.split(".")[0] + ".js";
const content = outputFiles.find((file) => file.path == "/" + mainPath)?.text ?? '';
log.info(`Main content: ${content.length}chars`);
tarball.append(
new File([bundleContent], "main.js", { type: "text/plain" })
new File([content], "main.js", { type: "text/plain" })
);
for (const asset of codebase.assets) {
const data = fs.readFileSync(asset.from);
const blob = new Blob([data], { type: "text/plain" });
const file = new File([blob], asset.to);
tarball.append(file);
for (const file of outputFiles) {
if (file.path == "/" + mainPath) {
continue;
}
log.info(`Adding file: ${file.path.substring(1)}`);
const fil = new File([file.contents], file.path.substring(1));
tarball.append(fil);
}
const endTime = performance.now();
log.info(
@@ -269,6 +286,33 @@ export async function handleFile(
).toFixed(0)}kB (${(endTime - startTime).toFixed(0)}ms)`
);
bundleContent = tarball;
} else {
if (Array.isArray(codebase.assets) && codebase.assets.length > 0) {
const archiveNpm = await import("npm:@ayonli/jsext/archive");
log.info(
`Using the following asset configuration for ${path}: ${JSON.stringify(
codebase.assets
)}`
);
const startTime = performance.now();
const tarball = new archiveNpm.Tarball();
tarball.append(
new File([bundleContent], "main.js", { type: "text/plain" })
);
for (const asset of codebase.assets) {
const data = fs.readFileSync(asset.from);
const blob = new Blob([data], { type: "text/plain" });
const file = new File([blob], asset.to);
tarball.append(file);
}
const endTime = performance.now();
log.info(
`Finished creating tarball for ${path}: ${(
tarball.size / 1024
).toFixed(0)}kB (${(endTime - startTime).toFixed(0)}ms)`
);
bundleContent = tarball;
}
}
}
let typed = opts?.skipScriptsMetadata
@@ -325,7 +369,7 @@ export async function handleFile(
}
if (typed && codebase) {
typed.codebase = await codebase.getDigest();
typed.codebase = await codebase.getDigest(forceTar);
}
const requestBodyCommon: NewScript = {
@@ -352,7 +396,7 @@ export async function handleFile(
concurrency_key: typed?.concurrency_key,
debounce_key: typed?.debounce_key,
debounce_delay_s: typed?.debounce_delay_s,
codebase: await codebase?.getDigest(),
codebase: await codebase?.getDigest(forceTar),
timeout: typed?.timeout,
on_behalf_of_email: typed?.on_behalf_of_email,
};
+1
View File
@@ -99,6 +99,7 @@ export interface Codebase {
external?: string[];
define?: { [key: string]: string };
inject?: string[];
loader?: any,
format?: "cjs" | "esm";
}
+1 -1
View File
@@ -68,7 +68,7 @@ export {
// }
// });
export const VERSION = "1.573.5";
export const VERSION = "1.574.1";
export const WM_FORK_PREFIX = "wm-fork";
+10 -5
View File
@@ -2,7 +2,7 @@ import { Codebase, SyncOptions } from "../core/conf.ts";
import { log } from "../../deps.ts";
import { digestDir } from "./utils.ts";
export type SyncCodebase = Codebase & { getDigest: () => Promise<string> };
export type SyncCodebase = Codebase & { getDigest: (forceTar?: boolean) => Promise<string> };
export function listSyncCodebases(
options: SyncOptions
): SyncCodebase[] {
@@ -13,16 +13,21 @@ export function listSyncCodebases(
}
for (const codebase of options?.codebases ?? []) {
let _digest: string | undefined = undefined;
const getDigest: () => Promise<string> = async () => {
if (_digest == undefined) {
let alreadyPrinted = false;
const getDigest: (forceTar?: boolean) => Promise<string> = async (forceTar?: boolean) => {
if (_digest == undefined || forceTar) {
_digest = await digestDir(
codebase.relative_path,
JSON.stringify(codebase)
);
if (Array.isArray(codebase.assets) && codebase.assets.length > 0) {
if (forceTar || (Array.isArray(codebase.assets) && codebase.assets.length > 0)) {
_digest += ".tar";
}
log.info(`Codebase ${codebase.relative_path}, digest: ${_digest}`);
if (!alreadyPrinted) {
alreadyPrinted = true;
log.info(`Codebase ${codebase.relative_path}, digest: ${_digest}`);
}
return _digest;
}
return _digest;
};
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "windmill-components",
"version": "1.573.5",
"version": "1.574.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "windmill-components",
"version": "1.573.5",
"version": "1.574.1",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "windmill-components",
"version": "1.573.5",
"version": "1.574.1",
"scripts": {
"dev": "vite dev",
"build": "vite build",
@@ -18,7 +18,7 @@
channels?: ChannelItem[]
teamId?: string
onError?: (error: Error) => void
onselectedchannelchange?: (channel: ChannelItem | undefined) => void
onSelectedChannelChange?: (channel: ChannelItem | undefined) => void
}
let {
@@ -30,7 +30,7 @@
channels = undefined,
teamId,
onError,
onselectedchannelchange
onSelectedChannelChange
}: Props = $props()
let isFetching = $state(false)
@@ -69,7 +69,7 @@
$effect(() => {
if (selectedChannel?.channel_id !== previousChannelId) {
previousChannelId = selectedChannel?.channel_id
onselectedchannelchange?.(selectedChannel)
onSelectedChannelChange?.(selectedChannel)
}
})
@@ -502,7 +502,7 @@
channel_name: handlerExtraArgs['channel_name']
}
: undefined}
onselectedchannelchange={(channel) => {
onSelectedChannelChange={(channel) => {
handlerExtraArgs['channel'] = channel?.channel_id
handlerExtraArgs['channel_name'] = channel?.channel_name
}}
@@ -39,6 +39,7 @@
import { aiChatManager } from './copilot/chat/AIChatManager.svelte'
import { stateSnapshot } from '$lib/svelte5Utils.svelte'
import FlowChatInterface from './flows/conversations/FlowChatInterface.svelte'
import { randomUUID } from './flows/conversations/FlowChatManager.svelte'
interface Props {
previewMode: 'upTo' | 'whole'
@@ -469,7 +470,7 @@
return jobId ?? ''
}}
createConversation={async () => {
const newConversationId = crypto.randomUUID()
const newConversationId = randomUUID()
return newConversationId
}}
/>
@@ -586,7 +586,7 @@
minWidth="140px"
showRefreshButton={false}
selectedTeam={currentTeam}
onselectedteamchange={(team) => handleTeamChange(team, i)}
onSelectedTeamChange={(team) => handleTeamChange(team, i)}
/>
{#if $values['critical_error_channels'][i]?.teams_channel?.team_id}
@@ -595,7 +595,7 @@
placeholder="Search channels"
teamId={$values['critical_error_channels'][i]?.teams_channel?.team_id}
selectedChannel={currentChannel}
onselectedchannelchange={(channel) => handleChannelChange(channel, i)}
onSelectedChannelChange={(channel) => handleChannelChange(channel, i)}
onError={(e) =>
sendUserToast('Failed to load channels: ' + e.message, true)}
/>
@@ -18,7 +18,7 @@
teams?: TeamItem[] | undefined
minWidth?: string
onError?: (error: Error) => void
onselectedteamchange?: (team: TeamItem | undefined) => void
onSelectedTeamChange?: (team: TeamItem | undefined) => void
}
let {
@@ -29,7 +29,7 @@
teams = undefined,
minWidth = '160px',
onError,
onselectedteamchange
onSelectedTeamChange
}: Props = $props()
let isFetching = $state(false)
@@ -68,7 +68,7 @@
$effect(() => {
if (selectedTeam?.team_id !== previousTeamId) {
previousTeamId = selectedTeam?.team_id
onselectedteamchange?.(selectedTeam)
onSelectedTeamChange?.(selectedTeam)
}
})
@@ -55,7 +55,11 @@
})
let selectedItems: string[] = $state([...new Set(outputs?.result.peak())].map(convertToValue))
$effect(() => setResultsFromSelectedItems(selectedItems))
$effect(() => {
selectedItems
// console.log('selectedItems', selectedItems)
untrack(() => setResultsFromSelectedItems(selectedItems))
})
let customItems: string[] = $state([])
@@ -49,6 +49,7 @@
import { AI_AGENT_SCHEMA } from '../flowInfers'
import { nextId } from '../flowModuleNextId'
import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte'
import { randomUUID } from '../conversations/FlowChatManager.svelte'
interface Props {
noEditor: boolean
@@ -491,7 +492,7 @@
<FlowChatInterface
onRunFlow={runFlowWithMessage}
createConversation={async () => {
const newConversationId = crypto.randomUUID()
const newConversationId = randomUUID()
return newConversationId
}}
/>
@@ -18,6 +18,15 @@ export interface FlowChatManagerOptions {
path?: string
}
export function randomUUID() {
// Pure JS (RFC4122 v4) UUID implementation (no external dependencies)
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = (Math.random() * 16) | 0
const v = c === 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
}
class FlowChatManager {
// State
messages = $state<ChatMessage[]>([])
@@ -320,7 +329,7 @@ class FlowChatManager {
delete this.#conversationsCache[currentConversationId]
const userMessage: ChatMessage = {
id: crypto.randomUUID(),
id: randomUUID(),
content: this.inputMessage.trim(),
created_at: new Date().toISOString(),
message_type: 'user',
@@ -371,17 +380,20 @@ class FlowChatManager {
let isCompleted = false
try {
const jobId = await JobService.runFlowByPath({
workspace: this.#workspace!,
path: this.#path!,
requestBody: { user_message: messageContent },
memoryId: currentConversationId
})
// Encode the payload as base64
const payload = { user_message: messageContent }
const payloadBase64 = btoa(JSON.stringify(payload))
// Build the EventSource URL
const streamUrl = `/api/w/${this.#workspace}/jobs/run_and_stream/f/${this.#path}`
const streamUrl = `/api/w/${this.#workspace}/jobs_u/getupdate_sse/${jobId}`
const url = new URL(streamUrl, window.location.origin)
url.searchParams.set('payload', payloadBase64)
url.searchParams.set('memory_id', currentConversationId)
url.searchParams.set('poll_delay_ms', '50')
url.searchParams.set('fast', 'true')
url.searchParams.set('only_result', 'true')
// Create EventSource connection
const eventSource = new EventSource(url.toString())
this.currentEventSource = eventSource
@@ -392,7 +404,6 @@ class FlowChatManager {
eventSource.onmessage = async (event) => {
try {
const data = JSON.parse(event.data)
if (data.type === 'update') {
if (data.flow_stream_job_id) {
this.currentJobId = data.flow_stream_job_id
@@ -420,7 +431,7 @@ class FlowChatManager {
this.messages = [
...this.messages,
{
id: 'temp-' + crypto.randomUUID(),
id: 'temp-' + randomUUID(),
content: newContent,
created_at: new Date().toISOString(),
message_type: 'tool',
@@ -442,7 +453,7 @@ class FlowChatManager {
assistantMessageId.length === 0 &&
accumulatedContent.length > 0
) {
assistantMessageId = 'temp-' + crypto.randomUUID()
assistantMessageId = 'temp-' + randomUUID()
this.messages = [
...this.messages,
{
@@ -18,7 +18,7 @@
export let error: boolean = false
export let allowCopy = false
export let previousId: string | undefined = undefined
export let flow_env: Record<string, string> | undefined = undefined
export let flow_env: Record<string, any> | undefined = undefined
let variables: Record<string, string> = {}
let resources: Record<string, any> = {}
@@ -65,6 +65,7 @@
initFlowGraphAssetsCtx
} from '$lib/components/flows/FlowAssetsHandler.svelte'
import { page } from '$app/state'
import { randomUUID } from '$lib/components/flows/conversations/FlowChatManager.svelte'
let flow: Flow | undefined = $state()
let can_write = false
@@ -401,7 +402,7 @@
let path = $derived(page.params.path ?? '')
async function handleNewConversation({ clearMessages = true }: { clearMessages?: boolean }) {
const newConversationId = crypto.randomUUID()
const newConversationId = randomUUID()
// Add the new conversation to the sidebar (returns id of draft or new conversation)
if (flowConversationsSidebar) {
+2 -2
View File
@@ -4,8 +4,8 @@ verify_ssl = true
name = "pypi"
[packages]
wmill = ">=1.573.5"
wmill_pg = ">=1.573.5"
wmill = ">=1.574.1"
wmill_pg = ">=1.574.1"
sendgrid = "*"
mysql-connector-python = "*"
pymongo = "*"
+1 -1
View File
@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.573.5
version: 1.574.1
title: OpenFlow Spec
contact:
name: Ruben Fiszel
@@ -12,7 +12,7 @@
RootModule = 'WindmillClient.psm1'
# Version number of this module.
ModuleVersion = '1.573.5'
ModuleVersion = '1.574.1'
# Supported PSEditions
# CompatiblePSEditions = @()
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill"
version = "1.573.5"
version = "1.574.1"
description = "A client library for accessing Windmill server wrapping the Windmill client API"
license = "Apache-2.0"
homepage = "https://windmill.dev"
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill-pg"
version = "1.573.5"
version = "1.574.1"
description = "An extension client for the wmill client library focused on pg"
license = "Apache-2.0"
homepage = "https://windmill.dev"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@windmill/windmill",
"version": "1.573.5",
"version": "1.574.1",
"exports": "./src/index.ts",
"publish": {
"exclude": ["!src", "./s3Types.ts", "./client.ts"]
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "windmill-client",
"description": "Windmill SDK client for browsers and Node.js",
"version": "1.573.5",
"version": "1.574.1",
"author": "Ruben Fiszel",
"license": "Apache 2.0",
"devDependencies": {
+1 -1
View File
@@ -1 +1 @@
1.573.5
1.574.1