mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 00:01:34 +00:00
Revert "chore: revert non-migration files to main branch state"
This reverts commit 38ba77db06.
This commit is contained in:
@@ -238,4 +238,4 @@ jobs:
|
||||
run: |
|
||||
deno --version && bun -v && node --version && go version && python3 --version && php --version && ruby --version && pwsh --version && dotnet --version
|
||||
cd windmill-duckdb-ffi-internal && ./build_dev.sh && cd ..
|
||||
DENO_PATH=$(which deno) BUN_PATH=$(which bun) NODE_BIN_PATH=$(which node) GO_PATH=$(which go) UV_PATH=$(which uv) PHP_PATH=$(which php) COMPOSER_PATH=$(which composer) RUBY_PATH=$(which ruby) RUBY_BUNDLE_PATH=$(which bundle) RUBY_GEM_PATH=$(which gem) POWERSHELL_PATH=$(which pwsh) DOTNET_PATH=$(which dotnet) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private,private_registry_test,csharp,php,ruby,mysql,quickjs,mcp,run_inline --all -- --nocapture --test-threads=10
|
||||
DENO_PATH=$(which deno) BUN_PATH=$(which bun) NODE_BIN_PATH=$(which node) GO_PATH=$(which go) UV_PATH=$(which uv) PHP_PATH=$(which php) COMPOSER_PATH=$(which composer) RUBY_PATH=$(which ruby) RUBY_BUNDLE_PATH=$(which bundle) RUBY_GEM_PATH=$(which gem) POWERSHELL_PATH=$(which pwsh) DOTNET_PATH=$(which dotnet) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private,private_registry_test,csharp,php,ruby,mysql,quickjs,mcp --all -- --nocapture --test-threads=10
|
||||
|
||||
@@ -9,7 +9,9 @@ on:
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
- edited
|
||||
pull_request_review_comment:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
notify_discord_when_pr_opened:
|
||||
@@ -51,7 +53,23 @@ jobs:
|
||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
|
||||
COMMENT_URL: ${{ github.event.comment.html_url }}
|
||||
COMMENT_IS_EDIT: ${{ github.event.action == 'edited' }}
|
||||
DISCORD_CHANNEL_ID: "1372204995868491786"
|
||||
DISCORD_GUILD_ID: "930051556043276338"
|
||||
secrets:
|
||||
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_AI_BOT_TOKEN }}
|
||||
|
||||
notify_discord_on_review_comment:
|
||||
if: >
|
||||
github.event_name == 'pull_request_review_comment'
|
||||
&& github.event.comment.user.login != 'cloudflare-workers-and-pages[bot]'
|
||||
&& github.event.comment.user.login != 'ellipsis-dev[bot]'
|
||||
uses: ./.github/workflows/shareable-discord-notification.yml
|
||||
with:
|
||||
PR_STATUS: "comment"
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
|
||||
COMMENT_URL: ${{ github.event.comment.html_url }}
|
||||
DISCORD_CHANNEL_ID: "1372204995868491786"
|
||||
DISCORD_GUILD_ID: "930051556043276338"
|
||||
secrets:
|
||||
|
||||
@@ -36,10 +36,6 @@ on:
|
||||
description: "The comment URL"
|
||||
type: string
|
||||
default: ""
|
||||
COMMENT_IS_EDIT:
|
||||
description: "Whether this is an edit of an existing comment"
|
||||
type: string
|
||||
default: "false"
|
||||
secrets:
|
||||
DISCORD_WEBHOOK_URL:
|
||||
description: "Discord Webhook URL"
|
||||
@@ -139,7 +135,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ inputs.PR_STATUS == 'comment' }}
|
||||
steps:
|
||||
- name: Post or update comment in Discord thread
|
||||
- name: Post comment to Discord thread
|
||||
env:
|
||||
BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
|
||||
CHANNEL_ID: ${{ inputs.DISCORD_CHANNEL_ID }}
|
||||
@@ -148,7 +144,6 @@ jobs:
|
||||
COMMENT_BODY: ${{ inputs.COMMENT_BODY }}
|
||||
COMMENT_AUTHOR: ${{ inputs.COMMENT_AUTHOR }}
|
||||
COMMENT_URL: ${{ inputs.COMMENT_URL }}
|
||||
COMMENT_IS_EDIT: ${{ inputs.COMMENT_IS_EDIT }}
|
||||
run: |
|
||||
# 1) Find the thread by PR number
|
||||
threads=$(curl -s -H "Authorization: Bot $BOT_TOKEN" \
|
||||
@@ -177,36 +172,10 @@ jobs:
|
||||
truncated_body="$COMMENT_BODY"
|
||||
fi
|
||||
|
||||
# 3) Build the message content
|
||||
if [ "$COMMENT_IS_EDIT" = "true" ]; then
|
||||
message=$(printf '**%s** [edited comment](%s):\n%s' "$COMMENT_AUTHOR" "$COMMENT_URL" "$truncated_body")
|
||||
else
|
||||
message=$(printf '**%s** [commented](%s):\n%s' "$COMMENT_AUTHOR" "$COMMENT_URL" "$truncated_body")
|
||||
fi
|
||||
# 3) Post the comment to the thread
|
||||
message=$(printf '**%s** [commented](%s):\n%s' "$COMMENT_AUTHOR" "$COMMENT_URL" "$truncated_body")
|
||||
payload=$(jq -n --arg content "$message" '{content: $content, flags: 4, allowed_mentions: {parse: []}}')
|
||||
|
||||
# 4) If this is an edit, try to find and update the existing Discord message
|
||||
if [ "$COMMENT_IS_EDIT" = "true" ]; then
|
||||
# Search recent messages in the thread for one containing the comment URL
|
||||
messages=$(curl -s -H "Authorization: Bot $BOT_TOKEN" \
|
||||
"https://discord.com/api/v10/channels/${thread_id}/messages?limit=100")
|
||||
existing_msg_id=$(echo "$messages" | jq -r \
|
||||
--arg url "$COMMENT_URL" \
|
||||
'[.[] | select(.content | contains($url))] | first | .id // empty')
|
||||
|
||||
if [ -n "$existing_msg_id" ]; then
|
||||
echo "Updating existing Discord message $existing_msg_id"
|
||||
curl -s -X PATCH \
|
||||
-H "Authorization: Bot $BOT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" \
|
||||
"https://discord.com/api/v10/channels/${thread_id}/messages/${existing_msg_id}"
|
||||
exit 0
|
||||
fi
|
||||
echo "Original Discord message not found, posting as new message"
|
||||
fi
|
||||
|
||||
# 5) Post a new message to the thread
|
||||
curl -s -X POST \
|
||||
-H "Authorization: Bot $BOT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
|
||||
Generated
-1
@@ -16167,7 +16167,6 @@ dependencies = [
|
||||
"windmill-common",
|
||||
"windmill-native-triggers",
|
||||
"windmill-test-utils",
|
||||
"windmill-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
+2
-2
@@ -159,12 +159,12 @@ all_languages = ["python", "deno_core", "rust", "mysql", "oracledb", "duckdb", "
|
||||
# For windows we have another set of languages enabled
|
||||
all_languages_windows = ["python", "deno_core", "rust", "mysql", "oracledb", "duckdb", "mssql-winauth", "bigquery", "csharp", "nu", "php", "java"]
|
||||
# Edition meta-features: shared groups
|
||||
run_inline = ["windmill-api/run_inline"]
|
||||
inline_preview = ["windmill-api/inline_preview"]
|
||||
oss_core = [
|
||||
"embedding", "parquet", "openidconnect", "license",
|
||||
"http_trigger", "zip", "oauth2", "postgres_trigger",
|
||||
"mqtt_trigger", "websocket", "smtp", "native_trigger",
|
||||
"static_frontend", "mcp", "bedrock", "run_inline",
|
||||
"static_frontend", "mcp", "bedrock", "inline_preview",
|
||||
"quickjs"
|
||||
]
|
||||
ce_core = ["oss_core", "private", "operator"]
|
||||
|
||||
@@ -13,7 +13,7 @@ default = []
|
||||
enterprise = ["dep:windmill-autoscaling"]
|
||||
private = []
|
||||
python = []
|
||||
run_inline = ["dep:windmill-worker", "dep:itertools"]
|
||||
inline_preview = ["dep:windmill-worker", "dep:itertools"]
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
|
||||
@@ -283,14 +283,14 @@ async fn native_kubernetes_autoscaling_healthcheck() -> Result<(), error::Error>
|
||||
}
|
||||
|
||||
async fn list_available_python_versions() -> error::JsonResult<Vec<String>> {
|
||||
#[cfg(not(all(feature = "python", feature = "run_inline")))]
|
||||
#[cfg(not(all(feature = "python", feature = "inline_preview")))]
|
||||
return Err(error::Error::BadRequest(
|
||||
"Python listing available only with 'python' feature enabled".to_string(),
|
||||
));
|
||||
|
||||
#[cfg(all(feature = "python", feature = "run_inline"))]
|
||||
#[cfg(all(feature = "python", feature = "inline_preview"))]
|
||||
use itertools::Itertools;
|
||||
#[cfg(all(feature = "python", feature = "run_inline"))]
|
||||
#[cfg(all(feature = "python", feature = "inline_preview"))]
|
||||
return Ok(Json(
|
||||
windmill_worker::PyV::list_available_python_versions()
|
||||
.await
|
||||
|
||||
@@ -14,7 +14,6 @@ private = ["windmill-test-utils/private", "dep:aws-config", "dep:aws-credential-
|
||||
enterprise = ["windmill-test-utils/enterprise", "dep:base64"]
|
||||
deno_core = ["windmill-test-utils/deno_core"]
|
||||
mcp = []
|
||||
run_inline = ["dep:windmill-worker", "windmill-test-utils/run_inline", "windmill-test-utils/duckdb"]
|
||||
|
||||
[dependencies]
|
||||
windmill-test-utils.workspace = true
|
||||
@@ -22,7 +21,6 @@ windmill-api-client.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-native-triggers = { workspace = true, features = ["native_trigger"] }
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-worker = { workspace = true, optional = true }
|
||||
sqlx.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
@@ -13,7 +13,7 @@ default = []
|
||||
private = ["windmill-audit/private", "windmill-common/private", "windmill-api-auth/private", "windmill-store/private", "windmill-api-users/private", "windmill-api-workspaces/private", "windmill-api-groups/private", "windmill-api-configs/private", "windmill-api-settings/private", "windmill-api-agent-workers?/private", "windmill-trigger-kafka?/private", "windmill-trigger-postgres?/private", "windmill-trigger-mqtt?/private", "windmill-trigger-websocket?/private", "windmill-trigger-nats?/private", "windmill-trigger-sqs?/private", "windmill-trigger-gcp?/private", "windmill-trigger-email?/private"]
|
||||
enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "windmill-worker?/enterprise", "windmill-api-auth/enterprise", "windmill-store/enterprise", "windmill-api-jobs/enterprise", "windmill-api-scripts/enterprise", "windmill-api-flows/enterprise", "windmill-api-users/enterprise", "windmill-api-workspaces/enterprise", "windmill-api-groups/enterprise", "windmill-api-configs/enterprise", "windmill-api-settings/enterprise", "windmill-api-agent-workers?/enterprise", "windmill-trigger/enterprise", "windmill-trigger-kafka?/enterprise", "windmill-trigger-postgres?/enterprise", "windmill-trigger-mqtt?/enterprise", "windmill-trigger-websocket?/enterprise", "windmill-trigger-email?/enterprise", "windmill-trigger-nats?/enterprise", "windmill-trigger-sqs?/enterprise", "windmill-trigger-gcp?/enterprise", "windmill-trigger-http?/enterprise", "windmill-native-triggers?/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise"]
|
||||
stripe = []
|
||||
run_inline = ["dep:windmill-worker", "windmill-api-configs/run_inline"]
|
||||
inline_preview = ["dep:windmill-worker", "windmill-api-configs/inline_preview"]
|
||||
agent_worker_server = ["dep:windmill-worker", "dep:windmill-api-agent-workers"]
|
||||
enterprise_saml = ["dep:samael", "dep:libxml"]
|
||||
benchmark = []
|
||||
|
||||
@@ -9173,54 +9173,6 @@ paths:
|
||||
application/json:
|
||||
schema: {}
|
||||
|
||||
/w/{workspace}/jobs/run_inline/p/{path}:
|
||||
post:
|
||||
summary: run script by path without starting a new job
|
||||
operationId: runScriptByPathInline
|
||||
tags:
|
||||
- job
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/ScriptPath"
|
||||
requestBody:
|
||||
description: script args
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/InlineScriptArgs"
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: script result
|
||||
content:
|
||||
application/json:
|
||||
schema: {}
|
||||
|
||||
/w/{workspace}/jobs/run_inline/h/{hash}:
|
||||
post:
|
||||
summary: run script by hash without starting a new job
|
||||
operationId: runScriptByHashInline
|
||||
tags:
|
||||
- job
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/ScriptHash"
|
||||
requestBody:
|
||||
description: script args
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/InlineScriptArgs"
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: script result
|
||||
content:
|
||||
application/json:
|
||||
schema: {}
|
||||
|
||||
/w/{workspace}/jobs/run_wait_result/preview:
|
||||
post:
|
||||
summary: run script preview and wait for result
|
||||
@@ -19859,12 +19811,6 @@ components:
|
||||
$ref: "#/components/schemas/ScriptLang"
|
||||
required: [content, args, language]
|
||||
|
||||
InlineScriptArgs:
|
||||
type: object
|
||||
properties:
|
||||
args:
|
||||
$ref: "#/components/schemas/ScriptArgs"
|
||||
|
||||
WorkflowTask:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -27,22 +27,20 @@ use url::Url;
|
||||
#[cfg(all(feature = "enterprise", feature = "smtp"))]
|
||||
use windmill_common::auth::is_super_admin_email;
|
||||
use windmill_common::auth::TOKEN_PREFIX_LEN;
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[cfg(feature = "inline_preview")]
|
||||
use windmill_common::client::AuthedClient;
|
||||
use windmill_common::db::UserDbWithAuthed;
|
||||
use windmill_common::error::JsonResult;
|
||||
use windmill_common::flow_status::{JobResult, RestartedFrom};
|
||||
#[cfg(feature = "inline_preview")]
|
||||
use windmill_common::jobs::RunInlinePreviewScriptFnParams;
|
||||
use windmill_common::jobs::{
|
||||
format_completed_job_result, format_result, DynamicInput, ENTRYPOINT_OVERRIDE,
|
||||
};
|
||||
#[cfg(feature = "run_inline")]
|
||||
use windmill_common::jobs::{
|
||||
InlineScriptTarget, RunInlinePreviewScriptFnParams, RunInlineScriptFnParams,
|
||||
};
|
||||
use windmill_common::runnable_settings::{
|
||||
ConcurrencySettings, ConcurrencySettingsWithCustom, DebouncingSettings,
|
||||
};
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[cfg(feature = "inline_preview")]
|
||||
use windmill_common::runtime_assets::{register_runtime_asset, InsertRuntimeAssetParams};
|
||||
use windmill_common::scripts::ScriptRunnableSettingsInline;
|
||||
use windmill_common::triggers::TriggerMetadata;
|
||||
@@ -55,15 +53,15 @@ use windmill_common::DYNAMIC_INPUT_CACHE;
|
||||
#[cfg(all(feature = "enterprise", feature = "smtp"))]
|
||||
use windmill_common::{email_oss::send_email_html, server::load_smtp_config};
|
||||
use windmill_object_store::upload_artifact_to_store;
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[cfg(feature = "inline_preview")]
|
||||
use windmill_parser::asset_parser::AssetKind;
|
||||
use windmill_types::s3::BundleFormat;
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[cfg(feature = "inline_preview")]
|
||||
use windmill_worker::get_worker_internal_server_inline_utils;
|
||||
|
||||
use windmill_common::variables::get_workspace_key;
|
||||
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[cfg(feature = "inline_preview")]
|
||||
use crate::db::OptJobAuthed;
|
||||
use crate::triggers::trigger_helpers::{FlowId, ScriptId};
|
||||
use crate::{
|
||||
@@ -244,11 +242,6 @@ pub fn workspaced_service() -> Router {
|
||||
)
|
||||
.route("/run/preview", post(run_preview_script))
|
||||
.route("/run_inline/preview", post(run_inline_preview_script))
|
||||
.route(
|
||||
"/run_inline/p/*script_path",
|
||||
post(run_inline_script_by_path),
|
||||
)
|
||||
.route("/run_inline/h/:hash", post(run_inline_script_by_hash))
|
||||
.route(
|
||||
"/run_wait_result/preview",
|
||||
post(run_wait_result_preview_script),
|
||||
@@ -2860,7 +2853,7 @@ struct Preview {
|
||||
flow_path: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[cfg(feature = "inline_preview")]
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct PreviewInline {
|
||||
content: String,
|
||||
@@ -2868,12 +2861,6 @@ struct PreviewInline {
|
||||
language: ScriptLang,
|
||||
}
|
||||
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct InlineScriptArgs {
|
||||
args: Option<HashMap<String, Box<JsonRawValue>>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct WorkflowTask {
|
||||
pub args: Option<HashMap<String, Box<JsonRawValue>>>,
|
||||
@@ -4586,7 +4573,7 @@ async fn run_preview_script(
|
||||
Ok((StatusCode::CREATED, uuid.to_string()))
|
||||
}
|
||||
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[cfg(feature = "inline_preview")]
|
||||
async fn run_inline_preview_script(
|
||||
OptJobAuthed { authed, job_id }: OptJobAuthed,
|
||||
Tokened { token }: Tokened,
|
||||
@@ -4623,120 +4610,14 @@ async fn run_inline_preview_script(
|
||||
Ok(Json(to_raw_value(&result)).into_response())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "run_inline"))]
|
||||
#[cfg(not(feature = "inline_preview"))]
|
||||
async fn run_inline_preview_script() -> error::Result<Response> {
|
||||
Err(error::Error::InternalErr(
|
||||
"inline preview requires the worker feature".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "run_inline")]
|
||||
async fn run_inline_script_by_path(
|
||||
OptJobAuthed { authed, .. }: OptJobAuthed,
|
||||
Tokened { token }: Tokened,
|
||||
Extension(db): Extension<DB>,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Path((w_id, script_path)): Path<(String, StripPath)>,
|
||||
Json(body): Json<InlineScriptArgs>,
|
||||
) -> error::Result<Response> {
|
||||
let script_path_str = script_path.to_path();
|
||||
check_scopes(&authed, || format!("jobs:run:scripts:{script_path_str}"))?;
|
||||
run_inline_script_inner(
|
||||
authed,
|
||||
token,
|
||||
db,
|
||||
w_id,
|
||||
InlineScriptTarget::Path(script_path.to_path().to_string()),
|
||||
body.args,
|
||||
Some(user_db),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "run_inline"))]
|
||||
async fn run_inline_script_by_path() -> error::Result<Response> {
|
||||
Err(error::Error::InternalErr(
|
||||
"inline script by path requires the worker feature".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "run_inline")]
|
||||
async fn run_inline_script_by_hash(
|
||||
OptJobAuthed { authed, .. }: OptJobAuthed,
|
||||
Tokened { token }: Tokened,
|
||||
Extension(db): Extension<DB>,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Path((w_id, script_hash)): Path<(String, ScriptHash)>,
|
||||
Json(body): Json<InlineScriptArgs>,
|
||||
) -> error::Result<Response> {
|
||||
// Resolve the script path from the hash and check scopes properly
|
||||
let hash = script_hash.0;
|
||||
let userdb_authed = UserDbWithAuthed { db: user_db.clone(), authed: &authed.to_authed_ref() };
|
||||
let ScriptHashInfo { path, .. } =
|
||||
get_script_info_for_hash(Some(userdb_authed), &db, &w_id, hash)
|
||||
.await?
|
||||
.prefetch_cached(&db)
|
||||
.await?;
|
||||
|
||||
check_scopes(&authed, || format!("jobs:run:scripts:{path}"))?;
|
||||
|
||||
run_inline_script_inner(
|
||||
authed,
|
||||
token,
|
||||
db,
|
||||
w_id,
|
||||
InlineScriptTarget::Hash(hash),
|
||||
body.args,
|
||||
Some(user_db),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "run_inline"))]
|
||||
async fn run_inline_script_by_hash() -> error::Result<Response> {
|
||||
Err(error::Error::InternalErr(
|
||||
"inline script by hash requires the worker feature".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "run_inline")]
|
||||
async fn run_inline_script_inner(
|
||||
authed: ApiAuthed,
|
||||
token: String,
|
||||
db: DB,
|
||||
w_id: String,
|
||||
target: InlineScriptTarget,
|
||||
args: Option<HashMap<String, Box<JsonRawValue>>>,
|
||||
user_db: Option<UserDB>,
|
||||
) -> error::Result<Response> {
|
||||
let utils = get_worker_internal_server_inline_utils()?;
|
||||
let authed_owned: windmill_common::db::Authed = authed.clone().into();
|
||||
let result = utils.run_inline_script.as_ref()(RunInlineScriptFnParams {
|
||||
target,
|
||||
args,
|
||||
workspace_id: w_id.clone(),
|
||||
base_internal_url: utils.base_internal_url.clone(),
|
||||
killpill_rx: utils.killpill_rx.resubscribe(),
|
||||
created_by: authed.display_username().to_string(),
|
||||
permissioned_as: username_to_permissioned_as(&authed.username),
|
||||
permissioned_as_email: authed.email.clone(),
|
||||
job_dir: "".to_string(),
|
||||
worker_name: "".to_string(),
|
||||
worker_dir: "".to_string(),
|
||||
client: AuthedClient {
|
||||
base_internal_url: utils.base_internal_url.clone(),
|
||||
force_client: None,
|
||||
token,
|
||||
workspace: w_id,
|
||||
},
|
||||
conn: windmill_common::worker::Connection::Sql(db),
|
||||
user_db: user_db.map(|udb| (udb, authed_owned)),
|
||||
})
|
||||
.await?;
|
||||
Ok(Json(to_raw_value(&result)).into_response())
|
||||
}
|
||||
|
||||
#[cfg(feature = "run_inline")]
|
||||
#[cfg(feature = "inline_preview")]
|
||||
fn register_potential_assets_on_inline_execution(
|
||||
job_id: Uuid,
|
||||
w_id: &str,
|
||||
|
||||
@@ -17,21 +17,6 @@ pub struct Authed {
|
||||
pub token_prefix: Option<String>,
|
||||
}
|
||||
|
||||
impl Authed {
|
||||
pub fn to_authed_ref(&self) -> AuthedRef<'_> {
|
||||
AuthedRef {
|
||||
email: &self.email,
|
||||
username: &self.username,
|
||||
is_admin: &self.is_admin,
|
||||
is_operator: &self.is_operator,
|
||||
groups: &self.groups,
|
||||
folders: &self.folders,
|
||||
scopes: &self.scopes,
|
||||
token_prefix: &self.token_prefix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash)]
|
||||
pub struct AuthedRef<'a> {
|
||||
pub email: &'a str,
|
||||
|
||||
@@ -326,28 +326,6 @@ pub struct RunInlinePreviewScriptFnParams {
|
||||
pub killpill_rx: tokio::sync::broadcast::Receiver<()>,
|
||||
}
|
||||
|
||||
pub enum InlineScriptTarget {
|
||||
Path(String),
|
||||
Hash(i64),
|
||||
}
|
||||
|
||||
pub struct RunInlineScriptFnParams {
|
||||
pub workspace_id: String,
|
||||
pub target: InlineScriptTarget,
|
||||
pub args: Option<HashMap<String, Box<RawValue>>>,
|
||||
pub created_by: String,
|
||||
pub permissioned_as: String,
|
||||
pub permissioned_as_email: String,
|
||||
pub base_internal_url: String,
|
||||
pub worker_name: String,
|
||||
pub conn: crate::worker::Connection,
|
||||
pub client: AuthedClient,
|
||||
pub job_dir: String,
|
||||
pub worker_dir: String,
|
||||
pub killpill_rx: tokio::sync::broadcast::Receiver<()>,
|
||||
pub user_db: Option<(crate::db::UserDB, crate::db::Authed)>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WorkerInternalServerInlineUtils {
|
||||
pub killpill_rx: Arc<tokio::sync::broadcast::Receiver<()>>,
|
||||
@@ -359,13 +337,6 @@ pub struct WorkerInternalServerInlineUtils {
|
||||
+ Send
|
||||
+ Sync,
|
||||
>,
|
||||
pub run_inline_script: Arc<
|
||||
dyn Fn(
|
||||
RunInlineScriptFnParams,
|
||||
) -> Pin<Box<dyn Future<Output = error::Result<Box<RawValue>>> + Send>>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>,
|
||||
}
|
||||
// To run a script inline, bypassing the db and job queue, windmill-api uses these functions.
|
||||
// They should only be called by the internal server of a worker.
|
||||
|
||||
@@ -2285,59 +2285,6 @@ pub struct MiniPulledJob {
|
||||
pub runnable_settings_handle: Option<i64>,
|
||||
}
|
||||
|
||||
impl MiniPulledJob {
|
||||
pub fn new_inline(
|
||||
workspace_id: String,
|
||||
args: Option<HashMap<String, Box<RawValue>>>,
|
||||
created_by: String,
|
||||
permissioned_as: String,
|
||||
permissioned_as_email: String,
|
||||
runnable_path: Option<String>,
|
||||
kind: JobKind,
|
||||
runnable_id: Option<ScriptHash>,
|
||||
tag: String,
|
||||
script_lang: Option<ScriptLang>,
|
||||
) -> Self {
|
||||
Self {
|
||||
workspace_id,
|
||||
id: Uuid::new_v4(),
|
||||
args: args.map(Json),
|
||||
parent_job: None,
|
||||
created_by,
|
||||
scheduled_for: chrono::Utc::now(),
|
||||
started_at: None,
|
||||
runnable_path,
|
||||
kind,
|
||||
runnable_id,
|
||||
canceled_reason: None,
|
||||
canceled_by: None,
|
||||
permissioned_as,
|
||||
permissioned_as_email,
|
||||
flow_status: None,
|
||||
tag,
|
||||
script_lang,
|
||||
same_worker: true,
|
||||
pre_run_error: None,
|
||||
flow_innermost_root_job: None,
|
||||
root_job: None,
|
||||
timeout: None,
|
||||
flow_step_id: None,
|
||||
cache_ttl: None,
|
||||
cache_ignore_s3_path: None,
|
||||
priority: None,
|
||||
preprocessed: None,
|
||||
script_entrypoint_override: None,
|
||||
trigger: None,
|
||||
trigger_kind: None,
|
||||
visible_to_owner: false,
|
||||
permissioned_as_end_user_email: None,
|
||||
runnable_settings_handle: None,
|
||||
concurrent_limit: None,
|
||||
concurrency_time_window_s: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MiniCompletedJob {
|
||||
pub id: Uuid,
|
||||
|
||||
@@ -15,8 +15,6 @@ enterprise = []
|
||||
python = ["windmill-common/python"]
|
||||
deno_core = ["dep:windmill-runtime-nativets"]
|
||||
agent_worker_server = ["dep:windmill-api-agent-workers"]
|
||||
run_inline = ["windmill-api/run_inline"]
|
||||
duckdb = ["windmill-worker/duckdb"]
|
||||
|
||||
[dependencies]
|
||||
windmill-api = { workspace = true, default-features = false }
|
||||
|
||||
@@ -14,10 +14,6 @@ use futures::TryFutureExt;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::time::timeout;
|
||||
use windmill_common::client::AuthedClient;
|
||||
use windmill_common::db::UserDbWithAuthed;
|
||||
use windmill_common::get_latest_deployed_hash_for_path;
|
||||
use windmill_common::jobs::InlineScriptTarget;
|
||||
use windmill_common::jobs::RunInlineScriptFnParams;
|
||||
use windmill_common::jobs::WorkerInternalServerInlineUtils;
|
||||
use windmill_common::jobs::WORKER_INTERNAL_SERVER_INLINE_UTILS;
|
||||
use windmill_common::runtime_assets::init_runtime_asset_loop;
|
||||
@@ -4709,18 +4705,43 @@ pub fn init_worker_internal_server_inline_utils(
|
||||
base_internal_url,
|
||||
killpill_rx: Arc::new(killpill_rx),
|
||||
run_inline_preview_script: Arc::new(|params| {
|
||||
let job = MiniPulledJob::new_inline(
|
||||
params.workspace_id,
|
||||
params.args,
|
||||
params.created_by,
|
||||
params.permissioned_as,
|
||||
params.permissioned_as_email,
|
||||
None,
|
||||
JobKind::Preview,
|
||||
None,
|
||||
"inline_preview".to_string(),
|
||||
Some(params.lang),
|
||||
);
|
||||
let job = MiniPulledJob {
|
||||
workspace_id: params.workspace_id,
|
||||
id: Uuid::new_v4(),
|
||||
args: params.args.map(Json),
|
||||
parent_job: None,
|
||||
created_by: params.created_by,
|
||||
scheduled_for: chrono::Utc::now(),
|
||||
started_at: None,
|
||||
runnable_path: None,
|
||||
kind: JobKind::Preview,
|
||||
runnable_id: None,
|
||||
canceled_reason: None,
|
||||
canceled_by: None,
|
||||
permissioned_as: params.permissioned_as,
|
||||
permissioned_as_email: params.permissioned_as_email,
|
||||
flow_status: None,
|
||||
tag: "inline_preview".to_string(),
|
||||
script_lang: Some(params.lang),
|
||||
same_worker: true,
|
||||
pre_run_error: None,
|
||||
flow_innermost_root_job: None,
|
||||
root_job: None,
|
||||
timeout: None,
|
||||
flow_step_id: None,
|
||||
cache_ttl: None,
|
||||
cache_ignore_s3_path: None,
|
||||
priority: None,
|
||||
preprocessed: None,
|
||||
script_entrypoint_override: None,
|
||||
trigger: None,
|
||||
trigger_kind: None,
|
||||
visible_to_owner: false,
|
||||
permissioned_as_end_user_email: None,
|
||||
runnable_settings_handle: None,
|
||||
concurrent_limit: None,
|
||||
concurrency_time_window_s: None,
|
||||
};
|
||||
Box::pin(async move {
|
||||
let mut mem_peak: i32 = -1;
|
||||
let mut canceled_by: Option<CanceledBy> = None;
|
||||
@@ -4757,86 +4778,6 @@ pub fn init_worker_internal_server_inline_utils(
|
||||
.await
|
||||
})
|
||||
}),
|
||||
run_inline_script: Arc::new(|params: RunInlineScriptFnParams| {
|
||||
Box::pin(async move {
|
||||
let (script_hash, runnable_path) = match params.target {
|
||||
InlineScriptTarget::Path(ref path) => {
|
||||
let db = params
|
||||
.conn
|
||||
.as_sql()
|
||||
.ok_or_else(|| {
|
||||
error::Error::InternalErr(
|
||||
"run_inline_script by path requires a SQL connection"
|
||||
.to_string(),
|
||||
)
|
||||
})?
|
||||
.clone();
|
||||
let authed_ref = params.user_db.as_ref().map(|(_, a)| a.to_authed_ref());
|
||||
let user_db_authed =
|
||||
params.user_db.as_ref().zip(authed_ref.as_ref()).map(
|
||||
|((udb, _), ar)| UserDbWithAuthed { db: udb.clone(), authed: ar },
|
||||
);
|
||||
let script_hash_info = get_latest_deployed_hash_for_path(
|
||||
user_db_authed,
|
||||
db,
|
||||
¶ms.workspace_id,
|
||||
path,
|
||||
)
|
||||
.await?;
|
||||
(ScriptHash(script_hash_info.hash), Some(path.clone()))
|
||||
}
|
||||
InlineScriptTarget::Hash(hash) => (ScriptHash(hash), None),
|
||||
};
|
||||
let content_info =
|
||||
get_script_content_by_hash(&script_hash, ¶ms.workspace_id, ¶ms.conn)
|
||||
.await?;
|
||||
let job = MiniPulledJob::new_inline(
|
||||
params.workspace_id,
|
||||
params.args,
|
||||
params.created_by,
|
||||
params.permissioned_as,
|
||||
params.permissioned_as_email,
|
||||
runnable_path,
|
||||
JobKind::Script,
|
||||
Some(script_hash),
|
||||
"inline_run".to_string(),
|
||||
content_info.language,
|
||||
);
|
||||
let mut mem_peak: i32 = -1;
|
||||
let mut canceled_by: Option<CanceledBy> = None;
|
||||
let mut column_order: Option<Vec<String>> = None;
|
||||
let mut new_args: Option<HashMap<String, Box<RawValue>>> = None;
|
||||
let mut occupancy_metrics = OccupancyMetrics::new(Instant::now());
|
||||
let mut has_stream: bool = false;
|
||||
let mut killpill_rx = params.killpill_rx;
|
||||
|
||||
run_language_executor(
|
||||
&job,
|
||||
¶ms.conn,
|
||||
¶ms.client,
|
||||
None,
|
||||
¶ms.job_dir,
|
||||
¶ms.worker_dir,
|
||||
&mut mem_peak,
|
||||
&mut canceled_by,
|
||||
¶ms.base_internal_url,
|
||||
¶ms.worker_name,
|
||||
&mut column_order,
|
||||
&mut new_args,
|
||||
&mut occupancy_metrics,
|
||||
&mut killpill_rx,
|
||||
None,
|
||||
&mut has_stream,
|
||||
content_info.language,
|
||||
&content_info.content,
|
||||
&content_info.envs,
|
||||
&content_info.codebase,
|
||||
&content_info.lockfile,
|
||||
true,
|
||||
)
|
||||
.await
|
||||
})
|
||||
}),
|
||||
};
|
||||
WORKER_INTERNAL_SERVER_INLINE_UTILS
|
||||
.set(utils)
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
|
||||
{
|
||||
"name": "Frontend container",
|
||||
"dockerComposeFile": [
|
||||
"../docker-compose.yml",
|
||||
"../.devcontainer/docker-compose.yml"
|
||||
],
|
||||
"dockerComposeFile": ["../docker-compose.yml", "../.devcontainer/docker-compose.yml"],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": []
|
||||
@@ -14,12 +11,10 @@
|
||||
},
|
||||
"service": "front",
|
||||
"workspaceFolder": "/workspace",
|
||||
"forwardPorts": [
|
||||
8080
|
||||
],
|
||||
"forwardPorts": [8080],
|
||||
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
|
||||
// "shutdownAction": "none",
|
||||
"postCreateCommand": "cd frontend && npm install && npm run generate-backend-client && wget https://github.com/caddyserver/caddy/releases/download/v2.6.0-beta.3/caddy_2.6.0-beta.3_linux_amd64.deb -O /tmp/caddy.deb && sudo dpkg -i /tmp/caddy.deb && rm /tmp/caddy.deb",
|
||||
"postStartCommand": "nohup bash -c 'cd frontend && npm run dev &' && nohup bash -c 'caddy run --config frontend/CaddyfileDev &'",
|
||||
"remoteUser": "node"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -5,4 +5,4 @@
|
||||
"onAutoForward": "openPreview"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -47,6 +47,7 @@ function useLoader(argsGetter: () => Args) {
|
||||
```
|
||||
|
||||
This pattern ensures:
|
||||
|
||||
- State responsibility is clearly owned by `useLoader`
|
||||
- Data flows in one direction (parent → child)
|
||||
- No ambiguity about where state can be modified
|
||||
@@ -59,7 +60,10 @@ For async requests, **always use `resource()` from the Runed library** instead o
|
||||
```typescript
|
||||
import { resource } from 'runed'
|
||||
|
||||
let items = resource(() => args, (args) => YourService.route(args))
|
||||
let items = resource(
|
||||
() => args,
|
||||
(args) => YourService.route(args)
|
||||
)
|
||||
|
||||
// Access loading state
|
||||
items.loading
|
||||
@@ -69,6 +73,7 @@ items.current
|
||||
```
|
||||
|
||||
The `resource()` utility:
|
||||
|
||||
- Automatically handles loading states
|
||||
- Manages async lifecycle
|
||||
- Provides reactive updates when dependencies change
|
||||
@@ -102,6 +107,7 @@ npm run check:fast
|
||||
```
|
||||
|
||||
At the end of a PR to do final validation, you can do the longer one (2s for fast vs 50s for the slow one):
|
||||
|
||||
```bash
|
||||
npm run check
|
||||
```
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"started":true,"success":true,"completed":true,"result":""}
|
||||
{ "started": true, "success": true, "completed": true, "result": "" }
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
|
||||
// Check if we're in node_modules (installed as dependency)
|
||||
if (process.cwd().includes('node_modules')) {
|
||||
console.log('Skipping postinstall - running as dependency');
|
||||
process.exit(0);
|
||||
console.log('Skipping postinstall - running as dependency')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Check if we're in the root project
|
||||
if (process.env.INIT_CWD && process.env.INIT_CWD !== process.cwd()) {
|
||||
console.log('Skipping postinstall - not root project');
|
||||
process.exit(0);
|
||||
console.log('Skipping postinstall - not root project')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Your actual postinstall logic here
|
||||
console.log('Running postinstall for root project');
|
||||
|
||||
console.log('Running postinstall for root project')
|
||||
|
||||
import { x } from 'tar'
|
||||
|
||||
@@ -35,7 +33,6 @@ const response = await fetch(tarUrl)
|
||||
const buffer = await response.arrayBuffer()
|
||||
await fs.promises.writeFile(outputTarPath, Buffer.from(buffer))
|
||||
|
||||
|
||||
// Create extract directory if it doesn't exist
|
||||
try {
|
||||
await fs.promises.mkdir(extractTo, { recursive: true })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
@@ -11,11 +11,17 @@ interface DelegateToGitRepoConfig {
|
||||
* @param value - The value to set (or undefined to remove the field)
|
||||
* @returns The modified YAML script content
|
||||
*/
|
||||
export function updateDelegateToGitRepoField(code: string, fieldName: string, value: string | undefined): string {
|
||||
export function updateDelegateToGitRepoField(
|
||||
code: string,
|
||||
fieldName: string,
|
||||
value: string | undefined
|
||||
): string {
|
||||
const lines = code.split('\n')
|
||||
|
||||
// Find delegate_to_git_repo section
|
||||
const delegateLineIndex = lines.findIndex(line => line.trim().startsWith('delegate_to_git_repo:'))
|
||||
const delegateLineIndex = lines.findIndex((line) =>
|
||||
line.trim().startsWith('delegate_to_git_repo:')
|
||||
)
|
||||
|
||||
if (delegateLineIndex === -1) {
|
||||
// If no delegate section exists and we're setting a value, create the whole section
|
||||
@@ -26,8 +32,8 @@ export function updateDelegateToGitRepoField(code: string, fieldName: string, va
|
||||
}
|
||||
|
||||
// Find the specific field line
|
||||
const fieldLineIndex = lines.findIndex((line, index) =>
|
||||
index > delegateLineIndex && line.trim().startsWith(`${fieldName}:`)
|
||||
const fieldLineIndex = lines.findIndex(
|
||||
(line, index) => index > delegateLineIndex && line.trim().startsWith(`${fieldName}:`)
|
||||
)
|
||||
|
||||
if (fieldLineIndex !== -1) {
|
||||
@@ -52,7 +58,10 @@ export function updateDelegateToGitRepoField(code: string, fieldName: string, va
|
||||
* @param config - Configuration object with fields to update
|
||||
* @returns The modified YAML script content
|
||||
*/
|
||||
export function updateDelegateToGitRepoConfig(code: string, config: DelegateToGitRepoConfig): string {
|
||||
export function updateDelegateToGitRepoConfig(
|
||||
code: string,
|
||||
config: DelegateToGitRepoConfig
|
||||
): string {
|
||||
let updatedCode = code
|
||||
|
||||
// Update each field that's provided
|
||||
@@ -121,7 +130,12 @@ function insertDelegateToGitRepoSection(code: string, config: DelegateToGitRepoC
|
||||
// Find the end of inventories section
|
||||
for (let j = i + 1; j < lines.length; j++) {
|
||||
const nextLine = lines[j].trim()
|
||||
if (nextLine && !nextLine.startsWith('-') && !nextLine.startsWith(' ') && !nextLine.startsWith('#')) {
|
||||
if (
|
||||
nextLine &&
|
||||
!nextLine.startsWith('-') &&
|
||||
!nextLine.startsWith(' ') &&
|
||||
!nextLine.startsWith('#')
|
||||
) {
|
||||
insertionIndex = j
|
||||
break
|
||||
}
|
||||
@@ -150,7 +164,9 @@ function extractDelegateToGitRepoField(code: string, fieldName: string): string
|
||||
const lines = code.split('\n')
|
||||
|
||||
// Find delegate_to_git_repo section
|
||||
const delegateLineIndex = lines.findIndex(line => line.trim().startsWith('delegate_to_git_repo:'))
|
||||
const delegateLineIndex = lines.findIndex((line) =>
|
||||
line.trim().startsWith('delegate_to_git_repo:')
|
||||
)
|
||||
|
||||
if (delegateLineIndex === -1) {
|
||||
return undefined
|
||||
@@ -222,7 +238,9 @@ export function insertAdditionalInventories(code: string, inventoryPaths: string
|
||||
const lines = code.split('\n')
|
||||
|
||||
// Find and update existing additional_inventories section if it exists
|
||||
const additionalInventoriesIndex = lines.findIndex(line => line.trim().startsWith('additional_inventories:'))
|
||||
const additionalInventoriesIndex = lines.findIndex((line) =>
|
||||
line.trim().startsWith('additional_inventories:')
|
||||
)
|
||||
if (additionalInventoriesIndex !== -1) {
|
||||
// Determine the indentation level of the additional_inventories line
|
||||
const sectionLine = lines[additionalInventoriesIndex]
|
||||
@@ -292,7 +310,7 @@ export function insertAdditionalInventories(code: string, inventoryPaths: string
|
||||
|
||||
// Format the new options content
|
||||
const optionsIndentation = ' ' // Standard 2-space indentation under additional_inventories
|
||||
const formattedPaths = inventoryPaths.map(path => `"delegated_git_repository/${path}"`)
|
||||
const formattedPaths = inventoryPaths.map((path) => `"delegated_git_repository/${path}"`)
|
||||
const inlineFormat = `${optionsIndentation}- options: [${formattedPaths.join(', ')}]`
|
||||
|
||||
let newOptionsContent: string[]
|
||||
@@ -302,7 +320,7 @@ export function insertAdditionalInventories(code: string, inventoryPaths: string
|
||||
} else {
|
||||
// Use dash format
|
||||
newOptionsContent = [`${optionsIndentation}- options:`]
|
||||
inventoryPaths.forEach(path => {
|
||||
inventoryPaths.forEach((path) => {
|
||||
newOptionsContent.push(`${optionsIndentation} - "delegated_git_repository/${path}"`)
|
||||
})
|
||||
}
|
||||
@@ -319,29 +337,25 @@ export function insertAdditionalInventories(code: string, inventoryPaths: string
|
||||
}
|
||||
|
||||
// Format the inventory paths based on length
|
||||
const formattedPaths = inventoryPaths.map(path => `"delegated_git_repository/${path}"`)
|
||||
const formattedPaths = inventoryPaths.map((path) => `"delegated_git_repository/${path}"`)
|
||||
const inlineFormat = `options: [${formattedPaths.join(', ')}]`
|
||||
|
||||
let inventorySection: string[]
|
||||
if (inlineFormat.length <= 100) {
|
||||
// Use inline format
|
||||
inventorySection = [
|
||||
'additional_inventories:',
|
||||
` ${inlineFormat}`
|
||||
]
|
||||
inventorySection = ['additional_inventories:', ` ${inlineFormat}`]
|
||||
} else {
|
||||
// Use dash format with each item on new line
|
||||
inventorySection = [
|
||||
'additional_inventories:',
|
||||
' - options:'
|
||||
]
|
||||
inventoryPaths.forEach(path => {
|
||||
inventorySection = ['additional_inventories:', ' - options:']
|
||||
inventoryPaths.forEach((path) => {
|
||||
inventorySection.push(` - "delegated_git_repository/${path}"`)
|
||||
})
|
||||
}
|
||||
|
||||
// Find insertion point (after the complete delegate_to_git_repo section)
|
||||
const delegateLineIndex = lines.findIndex(line => line.trim().startsWith('delegate_to_git_repo:'))
|
||||
const delegateLineIndex = lines.findIndex((line) =>
|
||||
line.trim().startsWith('delegate_to_git_repo:')
|
||||
)
|
||||
if (delegateLineIndex === -1) {
|
||||
// If no delegate_to_git_repo section, insert at the beginning (after document marker if exists)
|
||||
let insertionIndex = 0
|
||||
@@ -381,4 +395,3 @@ export function insertAdditionalInventories(code: string, inventoryPaths: string
|
||||
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
|
||||
+29
-27
@@ -1,29 +1,29 @@
|
||||
export interface ATABootstrapConfig {
|
||||
/** A object you pass in to get callbacks */
|
||||
delegate: {
|
||||
/** The callback which gets called when ATA decides a file needs to be written to your VFS */
|
||||
receivedFile?: (code: string, path: string) => void
|
||||
/** A way to display progress */
|
||||
progress?: (downloaded: number, estimatedTotal: number) => void
|
||||
/** Note: An error message does not mean ATA has stopped! */
|
||||
errorMessage?: (userFacingMessage: string, error: Error) => void
|
||||
/** A callback indicating that ATA actually has work to do */
|
||||
started?: () => void
|
||||
/** The callback when all ATA has finished */
|
||||
finished?: (files: Map<string, string>) => void
|
||||
}
|
||||
/** Passed to fetch as the user-agent */
|
||||
projectName: string
|
||||
/** Your local copy of typescript */
|
||||
depsParser: (code: string) => string[]
|
||||
/** A object you pass in to get callbacks */
|
||||
delegate: {
|
||||
/** The callback which gets called when ATA decides a file needs to be written to your VFS */
|
||||
receivedFile?: (code: string, path: string) => void
|
||||
/** A way to display progress */
|
||||
progress?: (downloaded: number, estimatedTotal: number) => void
|
||||
/** Note: An error message does not mean ATA has stopped! */
|
||||
errorMessage?: (userFacingMessage: string, error: Error) => void
|
||||
/** A callback indicating that ATA actually has work to do */
|
||||
started?: () => void
|
||||
/** The callback when all ATA has finished */
|
||||
finished?: (files: Map<string, string>) => void
|
||||
}
|
||||
/** Passed to fetch as the user-agent */
|
||||
projectName: string
|
||||
/** Your local copy of typescript */
|
||||
depsParser: (code: string) => string[]
|
||||
|
||||
/** If you need a custom version of fetch */
|
||||
fetcher?: typeof fetch
|
||||
/** If you need a custom logger instead of the console global */
|
||||
logger?: Logger
|
||||
/** If you need a custom version of fetch */
|
||||
fetcher?: typeof fetch
|
||||
/** If you need a custom logger instead of the console global */
|
||||
logger?: Logger
|
||||
}
|
||||
|
||||
type ModuleMeta = { state: "loading" }
|
||||
type ModuleMeta = { state: 'loading' }
|
||||
|
||||
/**
|
||||
* The function which starts up type acquisition,
|
||||
@@ -34,11 +34,13 @@ type ModuleMeta = { state: "loading" }
|
||||
* basically exported for tests and should be considered
|
||||
* implementation details by consumers.
|
||||
*/
|
||||
export const setupTypeAcquisition: (config: ATABootstrapConfig) => (initialSourceFile: string) => void
|
||||
export const setupTypeAcquisition: (
|
||||
config: ATABootstrapConfig
|
||||
) => (initialSourceFile: string) => void
|
||||
|
||||
interface Logger {
|
||||
log: (...args: any[]) => void
|
||||
error: (...args: any[]) => void
|
||||
groupCollapsed: (...args: any[]) => void
|
||||
groupEnd: (...args: any[]) => void
|
||||
log: (...args: any[]) => void
|
||||
error: (...args: any[]) => void
|
||||
groupCollapsed: (...args: any[]) => void
|
||||
groupEnd: (...args: any[]) => void
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ import { BROWSER } from 'esm-env'
|
||||
|
||||
export function isCloudHosted(): boolean {
|
||||
return BROWSER && window.location.hostname == 'app.windmill.dev'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
<script lang="ts">
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
export let twBgColor = 'bg-blue-200'
|
||||
export let twTextColor = 'text-secondary'
|
||||
export let tooltip: string | undefined = undefined
|
||||
interface Props {
|
||||
twBgColor?: string;
|
||||
twTextColor?: string;
|
||||
tooltip?: string | undefined;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
twBgColor = 'bg-blue-200',
|
||||
twTextColor = 'text-secondary',
|
||||
tooltip = undefined,
|
||||
children
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<span class="{twBgColor} {twTextColor} text-2xs rounded px-1 whitespace-nowrap">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{#if tooltip && tooltip != ''}
|
||||
<Tooltip>{tooltip}</Tooltip>
|
||||
{/if}
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
import { ExternalLink } from 'lucide-svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let link: string | undefined = undefined
|
||||
interface Props {
|
||||
link?: string | undefined
|
||||
class?: string
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { link = undefined, class: c = '', children }: Props = $props()
|
||||
</script>
|
||||
|
||||
<div class={twMerge('text-xs text-primary font-normal', $$props.class)}>
|
||||
<slot />
|
||||
<div class={twMerge('text-xs text-primary font-normal', c)}>
|
||||
{@render children?.()}
|
||||
{#if link}
|
||||
<a href={link} target="_blank" class="whitespace-nowrap"
|
||||
>Learn more <ExternalLink size={12} class="inline-block" /></a
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
import { Hourglass } from 'lucide-svelte'
|
||||
import WaitTimeWarning from './common/waitTimeWarning/WaitTimeWarning.svelte'
|
||||
|
||||
export let duration_ms: number
|
||||
export let self_wait_time_ms: number | undefined = undefined
|
||||
export let aggregate_wait_time_ms: number | undefined = undefined
|
||||
interface Props {
|
||||
duration_ms: number;
|
||||
self_wait_time_ms?: number | undefined;
|
||||
aggregate_wait_time_ms?: number | undefined;
|
||||
}
|
||||
|
||||
let { duration_ms, self_wait_time_ms = undefined, aggregate_wait_time_ms = undefined }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
|
||||
import FieldHeader from './FieldHeader.svelte'
|
||||
|
||||
export let schema: Schema | { [key: string]: unknown } | undefined
|
||||
interface Props {
|
||||
schema: Schema | { [key: string]: unknown } | undefined;
|
||||
}
|
||||
|
||||
let { schema }: Props = $props();
|
||||
</script>
|
||||
|
||||
<ul class="my-2">
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
let divEl: HTMLDivElement | null = null
|
||||
let editor: meditor.IStandaloneCodeEditor
|
||||
|
||||
export let code: string = ''
|
||||
interface Props {
|
||||
code?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
let { code = '', class: c = '' }: Props = $props()
|
||||
|
||||
async function loadMonaco() {
|
||||
editor = meditor.create(divEl as HTMLDivElement, {
|
||||
@@ -43,4 +48,4 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div bind:this={divEl} class="{$$props.class ?? ''} editor"></div>
|
||||
<div bind:this={divEl} class="{c ?? ''} editor"></div>
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
}
|
||||
|
||||
const lang = $derived(highlightLanguage ?? getLang(language))
|
||||
// Cast needed: svelte-highlight types not updated for Svelte 5 snippets
|
||||
const HighlightWithSnippet = Highlight as any
|
||||
</script>
|
||||
|
||||
<HighlightTheme />
|
||||
@@ -134,9 +136,11 @@
|
||||
{#if !lines}
|
||||
<Highlight class="nowrap {className}" language={lang} {code} />
|
||||
{:else}
|
||||
<Highlight class="nowrap {className}" language={lang} {code} let:highlighted>
|
||||
<LineNumbers {highlighted} />
|
||||
</Highlight>
|
||||
<HighlightWithSnippet class="nowrap {className}" language={lang} {code} >
|
||||
{#snippet children({ highlighted })}
|
||||
<LineNumbers {highlighted} />
|
||||
{/snippet}
|
||||
</HighlightWithSnippet>
|
||||
{/if}
|
||||
{:else}
|
||||
<pre class="overflow-auto max-h-screen text-xs {className}"
|
||||
|
||||
@@ -7,8 +7,12 @@
|
||||
import Cell from './table/Cell.svelte'
|
||||
import Row from './table/Row.svelte'
|
||||
|
||||
export let inputTransforms: Record<string, InputTransform>
|
||||
$: entries = Object.entries(inputTransforms)
|
||||
interface Props {
|
||||
inputTransforms: Record<string, InputTransform>;
|
||||
}
|
||||
|
||||
let { inputTransforms }: Props = $props();
|
||||
let entries = $derived(Object.entries(inputTransforms))
|
||||
</script>
|
||||
|
||||
{#if entries.length}
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
import { displayDate } from '$lib/utils'
|
||||
import { Hourglass } from 'lucide-svelte'
|
||||
|
||||
export let type: FlowStatusModule['type']
|
||||
export let scheduled_for: Date | undefined
|
||||
export let skipped: boolean = false
|
||||
interface Props {
|
||||
type: FlowStatusModule['type'];
|
||||
scheduled_for: Date | undefined;
|
||||
skipped?: boolean;
|
||||
}
|
||||
|
||||
let { type, scheduled_for, skipped = false }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if type == 'WaitingForEvents'}
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
<script lang="ts">
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
export let title: string
|
||||
export let tooltip: string = ''
|
||||
export let documentationLink: string | undefined = undefined
|
||||
export let primary: boolean = true
|
||||
export let childrenWrapperDivClasses: string = ''
|
||||
interface Props {
|
||||
title: string;
|
||||
tooltip?: string;
|
||||
documentationLink?: string | undefined;
|
||||
primary?: boolean;
|
||||
childrenWrapperDivClasses?: string;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
title,
|
||||
tooltip = '',
|
||||
documentationLink = undefined,
|
||||
primary = true,
|
||||
childrenWrapperDivClasses = '',
|
||||
children
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row flex-wrap justify-between items-center pb-2 my-4 mr-2 min-h-16">
|
||||
@@ -31,9 +43,9 @@
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
{#if $$slots.default}
|
||||
{#if children}
|
||||
<div class="my-2 {childrenWrapperDivClasses}">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -79,12 +79,14 @@
|
||||
<p class="text-primary text-sm">No permission changes recorded yet</p>
|
||||
{:else}
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
<th>Changed By</th>
|
||||
<th>Change Type</th>
|
||||
<th>Affected</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th>Changed By</th>
|
||||
<th>Change Type</th>
|
||||
<th>Affected</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody>
|
||||
{#each history as change}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
const SIDE = ['auto', 'top', 'bottom', 'left', 'right'] as const
|
||||
const ALIGN = ['start', 'end'] as const
|
||||
export type PopoverPlacement = `${typeof SIDE[number]}` | `${typeof SIDE[number]}-${typeof ALIGN[number]}`
|
||||
export type PopoverPlacement =
|
||||
| `${(typeof SIDE)[number]}`
|
||||
| `${(typeof SIDE)[number]}-${(typeof ALIGN)[number]}`
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
<script lang="ts">
|
||||
export let required: boolean
|
||||
export let detail = ''
|
||||
interface Props {
|
||||
required: boolean
|
||||
detail?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
let { required, detail = '', class: c = '' }: Props = $props()
|
||||
</script>
|
||||
|
||||
{#if required}
|
||||
<span class="text-red-500 dark:text-red-400 text-sm font-normal {$$props.class}">*</span>
|
||||
<span class="text-red-500 dark:text-red-400 text-sm font-normal {c}">*</span>
|
||||
{:else if detail || detail != ''}
|
||||
<span class="text-sm text-primary ml-2 font-normal {$$props.class}"
|
||||
<span class="text-sm text-primary ml-2 font-normal {c}"
|
||||
>({detail != '' ? `${detail}` : ''})</span
|
||||
>
|
||||
{/if}
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
import type { SchemaProperty } from '$lib/common'
|
||||
import Badge from './common/badge/Badge.svelte'
|
||||
|
||||
export let property: SchemaProperty
|
||||
interface Props {
|
||||
property: SchemaProperty;
|
||||
}
|
||||
|
||||
let { property }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row flex-wrap gap-1">
|
||||
|
||||
@@ -2,14 +2,19 @@
|
||||
import { onMount, onDestroy } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
let isAtBottom: boolean = false
|
||||
let isScrollable = false
|
||||
let isAtBottom: boolean = $state(false)
|
||||
let isScrollable = $state(false)
|
||||
|
||||
export let id: string | null | undefined = undefined
|
||||
export let scrollableClass: string = ''
|
||||
export let shiftedShadow: boolean = false
|
||||
interface Props {
|
||||
id?: string | null | undefined
|
||||
scrollableClass?: string
|
||||
shiftedShadow?: boolean
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { id = undefined, scrollableClass = '', shiftedShadow = false, children }: Props = $props()
|
||||
let mutationObserver: MutationObserver
|
||||
let el: HTMLDivElement
|
||||
let el: HTMLDivElement | undefined = $state()
|
||||
|
||||
function handleScroll(event) {
|
||||
const scrollableElement = event.target
|
||||
@@ -33,7 +38,7 @@
|
||||
}
|
||||
|
||||
export function scrollIntoView(top: number) {
|
||||
el.scrollTo({ top, behavior: 'smooth' })
|
||||
el?.scrollTo({ top, behavior: 'smooth' })
|
||||
}
|
||||
onMount(() => {
|
||||
observeScrollability(el)
|
||||
@@ -45,8 +50,8 @@
|
||||
</script>
|
||||
|
||||
<div {id} class={twMerge('relative pb-1', scrollableClass)}>
|
||||
<div bind:this={el} on:scroll={handleScroll} class="w-full h-full overflow-y-auto">
|
||||
<slot />
|
||||
<div bind:this={el} onscroll={handleScroll} class="w-full h-full overflow-y-auto">
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{#if !isAtBottom && isScrollable}
|
||||
<div
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
import { Pen } from 'lucide-svelte'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
|
||||
export let value: string
|
||||
export let disabled = false
|
||||
interface Props {
|
||||
value: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
let { value = $bindable(), disabled = false }: Props = $props();
|
||||
|
||||
function blur(e: KeyboardEvent) {
|
||||
e.key === 'Enter' && (e?.target as any)?.blur()
|
||||
|
||||
@@ -1,37 +1,51 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
interface Props {
|
||||
paginated?: boolean
|
||||
currentPage?: number
|
||||
showNext?: boolean
|
||||
class?: string
|
||||
header_row?: import('svelte').Snippet
|
||||
body?: import('svelte').Snippet
|
||||
onNext?: () => void
|
||||
onPrevious?: () => void
|
||||
}
|
||||
|
||||
export let paginated = false
|
||||
export let currentPage = 1
|
||||
export let showNext = true
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let {
|
||||
paginated = false,
|
||||
currentPage = 1,
|
||||
showNext = true,
|
||||
class: className = '',
|
||||
header_row,
|
||||
body,
|
||||
onNext,
|
||||
onPrevious
|
||||
}: Props = $props()
|
||||
</script>
|
||||
|
||||
<!-- A custom table
|
||||
<!-- A custom table
|
||||
- the first slot should be a <tr>, containing th elements
|
||||
- the second slot should be a <tbody>, containing th elements
|
||||
-->
|
||||
<div class="flex flex-col {$$props.class} min-w-full">
|
||||
<div class="flex flex-col {className} min-w-full">
|
||||
<div class="inline-block min-w-full py-2 align-middle">
|
||||
<table class="table-custom min-w-full table-auto divide-y">
|
||||
<thead>
|
||||
<slot name="header-row" />
|
||||
{@render header_row?.()}
|
||||
</thead>
|
||||
<slot name="body" />
|
||||
{@render body?.()}
|
||||
</table>
|
||||
</div>
|
||||
{#if paginated}
|
||||
<div class="sticky flex flex-row-reverse text-primary mb-6">
|
||||
<button
|
||||
class="ml-2 drop-shadow-md {showNext ? 'visible' : 'invisible'}"
|
||||
on:click={() => dispatch('next')}
|
||||
onclick={() => onNext?.()}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<button
|
||||
class="mx-2 drop-shadow-md {currentPage === 1 ? 'hidden' : ''}"
|
||||
on:click={() => dispatch('previous')}
|
||||
onclick={() => onPrevious?.()}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
|
||||
@@ -4,9 +4,19 @@
|
||||
import { gfmPlugin } from 'svelte-exmarkdown/gfm'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let documentationLink: string | undefined = undefined
|
||||
export let markdownTooltip: string | undefined = undefined
|
||||
export let customBgClass: string | undefined = undefined
|
||||
interface Props {
|
||||
documentationLink?: string | undefined;
|
||||
markdownTooltip?: string | undefined;
|
||||
customBgClass?: string | undefined;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
documentationLink = undefined,
|
||||
markdownTooltip = undefined,
|
||||
customBgClass = undefined,
|
||||
children
|
||||
}: Props = $props();
|
||||
const plugins = [gfmPlugin()]
|
||||
</script>
|
||||
|
||||
@@ -21,7 +31,7 @@
|
||||
<Markdown md={markdownTooltip} {plugins} />
|
||||
</div>
|
||||
{:else}
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{/if}
|
||||
|
||||
{#if documentationLink}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
let uptodate: string | undefined = undefined
|
||||
let uptodate: string | undefined = $state(undefined)
|
||||
|
||||
async function loadVersion() {
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { urlize } from '$lib/utils'
|
||||
|
||||
export let text: string
|
||||
$: parsed = text ? urlize(text, 'html') : ''
|
||||
interface Props {
|
||||
text: string;
|
||||
}
|
||||
|
||||
let { text }: Props = $props();
|
||||
let parsed = $derived(text ? urlize(text, 'html') : '')
|
||||
</script>
|
||||
|
||||
{@html parsed}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { SettingsService } from '$lib/gen'
|
||||
|
||||
let version = ''
|
||||
let version = $state('')
|
||||
|
||||
loadVersion()
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { WorkerService } from '$lib/gen'
|
||||
import { Alert } from './common'
|
||||
|
||||
let ips: string[] | undefined = undefined
|
||||
let ips: string[] | undefined = $state(undefined)
|
||||
|
||||
WorkerService.listWorkers({ pingSince: 300 }).then((workers) => {
|
||||
ips = [
|
||||
|
||||
@@ -7,23 +7,15 @@
|
||||
import TimelineBar from './TimelineBar.svelte'
|
||||
import type { WorkflowStatus } from '$lib/gen'
|
||||
|
||||
export let flow_status: Record<string, WorkflowStatus>
|
||||
export let flowDone = false
|
||||
interface Props {
|
||||
flow_status: Record<string, WorkflowStatus>;
|
||||
flowDone?: boolean;
|
||||
}
|
||||
|
||||
$: min = Object.values(flow_status).reduce(
|
||||
(a, b) => Math.min(a, b.scheduled_for ? new Date(b.scheduled_for).getTime() : Infinity),
|
||||
Infinity
|
||||
)
|
||||
$: max = flowDone
|
||||
? Object.values(flow_status).reduce(
|
||||
(a, b) =>
|
||||
Math.max(a, b.started_at ? new Date(b.started_at).getTime() + (b.duration_ms ?? 0) : 0),
|
||||
0
|
||||
)
|
||||
: undefined
|
||||
$: total = flowDone && max ? max - min : now - min
|
||||
let { flow_status, flowDone = false }: Props = $props();
|
||||
|
||||
let now = getDbClockNow().getTime()
|
||||
|
||||
let now = $state(getDbClockNow().getTime())
|
||||
|
||||
let interval = setInterval((x) => {
|
||||
if (!max) {
|
||||
@@ -37,6 +29,18 @@
|
||||
onDestroy(() => {
|
||||
interval && clearInterval(interval)
|
||||
})
|
||||
let min = $derived(Object.values(flow_status).reduce(
|
||||
(a, b) => Math.min(a, b.scheduled_for ? new Date(b.scheduled_for).getTime() : Infinity),
|
||||
Infinity
|
||||
))
|
||||
let max = $derived(flowDone
|
||||
? Object.values(flow_status).reduce(
|
||||
(a, b) =>
|
||||
Math.max(a, b.started_at ? new Date(b.started_at).getTime() + (b.duration_ms ?? 0) : 0),
|
||||
0
|
||||
)
|
||||
: undefined)
|
||||
let total = $derived(flowDone && max ? max - min : now - min)
|
||||
</script>
|
||||
|
||||
{#if flow_status}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { default as AppButton } from './AppButton.svelte'
|
||||
export { default as AppForm } from './AppForm.svelte'
|
||||
export { default as AppFormButton } from './AppFormButton.svelte'
|
||||
export { default as AppFormButton } from './AppFormButton.svelte'
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function executeRunnable(
|
||||
id: string,
|
||||
requestBody: ExecuteComponentData['requestBody'],
|
||||
inlineScriptOverride?: InlineScript,
|
||||
queryParams?: Record<string, any>,
|
||||
queryParams?: Record<string, any>
|
||||
) {
|
||||
let appPath = defaultIfEmptyString(path, `u/${username ?? 'unknown'}/newapp`)
|
||||
if (isRunnableByName(runnable)) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resourceOnly: boolean = true
|
||||
let resourceOnly: boolean = $state(true)
|
||||
</script>
|
||||
|
||||
<Alert type="info" title="Configurations">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { base } from "$lib/base"
|
||||
import { workspaceStore } from "$lib/stores"
|
||||
import { get } from "svelte/store"
|
||||
import { base } from '$lib/base'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { get } from 'svelte/store'
|
||||
|
||||
export function computeSecretUrl(secretUrl: string) {
|
||||
return `${window.location.origin}${base}/public/${get(workspaceStore)}/${secretUrl}`
|
||||
return `${window.location.origin}${base}/public/${get(workspaceStore)}/${secretUrl}`
|
||||
}
|
||||
|
||||
@@ -1,37 +1,35 @@
|
||||
import type { StaticAppInput } from "../inputType"
|
||||
import type { StaticAppInput } from '../inputType'
|
||||
import { Sha256 } from '@aws-crypto/sha256-js'
|
||||
|
||||
export function collectStaticFields(
|
||||
fields: Record<string, StaticAppInput>
|
||||
) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(fields ?? {})
|
||||
.filter(([k, v]) => v.type == 'static')
|
||||
.map(([k, v]) => {
|
||||
return [k, v['value']]
|
||||
})
|
||||
)
|
||||
export function collectStaticFields(fields: Record<string, StaticAppInput>) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(fields ?? {})
|
||||
.filter(([k, v]) => v.type == 'static')
|
||||
.map(([k, v]) => {
|
||||
return [k, v['value']]
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export type TriggerableV2 = {
|
||||
static_inputs: Record<string, any>
|
||||
one_of_inputs?: Record<string, any[] | undefined>
|
||||
allow_user_resources?: string[]
|
||||
static_inputs: Record<string, any>
|
||||
one_of_inputs?: Record<string, any[] | undefined>
|
||||
allow_user_resources?: string[]
|
||||
}
|
||||
|
||||
export async function hash(message) {
|
||||
try {
|
||||
const msgUint8 = new TextEncoder().encode(message) // encode as (utf-8) Uint8Array
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8) // hash the message
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer)) // convert buffer to byte array
|
||||
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string
|
||||
return hashHex
|
||||
} catch {
|
||||
//subtle not available, trying pure js
|
||||
const hash = new Sha256()
|
||||
hash.update(message ?? '')
|
||||
const result = Array.from(await hash.digest())
|
||||
const hex = result.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string
|
||||
return hex
|
||||
}
|
||||
}
|
||||
try {
|
||||
const msgUint8 = new TextEncoder().encode(message) // encode as (utf-8) Uint8Array
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8) // hash the message
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer)) // convert buffer to byte array
|
||||
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string
|
||||
return hashHex
|
||||
} catch {
|
||||
//subtle not available, trying pure js
|
||||
const hash = new Sha256()
|
||||
hash.update(message ?? '')
|
||||
const result = Array.from(await hash.digest())
|
||||
const hex = result.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string
|
||||
return hex
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export const DEFAULT_CODES: Partial<
|
||||
| 'snowflake'
|
||||
| 'mssql'
|
||||
| 'bigquery'
|
||||
| 'oracledb',
|
||||
| 'oracledb',
|
||||
string
|
||||
>
|
||||
>
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import type { Schema } from '$lib/common'
|
||||
import { ScriptService } from '$lib/gen'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { isRunnableByName, isRunnableByPath, type AppInputs, type InlineScript, type Runnable, type RunnableByName, type CtxInput } from '../../inputType'
|
||||
import {
|
||||
isRunnableByName,
|
||||
isRunnableByPath,
|
||||
type AppInputs,
|
||||
type InlineScript,
|
||||
type Runnable,
|
||||
type RunnableByName,
|
||||
type CtxInput
|
||||
} from '../../inputType'
|
||||
import type { GridItem, HiddenRunnable } from '../../types'
|
||||
import { fieldTypeToTsType, schemaToInputsSpec } from '../../utils'
|
||||
import type { AppComponent } from '../component'
|
||||
@@ -14,7 +22,11 @@ export interface AppScriptsList {
|
||||
// When the schema is loaded, we need to update the inputs spec
|
||||
// in order to render the inputs the component panel
|
||||
// Note: fields can include CtxInput for raw apps
|
||||
export function computeFields(schema: Schema, defaultUserInput: boolean, fields: AppInputs | Record<string, CtxInput | AppInputs[string]>) {
|
||||
export function computeFields(
|
||||
schema: Schema,
|
||||
defaultUserInput: boolean,
|
||||
fields: AppInputs | Record<string, CtxInput | AppInputs[string]>
|
||||
) {
|
||||
let schemaCopy: Schema = JSON.parse(JSON.stringify(schema))
|
||||
|
||||
const result = {}
|
||||
|
||||
@@ -33,9 +33,13 @@ export function isFrontend(runnable: Runnable): boolean {
|
||||
}
|
||||
|
||||
export function isTriggerable(componentType: string): boolean {
|
||||
return ['buttoncomponent', 'formbuttoncomponent', 'formcomponent', 'steppercomponent', 'chatcomponent'].includes(
|
||||
componentType
|
||||
)
|
||||
return [
|
||||
'buttoncomponent',
|
||||
'formbuttoncomponent',
|
||||
'formcomponent',
|
||||
'steppercomponent',
|
||||
'chatcomponent'
|
||||
].includes(componentType)
|
||||
}
|
||||
|
||||
export function isTriggerOnAppLoad(appComponent: AppComponent): boolean {
|
||||
|
||||
@@ -10,7 +10,6 @@ const Breakpoints = {
|
||||
|
||||
export const moveMode = writable<'move' | 'insert'>('move')
|
||||
|
||||
|
||||
const WIDE_GRID_COLUMNS = 12 as const
|
||||
const NARROW_GRID_COLUMNS = 3 as const
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getRowsCount } from "./other";
|
||||
import { getRowsCount } from './other'
|
||||
|
||||
export function getContainerHeight(items, yPerPx, cols) {
|
||||
return getRowsCount(items, cols) * yPerPx;
|
||||
return getRowsCount(items, cols) * yPerPx
|
||||
}
|
||||
|
||||
@@ -1,130 +1,130 @@
|
||||
@import 'tailwindcss/base';
|
||||
|
||||
.svelte-select {
|
||||
@apply border rounded box-border h-10 relative flex items-center px-4 py-0 bg-white m-0 w-full
|
||||
@apply border rounded box-border h-10 relative flex items-center px-4 py-0 bg-white m-0 w-full
|
||||
hover:border-gray-400;
|
||||
}
|
||||
|
||||
.svelte-select input {
|
||||
@apply cursor-default border-none text-tertiary h-10 leading-10 px-4 py-0 bg-transparent text-sm absolute left-0 m-0 w-full
|
||||
@apply cursor-default border-none text-tertiary h-10 leading-10 px-4 py-0 bg-transparent text-sm absolute left-0 m-0 w-full
|
||||
focus:outline-none hover:border-gray-400;
|
||||
}
|
||||
|
||||
.svelte-select.focused {
|
||||
@apply border-blue-600;
|
||||
@apply border-blue-600;
|
||||
}
|
||||
|
||||
.svelte-select.disabled {
|
||||
@apply bg-gray-200 border-gray-200 text-tertiary;
|
||||
@apply bg-gray-200 border-gray-200 text-tertiary;
|
||||
}
|
||||
|
||||
.svelte-select.disabled input {
|
||||
@apply placeholder:text-gray-400 placeholder:opacity-100;
|
||||
@apply placeholder:text-gray-400 placeholder:opacity-100;
|
||||
}
|
||||
|
||||
.svelte-select .selected-item {
|
||||
@apply leading-10 h-10 overflow-x-hidden pr-5
|
||||
@apply leading-10 h-10 overflow-x-hidden pr-5
|
||||
focus:outline-none;
|
||||
}
|
||||
|
||||
.svelte-select .icons {
|
||||
@apply absolute flex items-center right-0 translate-y-0 text-gray-200 pointer-events-none top-0 bottom-0;
|
||||
@apply absolute flex items-center right-0 translate-y-0 text-gray-200 pointer-events-none top-0 bottom-0;
|
||||
}
|
||||
|
||||
.svelte-select .icons > * {
|
||||
@apply transition-colors ease-in-out duration-200;
|
||||
@apply transition-colors ease-in-out duration-200;
|
||||
}
|
||||
|
||||
.svelte-select .clear-select {
|
||||
@apply pointer-events-auto;
|
||||
@apply pointer-events-auto;
|
||||
}
|
||||
|
||||
.svelte-select.focused .icons,
|
||||
.svelte-select .chevron:hover,
|
||||
.svelte-select .clear-select:hover {
|
||||
@apply text-tertiary;
|
||||
@apply text-tertiary;
|
||||
}
|
||||
|
||||
.svelte-select .clear-select {
|
||||
@apply px-2 h-5 text-gray-300 flex-none w-9;
|
||||
@apply px-2 h-5 text-gray-300 flex-none w-9;
|
||||
}
|
||||
|
||||
.svelte-select .chevron {
|
||||
@apply flex pt-0 pr-2 pl-2 border-l-2 w-9 h-5 text-gray-300;
|
||||
@apply flex pt-0 pr-2 pl-2 border-l-2 w-9 h-5 text-gray-300;
|
||||
}
|
||||
|
||||
.svelte-select.multi {
|
||||
@apply pr-9 pl-4 h-auto flex-wrap items-stretch;
|
||||
@apply pr-9 pl-4 h-auto flex-wrap items-stretch;
|
||||
}
|
||||
|
||||
.svelte-select.multi input {
|
||||
@apply p-0 relative m-0;
|
||||
@apply p-0 relative m-0;
|
||||
}
|
||||
|
||||
.svelte-select.error {
|
||||
@apply border-red-500 bg-white;
|
||||
@apply border-red-500 bg-white;
|
||||
}
|
||||
|
||||
.a11y-text {
|
||||
@apply sr-only;
|
||||
@apply sr-only;
|
||||
}
|
||||
|
||||
.list {
|
||||
@apply shadow-md rounded-sm max-h-64 overflow-y-auto bg-white border-none absolute z-10 w-full left-0 right-0;
|
||||
@apply shadow-md rounded-sm max-h-64 overflow-y-auto bg-white border-none absolute z-10 w-full left-0 right-0;
|
||||
}
|
||||
|
||||
.list .list-group-title {
|
||||
@apply text-gray-400 cursor-default text-sm font-medium h-10 leading-10 px-5 overflow-ellipsis whitespace-nowrap uppercase;
|
||||
@apply text-gray-400 cursor-default text-sm font-medium h-10 leading-10 px-5 overflow-ellipsis whitespace-nowrap uppercase;
|
||||
}
|
||||
|
||||
.list .empty {
|
||||
@apply text-center py-5 text-tertiary;
|
||||
@apply text-center py-5 text-tertiary;
|
||||
}
|
||||
|
||||
.item {
|
||||
@apply cursor-default h-10 leading-10 px-5 text-gray-800 overflow-ellipsis overflow-hidden whitespace-nowrap;
|
||||
@apply cursor-default h-10 leading-10 px-5 text-gray-800 overflow-ellipsis overflow-hidden whitespace-nowrap;
|
||||
}
|
||||
|
||||
.item.group-item {
|
||||
@apply px-10;
|
||||
@apply px-10;
|
||||
}
|
||||
|
||||
.item:active {
|
||||
@apply bg-blue-200;
|
||||
@apply bg-blue-200;
|
||||
}
|
||||
|
||||
.item.active {
|
||||
@apply bg-blue-600 text-white;
|
||||
@apply bg-blue-600 text-white;
|
||||
}
|
||||
|
||||
.item.not-selectable {
|
||||
@apply text-gray-300;
|
||||
@apply text-gray-300;
|
||||
}
|
||||
|
||||
.item.first {
|
||||
@apply rounded-t-sm;
|
||||
@apply rounded-t-sm;
|
||||
}
|
||||
|
||||
.item.hover:not(.active) {
|
||||
@apply bg-blue-100;
|
||||
@apply bg-blue-100;
|
||||
}
|
||||
|
||||
.multi input {
|
||||
flex: 1 1 40px;
|
||||
flex: 1 1 40px;
|
||||
}
|
||||
|
||||
.multi-item {
|
||||
@apply bg-gray-100 mt-1 border border-gray-200 rounded-sm h-8 leading-8 flex cursor-default pr-1 pl-1 max-w-full items-center mr-1 overflow-hidden overflow-ellipsis whitespace-nowrap;
|
||||
@apply bg-gray-100 mt-1 border border-gray-200 rounded-sm h-8 leading-8 flex cursor-default pr-1 pl-1 max-w-full items-center mr-1 overflow-hidden overflow-ellipsis whitespace-nowrap;
|
||||
}
|
||||
|
||||
.multi-item.disabled {
|
||||
@apply hover:bg-gray-300 hover:text-tertiary;
|
||||
@apply hover:bg-gray-300 hover:text-tertiary;
|
||||
}
|
||||
|
||||
.multi-item-clear {
|
||||
@apply flex items-center justify-center w-5;
|
||||
@apply flex items-center justify-center w-5;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
@apply list-none;
|
||||
}
|
||||
@apply list-none;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,14 @@ import type { Schema } from '$lib/common'
|
||||
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { type AppComponent } from './editor/component'
|
||||
import { isRunnableByName, isRunnableByPath, type AppInput, type InputType, type ResultAppInput, type StaticAppInput } from './inputType'
|
||||
import {
|
||||
isRunnableByName,
|
||||
isRunnableByPath,
|
||||
type AppInput,
|
||||
type InputType,
|
||||
type ResultAppInput,
|
||||
type StaticAppInput
|
||||
} from './inputType'
|
||||
import type { Output } from './rx'
|
||||
import type {
|
||||
App,
|
||||
@@ -133,7 +140,7 @@ export function isScriptByNameDefined(appInput: AppInput | undefined): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
if (appInput.type === 'runnable' && isRunnableByName(appInput.runnable)) {
|
||||
if (appInput.type === 'runnable' && isRunnableByName(appInput.runnable)) {
|
||||
return appInput.runnable?.name != undefined
|
||||
}
|
||||
|
||||
@@ -402,10 +409,7 @@ export function getAllScriptNames(app: App): string[] {
|
||||
const names = (allItems(app.grid, app?.subgrids) ?? []).reduce((acc, gridItem: GridItem) => {
|
||||
const { componentInput } = gridItem.data
|
||||
|
||||
if (
|
||||
componentInput?.type === 'runnable' &&
|
||||
isRunnableByName(componentInput.runnable)
|
||||
) {
|
||||
if (componentInput?.type === 'runnable' && isRunnableByName(componentInput.runnable)) {
|
||||
acc.push(componentInput.runnable.name)
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ export function formatAssetKind(asset: {
|
||||
case 'datatable':
|
||||
return 'Data table'
|
||||
}
|
||||
return 'Unknown'
|
||||
}
|
||||
|
||||
export function formatAssetAccessType(accessType: AssetUsageAccessType | undefined) {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<script lang="ts">
|
||||
export let notificationCount = 0
|
||||
export let notificationLimit: number | undefined = undefined
|
||||
interface Props {
|
||||
notificationCount?: number;
|
||||
notificationLimit?: number | undefined;
|
||||
}
|
||||
|
||||
let { notificationCount = 0, notificationLimit = undefined }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if notificationCount > 0}
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
<script lang="ts">
|
||||
import AnimatedButtonInner from './AnimatedButtonInner.svelte'
|
||||
export let marginWidth = '2px'
|
||||
export let animationDuration = '2s'
|
||||
export let baseRadius = '4px'
|
||||
export let animate = true
|
||||
export let wrapperClasses = ''
|
||||
export let ringColor = 'transparent'
|
||||
export let darkMode = false
|
||||
interface Props {
|
||||
marginWidth?: string;
|
||||
animationDuration?: string;
|
||||
baseRadius?: string;
|
||||
animate?: boolean;
|
||||
wrapperClasses?: string;
|
||||
ringColor?: string;
|
||||
darkMode?: boolean;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
marginWidth = '2px',
|
||||
animationDuration = '2s',
|
||||
baseRadius = '4px',
|
||||
animate = true,
|
||||
wrapperClasses = '',
|
||||
ringColor = 'transparent',
|
||||
darkMode = false,
|
||||
children
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if animate}
|
||||
@@ -19,10 +33,10 @@
|
||||
{ringColor}
|
||||
{darkMode}
|
||||
>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</AnimatedButtonInner>
|
||||
{:else}
|
||||
<div class={wrapperClasses}>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,27 +1,41 @@
|
||||
<script lang="ts">
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import DarkModeObserver from '$lib/components/DarkModeObserver.svelte'
|
||||
export let marginWidth = '2px'
|
||||
export let animationDuration = '2s'
|
||||
export let baseRadius = '4px'
|
||||
export let animate = true
|
||||
export let wrapperClasses = ''
|
||||
export let ringColor = 'transparent'
|
||||
export let darkMode = false
|
||||
interface Props {
|
||||
marginWidth?: string;
|
||||
animationDuration?: string;
|
||||
baseRadius?: string;
|
||||
animate?: boolean;
|
||||
wrapperClasses?: string;
|
||||
ringColor?: string;
|
||||
darkMode?: boolean;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
marginWidth = '2px',
|
||||
animationDuration = '2s',
|
||||
baseRadius = '4px',
|
||||
animate = true,
|
||||
wrapperClasses = '',
|
||||
ringColor = 'transparent',
|
||||
darkMode = $bindable(false),
|
||||
children
|
||||
}: Props = $props();
|
||||
|
||||
const gradientColors = {
|
||||
light: ['#d6e5ff', '#0073ff', '#5aa2fa', '#0272fa', '#d6e5ff'],
|
||||
dark: ['#0469db', '#15498a', '#031ea3', '#0073ff', '#0469db']
|
||||
}
|
||||
|
||||
let clientWidth = 0
|
||||
let clientHeight = 0
|
||||
let clientWidth = $state(0)
|
||||
let clientHeight = $state(0)
|
||||
|
||||
$: circleRadius = Math.ceil(
|
||||
let circleRadius = $derived(Math.ceil(
|
||||
Math.sqrt(clientWidth * clientWidth + clientHeight * clientHeight) / 2
|
||||
)
|
||||
))
|
||||
|
||||
$: gradientString = `from 0deg, ${gradientColors[darkMode ? 'dark' : 'light'].join(', ')}`
|
||||
let gradientString = $derived(`from 0deg, ${gradientColors[darkMode ? 'dark' : 'light'].join(', ')}`)
|
||||
</script>
|
||||
|
||||
<DarkModeObserver bind:darkMode />
|
||||
@@ -33,7 +47,7 @@
|
||||
bind:clientWidth
|
||||
bind:clientHeight
|
||||
>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
<script>
|
||||
export let pulseDuration = 2
|
||||
export let numberOfPulses = 3
|
||||
export let scale = 1.2
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
pulseDuration?: number;
|
||||
numberOfPulses?: number;
|
||||
scale?: number;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let isPulsing = false
|
||||
let pulseCount = 1
|
||||
let {
|
||||
pulseDuration = 2,
|
||||
numberOfPulses = 3,
|
||||
scale = 1.2,
|
||||
children
|
||||
}: Props = $props();
|
||||
|
||||
let isPulsing = $state(false)
|
||||
let pulseCount = $state(1)
|
||||
|
||||
export function triggerPulse(count) {
|
||||
if (pulseCount < 1) return
|
||||
@@ -20,7 +30,7 @@
|
||||
|
||||
<div class="relative">
|
||||
<div>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{#each Array(numberOfPulses) as _, i}
|
||||
<div
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
<script lang="ts">
|
||||
export let color: 'light' | 'dark' | undefined = 'light'
|
||||
export let border: boolean = false
|
||||
interface Props {
|
||||
color?: 'light' | 'dark' | undefined;
|
||||
border?: boolean;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
$: colorClasses = {
|
||||
let { color = 'light', border = false, children }: Props = $props();
|
||||
|
||||
let colorClasses = $derived({
|
||||
light: 'text-primary bg-surface hover:bg-surface-hover text-primary',
|
||||
dark: 'text-primary hover:bg-surface-hover-dark text-primary'
|
||||
}[color ?? 'light']
|
||||
}[color ?? 'light'])
|
||||
</script>
|
||||
|
||||
<div class="rounded-full p-1 {colorClasses} {border ? 'border border-tertiary' : ''}">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { Value } from "$lib/utils"
|
||||
import type { Value } from '$lib/utils'
|
||||
|
||||
export type GetInitialAndModifiedValues = (() => SavedAndModifiedValue) | undefined
|
||||
|
||||
export type SavedAndModifiedValue = {
|
||||
savedValue: Value | undefined
|
||||
modifiedValue: Value | undefined
|
||||
}
|
||||
savedValue: Value | undefined
|
||||
modifiedValue: Value | undefined
|
||||
}
|
||||
|
||||
@@ -42,4 +42,3 @@ export const CONTEXT_MENU_DIVIDER_CLASS = 'my-1 h-px bg-border-light'
|
||||
*/
|
||||
export const CONTEXT_MENU_ANIMATION_CLASSES =
|
||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2'
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { FileUp, Trash } from 'lucide-svelte'
|
||||
import Button from '../../common/button/Button.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
@@ -8,24 +7,47 @@
|
||||
|
||||
type ConvertedFile = string | ArrayBuffer | null
|
||||
|
||||
let c = ''
|
||||
export { c as class }
|
||||
export let style = ''
|
||||
export let accept = '*'
|
||||
export let multiple = false
|
||||
export let convertTo: ReadFileAs | undefined = undefined
|
||||
export let hideIcon = false
|
||||
export let iconSize = 24
|
||||
export let returnFileNames = false
|
||||
export let submittedText: string | undefined = undefined
|
||||
export let defaultFile: string | string[] | undefined = undefined
|
||||
export let disabled: boolean | undefined = undefined
|
||||
export let folderOnly = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let input: HTMLInputElement
|
||||
type FileWithPath = File & { path?: string }
|
||||
export let files: FileWithPath[] | undefined = undefined
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
style?: string
|
||||
accept?: string
|
||||
multiple?: boolean
|
||||
convertTo?: ReadFileAs | undefined
|
||||
hideIcon?: boolean
|
||||
iconSize?: number
|
||||
returnFileNames?: boolean
|
||||
submittedText?: string | undefined
|
||||
defaultFile?: string | string[] | undefined
|
||||
disabled?: boolean | undefined
|
||||
folderOnly?: boolean
|
||||
files?: FileWithPath[] | undefined
|
||||
selected_title?: import('svelte').Snippet
|
||||
children?: import('svelte').Snippet
|
||||
onChange?: (detail: any) => void
|
||||
}
|
||||
|
||||
let {
|
||||
class: c = '',
|
||||
style = '',
|
||||
accept = '*',
|
||||
multiple = false,
|
||||
convertTo = undefined,
|
||||
hideIcon = false,
|
||||
iconSize = 24,
|
||||
returnFileNames = false,
|
||||
submittedText = undefined,
|
||||
defaultFile = undefined,
|
||||
disabled = undefined,
|
||||
folderOnly = false,
|
||||
files = $bindable(undefined),
|
||||
selected_title,
|
||||
children,
|
||||
onChange
|
||||
}: Props = $props()
|
||||
|
||||
let input: HTMLInputElement
|
||||
|
||||
let pointerStartX = 0
|
||||
let pointerStartY = 0
|
||||
@@ -35,10 +57,10 @@
|
||||
pointerStartY = e.clientY
|
||||
}
|
||||
|
||||
async function onChange(fileList: FileWithPath[] | null) {
|
||||
async function handleFileChange(fileList: FileWithPath[] | null) {
|
||||
if (!fileList || !fileList.length) {
|
||||
files = undefined
|
||||
dispatch('change', files)
|
||||
onChange?.(files)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -98,14 +120,14 @@
|
||||
dirEntry: FileSystemDirectoryEntry,
|
||||
path: string
|
||||
): Promise<FileWithPath[]> {
|
||||
const files: FileWithPath[] = []
|
||||
const filesArr: FileWithPath[] = []
|
||||
const dirReader = dirEntry.createReader()
|
||||
|
||||
async function readEntries() {
|
||||
return new Promise<FileWithPath[]>((resolve) => {
|
||||
dirReader.readEntries(async (entries) => {
|
||||
if (entries.length === 0) {
|
||||
resolve(files)
|
||||
resolve(filesArr)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -113,7 +135,7 @@
|
||||
return traverseFileTree(entry, path + dirEntry.name + '/')
|
||||
})
|
||||
const nestedFiles = await Promise.all(filePromises)
|
||||
files.push(...nestedFiles.flat())
|
||||
filesArr.push(...nestedFiles.flat())
|
||||
// readEntries only return up to 100 files
|
||||
// continue reading if more files exist
|
||||
resolve(await readEntries())
|
||||
@@ -141,8 +163,8 @@
|
||||
if (folderOnly) {
|
||||
const item = event.dataTransfer.items[0]?.webkitGetAsEntry()
|
||||
if (item) {
|
||||
const files = await traverseFileTree(item, '')
|
||||
onChange(files)
|
||||
const droppedFiles = await traverseFileTree(item, '')
|
||||
handleFileChange(droppedFiles)
|
||||
}
|
||||
} else {
|
||||
if (event.dataTransfer.files && event.dataTransfer.files.length) {
|
||||
@@ -150,7 +172,7 @@
|
||||
sendUserToast('Only one file can be uploaded at a time')
|
||||
return
|
||||
} else {
|
||||
onChange(Array.from(event.dataTransfer.files))
|
||||
handleFileChange(Array.from(event.dataTransfer.files))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,9 +195,9 @@
|
||||
if (returnFileNames) {
|
||||
converted = converted.map((c, i) => ({ name: files![i].name, data: c }))
|
||||
}
|
||||
dispatch('change', converted)
|
||||
onChange?.(converted)
|
||||
} else {
|
||||
dispatch('change', files)
|
||||
onChange?.(files)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,10 +216,10 @@
|
||||
duration-200 px-1 py-8`,
|
||||
c
|
||||
)}
|
||||
on:dragover={handleDragOver}
|
||||
on:drop={handleDrop}
|
||||
on:pointerdown={handlePointerDown}
|
||||
on:click={(e) => {
|
||||
ondragover={handleDragOver}
|
||||
ondrop={handleDrop}
|
||||
onpointerdown={handlePointerDown}
|
||||
onclick={(e) => {
|
||||
const deltaX = Math.abs(e.clientX - pointerStartX)
|
||||
const deltaY = Math.abs(e.clientY - pointerStartY)
|
||||
if (deltaX > 5 || deltaY > 5) {
|
||||
@@ -214,11 +236,13 @@
|
||||
{/if}
|
||||
{#if files}
|
||||
<div class="w-full max-h-full overflow-auto px-6">
|
||||
<slot name="selected-title">
|
||||
{#if selected_title}
|
||||
{@render selected_title()}
|
||||
{:else}
|
||||
<div class="text-center mb-2 px-2">
|
||||
{submittedText ? submittedText : `Selected file${files.length > 1 ? 's' : ''}`}:
|
||||
</div>
|
||||
</slot>
|
||||
{/if}
|
||||
<ul class="relative z-20 max-w-[500px] bg-surface rounded-lg overflow-hidden mx-auto">
|
||||
{#each files as { name }, i}
|
||||
<li
|
||||
@@ -232,7 +256,7 @@
|
||||
iconOnly
|
||||
btnClasses="bg-transparent"
|
||||
startIcon={{ icon: Trash }}
|
||||
on:click={() => removeFile(i)}
|
||||
onclick={() => removeFile(i)}
|
||||
destructive
|
||||
/>
|
||||
</li>
|
||||
@@ -240,9 +264,11 @@
|
||||
</ul>
|
||||
</div>
|
||||
{:else}
|
||||
<slot>
|
||||
{#if children}
|
||||
{@render children()}
|
||||
{:else}
|
||||
<span>Drag and drop {folderOnly ? 'a folder' : multiple ? 'files' : 'a file'}</span>
|
||||
</slot>
|
||||
{/if}
|
||||
{/if}
|
||||
<input
|
||||
class="!absolute !inset-0 !z-10 !opacity-0 !cursor-pointer"
|
||||
@@ -250,12 +276,11 @@
|
||||
{...{ webkitdirectory: folderOnly }}
|
||||
title={files ? `${files.length} file${files.length > 1 ? 's' : ''} chosen` : 'No file chosen'}
|
||||
bind:this={input}
|
||||
on:change={({ currentTarget }) => {
|
||||
onChange(currentTarget.files ? Array.from(currentTarget.files) : null)
|
||||
onchange={({ currentTarget }) => {
|
||||
handleFileChange(currentTarget.files ? Array.from(currentTarget.files) : null)
|
||||
}}
|
||||
{accept}
|
||||
{multiple}
|
||||
{...$$restProps}
|
||||
/>
|
||||
{#if defaultFile && (!Array.isArray(defaultFile) || defaultFile.length > 0)}
|
||||
<div class="w-full border-dashed border-t-2 text-2xs pt-1 text-primary mt-2">
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let { children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="w-full flex-grow bg-blue-300">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
interface Props {
|
||||
open?: boolean;
|
||||
onOpen?: () => void;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const dispatchIfMounted = createDispatcherIfMounted(dispatch)
|
||||
export let open: boolean = false
|
||||
let { open = false, onOpen = undefined, onClose = undefined }: Props = $props();
|
||||
|
||||
$: dispatchIfMounted(open ? 'open' : 'close')
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
onOpen?.()
|
||||
} else {
|
||||
onClose?.()
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -7,13 +7,19 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppViewerContext } from '$lib/components/apps/types'
|
||||
|
||||
export let title: string
|
||||
export let style: string = ''
|
||||
export let css: any = {}
|
||||
interface Props {
|
||||
title: string
|
||||
style?: string
|
||||
css?: any
|
||||
class?: string
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { title, style = '', css = {}, class: c = '', children }: Props = $props()
|
||||
|
||||
const { mode } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let isOpen = false
|
||||
let isOpen = $state(false)
|
||||
|
||||
export function close() {
|
||||
isOpen = false
|
||||
@@ -41,16 +47,13 @@
|
||||
css?.popup?.class,
|
||||
'wm-modal-form-popup'
|
||||
)}
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
close()
|
||||
}}
|
||||
use:clickOutside={{ onClickOutside: () => close() }}
|
||||
>
|
||||
<div class="px-4 py-2 border-b flex justify-between items-center">
|
||||
<div>{title}</div>
|
||||
<div class="w-8">
|
||||
<button
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
isOpen = false
|
||||
}}
|
||||
class="hover:bg-surface-hover bg-surface-secondary rounded-full w-8 h-8 flex items-center justify-center transition-all"
|
||||
@@ -60,17 +63,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="relative bg-surface rounded-md" on:click|stopPropagation={() => {}}>
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="relative bg-surface rounded-md" onclick={(e) => e.stopPropagation()}>
|
||||
<div
|
||||
class={twMerge(
|
||||
'max-w-screen-lg max-h-screen-80 overflow-auto flex flex-col',
|
||||
$$props.class
|
||||
c
|
||||
)}
|
||||
{style}
|
||||
>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
}
|
||||
]
|
||||
}}
|
||||
on:open={() => {
|
||||
onOpen={() => {
|
||||
menuOpen = true
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -18,33 +18,36 @@
|
||||
Unplug
|
||||
} from 'lucide-svelte'
|
||||
|
||||
export let kind:
|
||||
| 'script'
|
||||
| 'flow'
|
||||
| 'app'
|
||||
| 'raw_app'
|
||||
| 'resource'
|
||||
| 'variable'
|
||||
| 'resource_type'
|
||||
| 'folder'
|
||||
| 'schedule'
|
||||
| 'trigger'
|
||||
| 'routes'
|
||||
| 'schedules'
|
||||
| 'websockets'
|
||||
| 'postgres'
|
||||
| 'kafka'
|
||||
| 'nats'
|
||||
| 'mqtt'
|
||||
| 'sqs'
|
||||
| 'gcp'
|
||||
| 'emails'
|
||||
interface Props {
|
||||
kind:
|
||||
| 'script'
|
||||
| 'flow'
|
||||
| 'app'
|
||||
| 'raw_app'
|
||||
| 'resource'
|
||||
| 'variable'
|
||||
| 'resource_type'
|
||||
| 'folder'
|
||||
| 'schedule'
|
||||
| 'trigger'
|
||||
| 'routes'
|
||||
| 'schedules'
|
||||
| 'websockets'
|
||||
| 'postgres'
|
||||
| 'kafka'
|
||||
| 'nats'
|
||||
| 'mqtt'
|
||||
| 'sqs'
|
||||
| 'gcp'
|
||||
| 'emails'
|
||||
/** For 'trigger' kind, specifies the specific trigger type (routes, schedules, etc.) */
|
||||
triggerKind?: string | undefined
|
||||
}
|
||||
|
||||
/** For 'trigger' kind, specifies the specific trigger type (routes, schedules, etc.) */
|
||||
export let triggerKind: string | undefined = undefined
|
||||
let { kind, triggerKind = undefined }: Props = $props()
|
||||
|
||||
// Use triggerKind if kind is 'trigger' and triggerKind is provided
|
||||
$: effectiveKind = kind === 'trigger' && triggerKind ? triggerKind : kind
|
||||
let effectiveKind = $derived(kind === 'trigger' && triggerKind ? triggerKind : kind)
|
||||
</script>
|
||||
|
||||
<div class="flex justify-center items-center" title={effectiveKind}>
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let { children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div class="overflow-hidden rounded-md border">
|
||||
<table class="min-w-full divide-y divide-gray-300">
|
||||
<tbody class="divide-y bg-surface">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
import CodeDisplay from './script/CodeDisplay.svelte'
|
||||
import LinkRenderer from './LinkRenderer.svelte'
|
||||
|
||||
export let message: DisplayMessage
|
||||
interface Props {
|
||||
message: DisplayMessage;
|
||||
}
|
||||
|
||||
let { message }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
|
||||
@@ -12,39 +12,43 @@
|
||||
).length < 2}
|
||||
class="max-w-full"
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
<div
|
||||
class="text-primary text-xs flex flex-row items-center font-normal gap-0.5 border px-1 rounded-lg"
|
||||
>
|
||||
<span class={`truncate`}>
|
||||
{aiChatManager.mode.charAt(0).toUpperCase() + aiChatManager.mode.slice(1)} mode
|
||||
</span>
|
||||
{#if Object.keys(aiChatManager.allowedModes).filter((k) => aiChatManager.allowedModes[k]).length > 1}
|
||||
<div class="shrink-0">
|
||||
<ChevronDown size={16} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content" let:close>
|
||||
<div class="flex flex-col gap-1 p-1 min-w-24">
|
||||
{#each Object.values(AIMode) as possibleMode}
|
||||
{#if aiChatManager.allowedModes[possibleMode]}
|
||||
<button
|
||||
class={twMerge(
|
||||
'text-left text-xs hover:bg-surface-hover rounded-md p-1 font-normal',
|
||||
aiChatManager.mode === possibleMode && 'bg-surface-hover'
|
||||
)}
|
||||
onclick={() => {
|
||||
aiChatManager.changeMode(possibleMode)
|
||||
close()
|
||||
}}
|
||||
>
|
||||
{possibleMode.charAt(0).toUpperCase() + possibleMode.slice(1)} mode
|
||||
</button>
|
||||
{#snippet trigger()}
|
||||
|
||||
<div
|
||||
class="text-primary text-xs flex flex-row items-center font-normal gap-0.5 border px-1 rounded-lg"
|
||||
>
|
||||
<span class={`truncate`}>
|
||||
{aiChatManager.mode.charAt(0).toUpperCase() + aiChatManager.mode.slice(1)} mode
|
||||
</span>
|
||||
{#if Object.keys(aiChatManager.allowedModes).filter((k) => aiChatManager.allowedModes[k]).length > 1}
|
||||
<div class="shrink-0">
|
||||
<ChevronDown size={16} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</div>
|
||||
|
||||
{/snippet}
|
||||
{#snippet content({ close })}
|
||||
|
||||
<div class="flex flex-col gap-1 p-1 min-w-24">
|
||||
{#each Object.values(AIMode) as possibleMode}
|
||||
{#if aiChatManager.allowedModes[possibleMode]}
|
||||
<button
|
||||
class={twMerge(
|
||||
'text-left text-xs hover:bg-surface-hover rounded-md p-1 font-normal',
|
||||
aiChatManager.mode === possibleMode && 'bg-surface-hover'
|
||||
)}
|
||||
onclick={() => {
|
||||
aiChatManager.changeMode(possibleMode)
|
||||
close()
|
||||
}}
|
||||
>
|
||||
{possibleMode.charAt(0).toUpperCase() + possibleMode.slice(1)} mode
|
||||
</button>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{/snippet}
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,10 @@ export function createAppEvalHelpers(
|
||||
let frontend: Record<string, string> = { ...initialFrontend }
|
||||
let backend: Record<string, BackendRunnable> = { ...initialBackend }
|
||||
let snapshotId = 0
|
||||
const snapshots: Map<number, { frontend: Record<string, string>; backend: Record<string, BackendRunnable> }> = new Map()
|
||||
const snapshots: Map<
|
||||
number,
|
||||
{ frontend: Record<string, string>; backend: Record<string, BackendRunnable> }
|
||||
> = new Map()
|
||||
|
||||
const helpers: AppAIChatHelpers = {
|
||||
// Frontend file operations
|
||||
@@ -126,11 +129,7 @@ export function createAppEvalHelpers(
|
||||
return { success: true, result: [] }
|
||||
},
|
||||
|
||||
addTableToWhitelist: (
|
||||
_datatableName: string,
|
||||
_schemaName: string,
|
||||
_tableName: string
|
||||
) => {
|
||||
addTableToWhitelist: (_datatableName: string, _schemaName: string, _tableName: string) => {
|
||||
// No-op for eval testing - tables are not tracked in test context
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,9 +156,7 @@ export async function loadAppFixture(fixturePath: string): Promise<AppFiles> {
|
||||
* Loads an app fixture and returns the separate frontend and backend objects.
|
||||
* Convenience function for use with runAppEval options.
|
||||
*/
|
||||
export async function loadAppFixtureForEval(
|
||||
fixturePath: string
|
||||
): Promise<{
|
||||
export async function loadAppFixtureForEval(fixturePath: string): Promise<{
|
||||
initialFrontend: Record<string, string>
|
||||
initialBackend: Record<string, BackendRunnable>
|
||||
}> {
|
||||
|
||||
+40
-5
@@ -11,11 +11,46 @@ interface FileItem {
|
||||
const mockFiles: FileItem[] = [
|
||||
{ id: 'f1', name: 'Documents', type: 'folder', modifiedAt: '2024-01-15', parentId: null },
|
||||
{ id: 'f2', name: 'Images', type: 'folder', modifiedAt: '2024-01-10', parentId: null },
|
||||
{ id: 'f3', name: 'readme.txt', type: 'file', size: 1024, modifiedAt: '2024-01-20', parentId: null },
|
||||
{ id: 'f4', name: 'report.pdf', type: 'file', size: 52400, modifiedAt: '2024-01-18', parentId: 'f1' },
|
||||
{ id: 'f5', name: 'notes.txt', type: 'file', size: 256, modifiedAt: '2024-01-12', parentId: 'f1' },
|
||||
{ id: 'f6', name: 'photo1.jpg', type: 'file', size: 2048000, modifiedAt: '2024-01-08', parentId: 'f2' },
|
||||
{ id: 'f7', name: 'photo2.jpg', type: 'file', size: 1536000, modifiedAt: '2024-01-09', parentId: 'f2' },
|
||||
{
|
||||
id: 'f3',
|
||||
name: 'readme.txt',
|
||||
type: 'file',
|
||||
size: 1024,
|
||||
modifiedAt: '2024-01-20',
|
||||
parentId: null
|
||||
},
|
||||
{
|
||||
id: 'f4',
|
||||
name: 'report.pdf',
|
||||
type: 'file',
|
||||
size: 52400,
|
||||
modifiedAt: '2024-01-18',
|
||||
parentId: 'f1'
|
||||
},
|
||||
{
|
||||
id: 'f5',
|
||||
name: 'notes.txt',
|
||||
type: 'file',
|
||||
size: 256,
|
||||
modifiedAt: '2024-01-12',
|
||||
parentId: 'f1'
|
||||
},
|
||||
{
|
||||
id: 'f6',
|
||||
name: 'photo1.jpg',
|
||||
type: 'file',
|
||||
size: 2048000,
|
||||
modifiedAt: '2024-01-08',
|
||||
parentId: 'f2'
|
||||
},
|
||||
{
|
||||
id: 'f7',
|
||||
name: 'photo2.jpg',
|
||||
type: 'file',
|
||||
size: 1536000,
|
||||
modifiedAt: '2024-01-09',
|
||||
parentId: 'f2'
|
||||
},
|
||||
{ id: 'f8', name: 'Projects', type: 'folder', modifiedAt: '2024-01-05', parentId: 'f1' }
|
||||
]
|
||||
|
||||
|
||||
+2
-7
@@ -46,9 +46,7 @@ export const FileItem: React.FC<FileItemProps> = ({ item, onDelete, onRename, on
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
className={item.type === 'folder' ? 'cursor-pointer hover:text-blue-600' : ''}
|
||||
>
|
||||
<span className={item.type === 'folder' ? 'cursor-pointer hover:text-blue-600' : ''}>
|
||||
{item.name}
|
||||
</span>
|
||||
)}
|
||||
@@ -67,10 +65,7 @@ export const FileItem: React.FC<FileItemProps> = ({ item, onDelete, onRename, on
|
||||
>
|
||||
Rename
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onDelete(item)}
|
||||
className="text-red-500 hover:text-red-700 text-sm"
|
||||
>
|
||||
<button onClick={() => onDelete(item)} className="text-red-500 hover:text-red-700 text-sm">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
+1
-3
@@ -11,9 +11,7 @@ interface FileListProps {
|
||||
|
||||
export const FileList: React.FC<FileListProps> = ({ files, onDelete, onRename, onFolderOpen }) => {
|
||||
if (files.length === 0) {
|
||||
return (
|
||||
<div className="text-center text-gray-500 py-8">This folder is empty</div>
|
||||
)
|
||||
return <div className="text-center text-gray-500 py-8">This folder is empty</div>
|
||||
}
|
||||
|
||||
// Sort: folders first, then files
|
||||
|
||||
@@ -1,134 +1,134 @@
|
||||
{
|
||||
"summary": "",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_users",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n return [\n { id: 1, name: \"Alice\", role: \"admin\", active: true },\n { id: 2, name: \"Bob\", role: \"user\", active: false },\n { id: 4, name: \"Dana\", role: \"moderator\", active: true },\n { id: 3, name: \"Charlie\", role: \"user\", active: true },\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "filter_active_users",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(users) {\n return users.filter(user => user.active);\n}",
|
||||
"input_transforms": {
|
||||
"users": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_users"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "loop_users",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "results.filter_active_users"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"modules": [
|
||||
{
|
||||
"id": "branch_user_role",
|
||||
"value": {
|
||||
"type": "branchone",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "Admin Action",
|
||||
"expr": "flow_input.iter.value.role === 'admin'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "admin_action",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(user) {\n return `Admin action taken for ${user.name}`;\n}",
|
||||
"input_transforms": {
|
||||
"user": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "User Action",
|
||||
"expr": "flow_input.iter.value.role === 'user'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "user_action",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(user) {\n return `User action taken for ${user.name}`;\n}",
|
||||
"input_transforms": {
|
||||
"user": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Moderator Action",
|
||||
"expr": "flow_input.iter.value.role === 'moderator'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "moderator_action",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(user) { return `Moderator action taken for ${user.name}`; }",
|
||||
"input_transforms": {
|
||||
"user": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"parallel": false,
|
||||
"squash": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_actions",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(actions) {\n return actions;\n}",
|
||||
"input_transforms": {
|
||||
"actions": {
|
||||
"type": "javascript",
|
||||
"expr": "results.loop_users"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
"summary": "",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_users",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n return [\n { id: 1, name: \"Alice\", role: \"admin\", active: true },\n { id: 2, name: \"Bob\", role: \"user\", active: false },\n { id: 4, name: \"Dana\", role: \"moderator\", active: true },\n { id: 3, name: \"Charlie\", role: \"user\", active: true },\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "filter_active_users",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(users) {\n return users.filter(user => user.active);\n}",
|
||||
"input_transforms": {
|
||||
"users": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_users"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "loop_users",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "results.filter_active_users"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"modules": [
|
||||
{
|
||||
"id": "branch_user_role",
|
||||
"value": {
|
||||
"type": "branchone",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "Admin Action",
|
||||
"expr": "flow_input.iter.value.role === 'admin'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "admin_action",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(user) {\n return `Admin action taken for ${user.name}`;\n}",
|
||||
"input_transforms": {
|
||||
"user": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "User Action",
|
||||
"expr": "flow_input.iter.value.role === 'user'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "user_action",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(user) {\n return `User action taken for ${user.name}`;\n}",
|
||||
"input_transforms": {
|
||||
"user": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Moderator Action",
|
||||
"expr": "flow_input.iter.value.role === 'moderator'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "moderator_action",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(user) { return `Moderator action taken for ${user.name}`; }",
|
||||
"input_transforms": {
|
||||
"user": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"parallel": false,
|
||||
"squash": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_actions",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(actions) {\n return actions;\n}",
|
||||
"input_transforms": {
|
||||
"actions": {
|
||||
"type": "javascript",
|
||||
"expr": "results.loop_users"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,183 +1,183 @@
|
||||
{
|
||||
"summary": "E-commerce Order Processing Pipeline",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "validate_order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(items: { name: string; price: number; quantity: number }[]) {\n const invalid = items.filter(item => item.price <= 0 || item.quantity <= 0);\n return { valid: invalid.length === 0, invalidItems: invalid };\n}",
|
||||
"input_transforms": {
|
||||
"items": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.items"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "calculate_total",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(items: { name: string; price: number; quantity: number }[]) {\n const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);\n const tax = subtotal * 0.08;\n return { subtotal, tax, total: subtotal + tax };\n}",
|
||||
"input_transforms": {
|
||||
"items": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.items"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "check_inventory",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.items"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"parallel": true,
|
||||
"modules": [
|
||||
{
|
||||
"id": "check_item_stock",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: { name: string; quantity: number }) {\n // Mock inventory check - items with even quantity are in stock\n const inStock = item.quantity % 2 === 0 || item.quantity < 5;\n return { name: item.name, requested: item.quantity, inStock, available: inStock ? item.quantity : 0 };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "process_inventory_result",
|
||||
"value": {
|
||||
"type": "branchone",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "All items in stock - create shipment",
|
||||
"expr": "results.check_inventory.every(item => item.inStock)",
|
||||
"modules": [
|
||||
{
|
||||
"id": "create_shipment",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(shipping_address: string, total: number) {\n return {\n shipment_id: `SHIP-${Date.now()}`,\n status: 'created',\n address: shipping_address,\n total,\n estimated_delivery: '3-5 business days'\n };\n}",
|
||||
"input_transforms": {
|
||||
"shipping_address": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.shipping_address"
|
||||
},
|
||||
"total": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_total.total"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": [
|
||||
{
|
||||
"id": "create_backorder",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(inventory_results: { name: string; inStock: boolean }[]) {\n const outOfStock = inventory_results.filter(item => !item.inStock);\n return {\n backorder_id: `BO-${Date.now()}`,\n status: 'backorder',\n unavailable_items: outOfStock.map(item => item.name),\n message: 'Some items are out of stock. We will notify you when available.'\n };\n}",
|
||||
"input_transforms": {
|
||||
"inventory_results": {
|
||||
"type": "javascript",
|
||||
"expr": "results.check_inventory"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "send_confirmation",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(customer_email: string, order_result: any) {\n // Mock email sending\n return {\n email_sent: true,\n to: customer_email,\n subject: order_result.shipment_id ? 'Order Confirmed' : 'Order Update - Backorder',\n sent_at: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"customer_email": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.customer_email"
|
||||
},
|
||||
"order_result": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_inventory_result"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_summary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(validation: any, totals: any, order_result: any, confirmation: any) {\n return {\n order_valid: validation.valid,\n totals,\n order_status: order_result.shipment_id ? 'shipped' : 'backorder',\n order_id: order_result.shipment_id || order_result.backorder_id,\n confirmation_sent: confirmation.email_sent\n };\n}",
|
||||
"input_transforms": {
|
||||
"validation": {
|
||||
"type": "javascript",
|
||||
"expr": "results.validate_order"
|
||||
},
|
||||
"totals": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_total"
|
||||
},
|
||||
"order_result": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_inventory_result"
|
||||
},
|
||||
"confirmation": {
|
||||
"type": "javascript",
|
||||
"expr": "results.send_confirmation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Array of order items",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"price": { "type": "number" },
|
||||
"quantity": { "type": "integer" }
|
||||
},
|
||||
"required": ["name", "price", "quantity"]
|
||||
}
|
||||
},
|
||||
"customer_email": {
|
||||
"type": "string",
|
||||
"description": "Customer email address"
|
||||
},
|
||||
"shipping_address": {
|
||||
"type": "string",
|
||||
"description": "Shipping address"
|
||||
}
|
||||
},
|
||||
"required": ["items", "customer_email", "shipping_address"]
|
||||
}
|
||||
"summary": "E-commerce Order Processing Pipeline",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "validate_order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(items: { name: string; price: number; quantity: number }[]) {\n const invalid = items.filter(item => item.price <= 0 || item.quantity <= 0);\n return { valid: invalid.length === 0, invalidItems: invalid };\n}",
|
||||
"input_transforms": {
|
||||
"items": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.items"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "calculate_total",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(items: { name: string; price: number; quantity: number }[]) {\n const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);\n const tax = subtotal * 0.08;\n return { subtotal, tax, total: subtotal + tax };\n}",
|
||||
"input_transforms": {
|
||||
"items": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.items"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "check_inventory",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.items"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"parallel": true,
|
||||
"modules": [
|
||||
{
|
||||
"id": "check_item_stock",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: { name: string; quantity: number }) {\n // Mock inventory check - items with even quantity are in stock\n const inStock = item.quantity % 2 === 0 || item.quantity < 5;\n return { name: item.name, requested: item.quantity, inStock, available: inStock ? item.quantity : 0 };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "process_inventory_result",
|
||||
"value": {
|
||||
"type": "branchone",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "All items in stock - create shipment",
|
||||
"expr": "results.check_inventory.every(item => item.inStock)",
|
||||
"modules": [
|
||||
{
|
||||
"id": "create_shipment",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(shipping_address: string, total: number) {\n return {\n shipment_id: `SHIP-${Date.now()}`,\n status: 'created',\n address: shipping_address,\n total,\n estimated_delivery: '3-5 business days'\n };\n}",
|
||||
"input_transforms": {
|
||||
"shipping_address": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.shipping_address"
|
||||
},
|
||||
"total": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_total.total"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": [
|
||||
{
|
||||
"id": "create_backorder",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(inventory_results: { name: string; inStock: boolean }[]) {\n const outOfStock = inventory_results.filter(item => !item.inStock);\n return {\n backorder_id: `BO-${Date.now()}`,\n status: 'backorder',\n unavailable_items: outOfStock.map(item => item.name),\n message: 'Some items are out of stock. We will notify you when available.'\n };\n}",
|
||||
"input_transforms": {
|
||||
"inventory_results": {
|
||||
"type": "javascript",
|
||||
"expr": "results.check_inventory"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "send_confirmation",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(customer_email: string, order_result: any) {\n // Mock email sending\n return {\n email_sent: true,\n to: customer_email,\n subject: order_result.shipment_id ? 'Order Confirmed' : 'Order Update - Backorder',\n sent_at: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"customer_email": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.customer_email"
|
||||
},
|
||||
"order_result": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_inventory_result"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_summary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(validation: any, totals: any, order_result: any, confirmation: any) {\n return {\n order_valid: validation.valid,\n totals,\n order_status: order_result.shipment_id ? 'shipped' : 'backorder',\n order_id: order_result.shipment_id || order_result.backorder_id,\n confirmation_sent: confirmation.email_sent\n };\n}",
|
||||
"input_transforms": {
|
||||
"validation": {
|
||||
"type": "javascript",
|
||||
"expr": "results.validate_order"
|
||||
},
|
||||
"totals": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_total"
|
||||
},
|
||||
"order_result": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_inventory_result"
|
||||
},
|
||||
"confirmation": {
|
||||
"type": "javascript",
|
||||
"expr": "results.send_confirmation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Array of order items",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"price": { "type": "number" },
|
||||
"quantity": { "type": "integer" }
|
||||
},
|
||||
"required": ["name", "price", "quantity"]
|
||||
}
|
||||
},
|
||||
"customer_email": {
|
||||
"type": "string",
|
||||
"description": "Customer email address"
|
||||
},
|
||||
"shipping_address": {
|
||||
"type": "string",
|
||||
"description": "Shipping address"
|
||||
}
|
||||
},
|
||||
"required": ["items", "customer_email", "shipping_address"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,204 +1,204 @@
|
||||
{
|
||||
"summary": "Data Pipeline with Quality-Based Routing",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_data_sources",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n return [\n { id: 'source_1', url: 'https://api.example.com/data1' },\n { id: 'source_2', url: 'https://api.example.com/data2' },\n { id: 'source_3', url: 'https://api.example.com/data3' }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "process_sources",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_data_sources"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"parallel": true,
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_raw_data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(source: { id: string; url: string }) {\n // Mock fetch returning sample records\n return {\n source_id: source.id,\n records: [\n { id: 1, value: 'data_a', valid: true },\n { id: 2, value: '', valid: false },\n { id: 3, value: 'data_c', valid: true },\n { id: 4, value: 'data_d', valid: true }\n ]\n };\n}",
|
||||
"input_transforms": {
|
||||
"source": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "transform_data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(raw_data: { source_id: string; records: any[] }) {\n // Filter out invalid entries\n const cleaned = raw_data.records.filter(r => r.valid && r.value);\n return {\n source_id: raw_data.source_id,\n original_count: raw_data.records.length,\n cleaned_count: cleaned.length,\n records: cleaned\n };\n}",
|
||||
"input_transforms": {
|
||||
"raw_data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_raw_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "validate_data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(transformed: { source_id: string; original_count: number; cleaned_count: number; records: any[] }) {\n // Calculate validation score based on data quality\n const score = Math.round((transformed.cleaned_count / transformed.original_count) * 100);\n return {\n source_id: transformed.source_id,\n records: transformed.records,\n validation_score: score,\n record_count: transformed.cleaned_count\n };\n}",
|
||||
"input_transforms": {
|
||||
"transformed": {
|
||||
"type": "javascript",
|
||||
"expr": "results.transform_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aggregate_data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(processed_sources: any[]) {\n const all_records = processed_sources.flatMap(s => s.records);\n const total_count = all_records.length;\n return {\n combined_records: all_records,\n total_record_count: total_count,\n sources_processed: processed_sources.length\n };\n}",
|
||||
"input_transforms": {
|
||||
"processed_sources": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_sources"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "calculate_quality_score",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(processed_sources: any[]) {\n const scores = processed_sources.map(s => s.validation_score);\n const average = Math.round(scores.reduce((a, b) => a + b, 0) / scores.length);\n return { quality_score: average, individual_scores: scores };\n}",
|
||||
"input_transforms": {
|
||||
"processed_sources": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_sources"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "route_by_quality",
|
||||
"value": {
|
||||
"type": "branchone",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "High quality - store in primary database",
|
||||
"expr": "results.calculate_quality_score.quality_score >= 90",
|
||||
"modules": [
|
||||
{
|
||||
"id": "store_primary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any, score: number) {\n return {\n destination: 'primary_database',\n status: 'success',\n records_stored: data.total_record_count,\n quality_score: score\n };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.aggregate_data"
|
||||
},
|
||||
"score": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_quality_score.quality_score"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Medium quality - store in secondary with warning",
|
||||
"expr": "results.calculate_quality_score.quality_score >= 70",
|
||||
"modules": [
|
||||
{
|
||||
"id": "store_secondary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any, score: number) {\n return {\n destination: 'secondary_database',\n status: 'warning',\n warning_message: 'Data quality below optimal threshold',\n records_stored: data.total_record_count,\n quality_score: score\n };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.aggregate_data"
|
||||
},
|
||||
"score": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_quality_score.quality_score"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": [
|
||||
{
|
||||
"id": "store_quarantine",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any, score: number) {\n return {\n destination: 'quarantine',\n status: 'alert',\n alert_message: 'Data quality critically low - requires review',\n records_quarantined: data.total_record_count,\n quality_score: score\n };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.aggregate_data"
|
||||
},
|
||||
"score": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_quality_score.quality_score"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "generate_report",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(aggregated: any, quality: any, storage_result: any) {\n return {\n report: {\n total_records: aggregated.total_record_count,\n sources_processed: aggregated.sources_processed,\n quality_score: quality.quality_score,\n individual_scores: quality.individual_scores,\n destination: storage_result.destination,\n status: storage_result.status,\n processed_at: new Date().toISOString()\n }\n };\n}",
|
||||
"input_transforms": {
|
||||
"aggregated": {
|
||||
"type": "javascript",
|
||||
"expr": "results.aggregate_data"
|
||||
},
|
||||
"quality": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_quality_score"
|
||||
},
|
||||
"storage_result": {
|
||||
"type": "javascript",
|
||||
"expr": "results.route_by_quality"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
"summary": "Data Pipeline with Quality-Based Routing",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_data_sources",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n return [\n { id: 'source_1', url: 'https://api.example.com/data1' },\n { id: 'source_2', url: 'https://api.example.com/data2' },\n { id: 'source_3', url: 'https://api.example.com/data3' }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "process_sources",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_data_sources"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"parallel": true,
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_raw_data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(source: { id: string; url: string }) {\n // Mock fetch returning sample records\n return {\n source_id: source.id,\n records: [\n { id: 1, value: 'data_a', valid: true },\n { id: 2, value: '', valid: false },\n { id: 3, value: 'data_c', valid: true },\n { id: 4, value: 'data_d', valid: true }\n ]\n };\n}",
|
||||
"input_transforms": {
|
||||
"source": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "transform_data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(raw_data: { source_id: string; records: any[] }) {\n // Filter out invalid entries\n const cleaned = raw_data.records.filter(r => r.valid && r.value);\n return {\n source_id: raw_data.source_id,\n original_count: raw_data.records.length,\n cleaned_count: cleaned.length,\n records: cleaned\n };\n}",
|
||||
"input_transforms": {
|
||||
"raw_data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_raw_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "validate_data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(transformed: { source_id: string; original_count: number; cleaned_count: number; records: any[] }) {\n // Calculate validation score based on data quality\n const score = Math.round((transformed.cleaned_count / transformed.original_count) * 100);\n return {\n source_id: transformed.source_id,\n records: transformed.records,\n validation_score: score,\n record_count: transformed.cleaned_count\n };\n}",
|
||||
"input_transforms": {
|
||||
"transformed": {
|
||||
"type": "javascript",
|
||||
"expr": "results.transform_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aggregate_data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(processed_sources: any[]) {\n const all_records = processed_sources.flatMap(s => s.records);\n const total_count = all_records.length;\n return {\n combined_records: all_records,\n total_record_count: total_count,\n sources_processed: processed_sources.length\n };\n}",
|
||||
"input_transforms": {
|
||||
"processed_sources": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_sources"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "calculate_quality_score",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(processed_sources: any[]) {\n const scores = processed_sources.map(s => s.validation_score);\n const average = Math.round(scores.reduce((a, b) => a + b, 0) / scores.length);\n return { quality_score: average, individual_scores: scores };\n}",
|
||||
"input_transforms": {
|
||||
"processed_sources": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_sources"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "route_by_quality",
|
||||
"value": {
|
||||
"type": "branchone",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "High quality - store in primary database",
|
||||
"expr": "results.calculate_quality_score.quality_score >= 90",
|
||||
"modules": [
|
||||
{
|
||||
"id": "store_primary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any, score: number) {\n return {\n destination: 'primary_database',\n status: 'success',\n records_stored: data.total_record_count,\n quality_score: score\n };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.aggregate_data"
|
||||
},
|
||||
"score": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_quality_score.quality_score"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Medium quality - store in secondary with warning",
|
||||
"expr": "results.calculate_quality_score.quality_score >= 70",
|
||||
"modules": [
|
||||
{
|
||||
"id": "store_secondary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any, score: number) {\n return {\n destination: 'secondary_database',\n status: 'warning',\n warning_message: 'Data quality below optimal threshold',\n records_stored: data.total_record_count,\n quality_score: score\n };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.aggregate_data"
|
||||
},
|
||||
"score": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_quality_score.quality_score"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": [
|
||||
{
|
||||
"id": "store_quarantine",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any, score: number) {\n return {\n destination: 'quarantine',\n status: 'alert',\n alert_message: 'Data quality critically low - requires review',\n records_quarantined: data.total_record_count,\n quality_score: score\n };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.aggregate_data"
|
||||
},
|
||||
"score": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_quality_score.quality_score"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "generate_report",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(aggregated: any, quality: any, storage_result: any) {\n return {\n report: {\n total_records: aggregated.total_record_count,\n sources_processed: aggregated.sources_processed,\n quality_score: quality.quality_score,\n individual_scores: quality.individual_scores,\n destination: storage_result.destination,\n status: storage_result.status,\n processed_at: new Date().toISOString()\n }\n };\n}",
|
||||
"input_transforms": {
|
||||
"aggregated": {
|
||||
"type": "javascript",
|
||||
"expr": "results.aggregate_data"
|
||||
},
|
||||
"quality": {
|
||||
"type": "javascript",
|
||||
"expr": "results.calculate_quality_score"
|
||||
},
|
||||
"storage_result": {
|
||||
"type": "javascript",
|
||||
"expr": "results.route_by_quality"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,175 +1,175 @@
|
||||
{
|
||||
"summary": "AI-Powered Customer Support with Tools",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_customer_profile",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(customer_id: string) {\n // Mock customer profile and order history\n return {\n customer_id,\n name: 'John Doe',\n email: 'john.doe@example.com',\n membership_tier: 'gold',\n recent_orders: [\n { order_id: 'ORD-001', date: '2024-01-15', total: 149.99, status: 'delivered' },\n { order_id: 'ORD-002', date: '2024-02-20', total: 89.50, status: 'shipped' }\n ],\n support_history: [\n { ticket_id: 'TKT-100', issue: 'Delivery delay', resolved: true }\n ]\n };\n}",
|
||||
"input_transforms": {
|
||||
"customer_id": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.customer_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "support_agent",
|
||||
"value": {
|
||||
"type": "aiagent",
|
||||
"input_transforms": {
|
||||
"provider": {
|
||||
"type": "static",
|
||||
"value": "$res:f/ai_providers/openai"
|
||||
},
|
||||
"output_type": {
|
||||
"type": "static",
|
||||
"value": "text"
|
||||
},
|
||||
"user_message": {
|
||||
"type": "javascript",
|
||||
"expr": "`Customer Profile:\nName: ${results.fetch_customer_profile.name}\nMembership: ${results.fetch_customer_profile.membership_tier}\nRecent Orders: ${JSON.stringify(results.fetch_customer_profile.recent_orders)}\n\nCustomer Query: ${flow_input.query_text}`"
|
||||
},
|
||||
"system_prompt": {
|
||||
"type": "static",
|
||||
"value": "You are a helpful customer support agent. Use the available tools to look up order information, check refund eligibility, create support tickets, or search FAQs to help resolve customer queries. Be professional and empathetic."
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"id": "lookup_order",
|
||||
"summary": "Look up order details by order ID. Returns order status, items, and shipping information.",
|
||||
"value": {
|
||||
"tool_type": "flowmodule",
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order_id: string) {\n // Mock order lookup\n return {\n order_id,\n status: 'shipped',\n items: [\n { name: 'Wireless Headphones', quantity: 1, price: 79.99 },\n { name: 'Phone Case', quantity: 2, price: 19.99 }\n ],\n shipping: {\n carrier: 'FedEx',\n tracking_number: 'FX123456789',\n estimated_delivery: '2024-03-01'\n },\n total: 119.97\n };\n}",
|
||||
"input_transforms": {
|
||||
"order_id": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "check_refund_eligibility",
|
||||
"summary": "Check if an order is eligible for refund. Returns eligibility status and reason.",
|
||||
"value": {
|
||||
"tool_type": "flowmodule",
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order_id: string) {\n // Mock refund eligibility check\n return {\n order_id,\n eligible: true,\n reason: 'Within 30-day return window',\n refund_amount: 119.97,\n refund_method: 'original_payment_method',\n processing_time: '5-7 business days'\n };\n}",
|
||||
"input_transforms": {
|
||||
"order_id": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "create_support_ticket",
|
||||
"summary": "Create a support ticket with specified description and priority (low, medium, high).",
|
||||
"value": {
|
||||
"tool_type": "flowmodule",
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(description: string, priority: 'low' | 'medium' | 'high') {\n // Mock ticket creation\n return {\n ticket_id: `TKT-${Date.now()}`,\n description,\n priority,\n status: 'open',\n created_at: new Date().toISOString(),\n estimated_response: priority === 'high' ? '2 hours' : priority === 'medium' ? '24 hours' : '48 hours'\n };\n}",
|
||||
"input_transforms": {
|
||||
"description": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
},
|
||||
"priority": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "search_faq",
|
||||
"summary": "Search the FAQ database for relevant answers to common questions.",
|
||||
"value": {
|
||||
"tool_type": "flowmodule",
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(search_query: string) {\n // Mock FAQ search\n return {\n query: search_query,\n results: [\n {\n question: 'How do I track my order?',\n answer: 'You can track your order by logging into your account and clicking on \"Order History\". Each order has a tracking link.',\n relevance: 0.95\n },\n {\n question: 'What is the return policy?',\n answer: 'We offer a 30-day return policy for all unused items in original packaging. Refunds are processed within 5-7 business days.',\n relevance: 0.85\n }\n ]\n };\n}",
|
||||
"input_transforms": {
|
||||
"search_query": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parallel": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "log_interaction",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(customer_id: string, query: string, agent_response: string) {\n // Mock audit logging\n return {\n logged: true,\n log_id: `LOG-${Date.now()}`,\n timestamp: new Date().toISOString(),\n customer_id,\n query_summary: query.substring(0, 100),\n response_length: agent_response.length\n };\n}",
|
||||
"input_transforms": {
|
||||
"customer_id": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.customer_id"
|
||||
},
|
||||
"query": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.query_text"
|
||||
},
|
||||
"agent_response": {
|
||||
"type": "javascript",
|
||||
"expr": "results.support_agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_response",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(agent_response: string, log_info: any, customer_profile: any) {\n return {\n response: agent_response,\n customer_name: customer_profile.name,\n interaction_logged: log_info.logged,\n log_id: log_info.log_id\n };\n}",
|
||||
"input_transforms": {
|
||||
"agent_response": {
|
||||
"type": "javascript",
|
||||
"expr": "results.support_agent"
|
||||
},
|
||||
"log_info": {
|
||||
"type": "javascript",
|
||||
"expr": "results.log_interaction"
|
||||
},
|
||||
"customer_profile": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_customer_profile"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customer_id": {
|
||||
"type": "string",
|
||||
"description": "The unique identifier of the customer"
|
||||
},
|
||||
"query_text": {
|
||||
"type": "string",
|
||||
"description": "The customer's support query text"
|
||||
}
|
||||
},
|
||||
"required": ["customer_id", "query_text"]
|
||||
}
|
||||
"summary": "AI-Powered Customer Support with Tools",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_customer_profile",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(customer_id: string) {\n // Mock customer profile and order history\n return {\n customer_id,\n name: 'John Doe',\n email: 'john.doe@example.com',\n membership_tier: 'gold',\n recent_orders: [\n { order_id: 'ORD-001', date: '2024-01-15', total: 149.99, status: 'delivered' },\n { order_id: 'ORD-002', date: '2024-02-20', total: 89.50, status: 'shipped' }\n ],\n support_history: [\n { ticket_id: 'TKT-100', issue: 'Delivery delay', resolved: true }\n ]\n };\n}",
|
||||
"input_transforms": {
|
||||
"customer_id": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.customer_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "support_agent",
|
||||
"value": {
|
||||
"type": "aiagent",
|
||||
"input_transforms": {
|
||||
"provider": {
|
||||
"type": "static",
|
||||
"value": "$res:f/ai_providers/openai"
|
||||
},
|
||||
"output_type": {
|
||||
"type": "static",
|
||||
"value": "text"
|
||||
},
|
||||
"user_message": {
|
||||
"type": "javascript",
|
||||
"expr": "`Customer Profile:\nName: ${results.fetch_customer_profile.name}\nMembership: ${results.fetch_customer_profile.membership_tier}\nRecent Orders: ${JSON.stringify(results.fetch_customer_profile.recent_orders)}\n\nCustomer Query: ${flow_input.query_text}`"
|
||||
},
|
||||
"system_prompt": {
|
||||
"type": "static",
|
||||
"value": "You are a helpful customer support agent. Use the available tools to look up order information, check refund eligibility, create support tickets, or search FAQs to help resolve customer queries. Be professional and empathetic."
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"id": "lookup_order",
|
||||
"summary": "Look up order details by order ID. Returns order status, items, and shipping information.",
|
||||
"value": {
|
||||
"tool_type": "flowmodule",
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order_id: string) {\n // Mock order lookup\n return {\n order_id,\n status: 'shipped',\n items: [\n { name: 'Wireless Headphones', quantity: 1, price: 79.99 },\n { name: 'Phone Case', quantity: 2, price: 19.99 }\n ],\n shipping: {\n carrier: 'FedEx',\n tracking_number: 'FX123456789',\n estimated_delivery: '2024-03-01'\n },\n total: 119.97\n };\n}",
|
||||
"input_transforms": {
|
||||
"order_id": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "check_refund_eligibility",
|
||||
"summary": "Check if an order is eligible for refund. Returns eligibility status and reason.",
|
||||
"value": {
|
||||
"tool_type": "flowmodule",
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order_id: string) {\n // Mock refund eligibility check\n return {\n order_id,\n eligible: true,\n reason: 'Within 30-day return window',\n refund_amount: 119.97,\n refund_method: 'original_payment_method',\n processing_time: '5-7 business days'\n };\n}",
|
||||
"input_transforms": {
|
||||
"order_id": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "create_support_ticket",
|
||||
"summary": "Create a support ticket with specified description and priority (low, medium, high).",
|
||||
"value": {
|
||||
"tool_type": "flowmodule",
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(description: string, priority: 'low' | 'medium' | 'high') {\n // Mock ticket creation\n return {\n ticket_id: `TKT-${Date.now()}`,\n description,\n priority,\n status: 'open',\n created_at: new Date().toISOString(),\n estimated_response: priority === 'high' ? '2 hours' : priority === 'medium' ? '24 hours' : '48 hours'\n };\n}",
|
||||
"input_transforms": {
|
||||
"description": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
},
|
||||
"priority": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "search_faq",
|
||||
"summary": "Search the FAQ database for relevant answers to common questions.",
|
||||
"value": {
|
||||
"tool_type": "flowmodule",
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(search_query: string) {\n // Mock FAQ search\n return {\n query: search_query,\n results: [\n {\n question: 'How do I track my order?',\n answer: 'You can track your order by logging into your account and clicking on \"Order History\". Each order has a tracking link.',\n relevance: 0.95\n },\n {\n question: 'What is the return policy?',\n answer: 'We offer a 30-day return policy for all unused items in original packaging. Refunds are processed within 5-7 business days.',\n relevance: 0.85\n }\n ]\n };\n}",
|
||||
"input_transforms": {
|
||||
"search_query": {
|
||||
"type": "static",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parallel": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "log_interaction",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(customer_id: string, query: string, agent_response: string) {\n // Mock audit logging\n return {\n logged: true,\n log_id: `LOG-${Date.now()}`,\n timestamp: new Date().toISOString(),\n customer_id,\n query_summary: query.substring(0, 100),\n response_length: agent_response.length\n };\n}",
|
||||
"input_transforms": {
|
||||
"customer_id": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.customer_id"
|
||||
},
|
||||
"query": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.query_text"
|
||||
},
|
||||
"agent_response": {
|
||||
"type": "javascript",
|
||||
"expr": "results.support_agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_response",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(agent_response: string, log_info: any, customer_profile: any) {\n return {\n response: agent_response,\n customer_name: customer_profile.name,\n interaction_logged: log_info.logged,\n log_id: log_info.log_id\n };\n}",
|
||||
"input_transforms": {
|
||||
"agent_response": {
|
||||
"type": "javascript",
|
||||
"expr": "results.support_agent"
|
||||
},
|
||||
"log_info": {
|
||||
"type": "javascript",
|
||||
"expr": "results.log_interaction"
|
||||
},
|
||||
"customer_profile": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_customer_profile"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customer_id": {
|
||||
"type": "string",
|
||||
"description": "The unique identifier of the customer"
|
||||
},
|
||||
"query_text": {
|
||||
"type": "string",
|
||||
"description": "The customer's support query text"
|
||||
}
|
||||
},
|
||||
"required": ["customer_id", "query_text"]
|
||||
}
|
||||
}
|
||||
|
||||
+66
-66
@@ -1,68 +1,68 @@
|
||||
{
|
||||
"summary": "Simple data pipeline with validation",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_data",
|
||||
"summary": "Fetch data from API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n // Mock API call\n return [\n { id: 1, name: \"Item 1\", value: 100 },\n { id: 2, name: \"Item 2\", value: 200 },\n { id: 3, name: \"Item 3\", value: 300 }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "process_data",
|
||||
"summary": "Process the fetched data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any[]) {\n // Apply some transformation\n return data.map(item => ({\n ...item,\n value: item.value * 1.1,\n processed: true\n }));\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "validate_data",
|
||||
"summary": "Validate processed data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any[]) {\n if (!data || data.length === 0) {\n return { error: true, message: \"No data to save\" };\n }\n return { error: false, data: data };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "save_results",
|
||||
"summary": "Save results to database",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(validated: any) {\n if (validated.error) {\n return { saved: 0, status: \"skipped\", reason: validated.message };\n }\n // Mock database save\n console.log(`Saving ${validated.data.length} items to database`);\n return { saved: validated.data.length, status: \"success\" };\n}",
|
||||
"input_transforms": {
|
||||
"validated": {
|
||||
"type": "javascript",
|
||||
"expr": "results.validate_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
"summary": "Simple data pipeline with validation",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_data",
|
||||
"summary": "Fetch data from API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n // Mock API call\n return [\n { id: 1, name: \"Item 1\", value: 100 },\n { id: 2, name: \"Item 2\", value: 200 },\n { id: 3, name: \"Item 3\", value: 300 }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "process_data",
|
||||
"summary": "Process the fetched data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any[]) {\n // Apply some transformation\n return data.map(item => ({\n ...item,\n value: item.value * 1.1,\n processed: true\n }));\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "validate_data",
|
||||
"summary": "Validate processed data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any[]) {\n if (!data || data.length === 0) {\n return { error: true, message: \"No data to save\" };\n }\n return { error: false, data: data };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "save_results",
|
||||
"summary": "Save results to database",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(validated: any) {\n if (validated.error) {\n return { saved: 0, status: \"skipped\", reason: validated.message };\n }\n // Mock database save\n console.log(`Saving ${validated.data.length} items to database`);\n return { saved: validated.data.length, status: \"success\" };\n}",
|
||||
"input_transforms": {
|
||||
"validated": {
|
||||
"type": "javascript",
|
||||
"expr": "results.validate_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
+140
-140
@@ -1,142 +1,142 @@
|
||||
{
|
||||
"summary": "Order processing flow with type-based branching",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "get_orders",
|
||||
"summary": "Fetch list of orders",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n // Mock orders from database\n return [\n { id: \"ORD-001\", type: \"express\", items: 3, total: 150 },\n { id: \"ORD-002\", type: \"standard\", items: 5, total: 280 },\n { id: \"ORD-003\", type: \"pickup\", items: 2, total: 75 },\n { id: \"ORD-004\", type: \"express\", items: 1, total: 50 }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "loop_orders",
|
||||
"summary": "Process each order",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_orders"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"parallel": false,
|
||||
"modules": [
|
||||
{
|
||||
"id": "branch_order_type",
|
||||
"summary": "Branch based on order type",
|
||||
"value": {
|
||||
"type": "branchone",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "Express Order",
|
||||
"expr": "flow_input.iter.value.type === 'express'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "handle_express",
|
||||
"summary": "Handle express order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n // Mark as priority and calculate express shipping\n const expressShippingCost = 15.99;\n return {\n orderId: order.id,\n priority: true,\n shippingCost: expressShippingCost,\n shippingType: \"express\",\n estimatedDays: 1\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Standard Order",
|
||||
"expr": "flow_input.iter.value.type === 'standard'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "handle_standard",
|
||||
"summary": "Handle standard order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n // Calculate standard shipping cost\n const standardShippingCost = 5.99;\n return {\n orderId: order.id,\n priority: false,\n shippingCost: standardShippingCost,\n shippingType: \"standard\",\n estimatedDays: 5\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Pickup Order",
|
||||
"expr": "flow_input.iter.value.type === 'pickup'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "handle_pickup",
|
||||
"summary": "Handle pickup order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n // Mark as no shipping required\n return {\n orderId: order.id,\n priority: false,\n shippingCost: 0,\n shippingType: \"pickup\",\n estimatedDays: 0,\n pickupLocation: \"Store #1\"\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": [
|
||||
{
|
||||
"id": "process_order",
|
||||
"summary": "Process unknown order type",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n console.log(`Processing order ${order.id} with unknown type`);\n return {\n orderId: order.id,\n processed: true,\n shippingType: \"unknown\",\n timestamp: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "summarize",
|
||||
"summary": "Return processing summary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(results: any[]) {\n return {\n totalProcessed: results.length,\n processedAt: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"results": {
|
||||
"type": "javascript",
|
||||
"expr": "results.loop_orders"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
"summary": "Order processing flow with type-based branching",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "get_orders",
|
||||
"summary": "Fetch list of orders",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n // Mock orders from database\n return [\n { id: \"ORD-001\", type: \"express\", items: 3, total: 150 },\n { id: \"ORD-002\", type: \"standard\", items: 5, total: 280 },\n { id: \"ORD-003\", type: \"pickup\", items: 2, total: 75 },\n { id: \"ORD-004\", type: \"express\", items: 1, total: 50 }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "loop_orders",
|
||||
"summary": "Process each order",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_orders"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"parallel": false,
|
||||
"modules": [
|
||||
{
|
||||
"id": "branch_order_type",
|
||||
"summary": "Branch based on order type",
|
||||
"value": {
|
||||
"type": "branchone",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "Express Order",
|
||||
"expr": "flow_input.iter.value.type === 'express'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "handle_express",
|
||||
"summary": "Handle express order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n // Mark as priority and calculate express shipping\n const expressShippingCost = 15.99;\n return {\n orderId: order.id,\n priority: true,\n shippingCost: expressShippingCost,\n shippingType: \"express\",\n estimatedDays: 1\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Standard Order",
|
||||
"expr": "flow_input.iter.value.type === 'standard'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "handle_standard",
|
||||
"summary": "Handle standard order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n // Calculate standard shipping cost\n const standardShippingCost = 5.99;\n return {\n orderId: order.id,\n priority: false,\n shippingCost: standardShippingCost,\n shippingType: \"standard\",\n estimatedDays: 5\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Pickup Order",
|
||||
"expr": "flow_input.iter.value.type === 'pickup'",
|
||||
"modules": [
|
||||
{
|
||||
"id": "handle_pickup",
|
||||
"summary": "Handle pickup order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n // Mark as no shipping required\n return {\n orderId: order.id,\n priority: false,\n shippingCost: 0,\n shippingType: \"pickup\",\n estimatedDays: 0,\n pickupLocation: \"Store #1\"\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": [
|
||||
{
|
||||
"id": "process_order",
|
||||
"summary": "Process unknown order type",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n console.log(`Processing order ${order.id} with unknown type`);\n return {\n orderId: order.id,\n processed: true,\n shippingType: \"unknown\",\n timestamp: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "summarize",
|
||||
"summary": "Return processing summary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(results: any[]) {\n return {\n totalProcessed: results.length,\n processedAt: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"results": {
|
||||
"type": "javascript",
|
||||
"expr": "results.loop_orders"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
+134
-134
@@ -1,136 +1,136 @@
|
||||
{
|
||||
"summary": "Data enrichment flow with parallel processing",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "get_item",
|
||||
"summary": "Get item from input",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item_id: string) {\n // Mock item lookup\n return {\n id: item_id,\n name: \"Product \" + item_id,\n sku: \"SKU-\" + item_id\n };\n}",
|
||||
"input_transforms": {
|
||||
"item_id": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.item_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "parallel_enrichment",
|
||||
"summary": "Enrich data in parallel",
|
||||
"value": {
|
||||
"type": "branchall",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "Price enrichment",
|
||||
"modules": [
|
||||
{
|
||||
"id": "enrich_price",
|
||||
"summary": "Call pricing API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock pricing API call with timeout handling\n try {\n return {\n itemId: item.id,\n price: 99.99,\n currency: \"USD\",\n discount: 10\n };\n } catch (e) {\n return { itemId: item.id, price: 0, currency: \"USD\", fallback: true };\n }\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Inventory enrichment",
|
||||
"modules": [
|
||||
{
|
||||
"id": "enrich_inventory",
|
||||
"summary": "Call inventory API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock inventory API call with timeout handling\n try {\n return {\n itemId: item.id,\n inStock: true,\n quantity: 150,\n warehouse: \"WH-001\"\n };\n } catch (e) {\n return { itemId: item.id, inStock: false, quantity: 0, fallback: true };\n }\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Reviews enrichment",
|
||||
"modules": [
|
||||
{
|
||||
"id": "enrich_reviews",
|
||||
"summary": "Call reviews API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock reviews API call with timeout handling\n try {\n return {\n itemId: item.id,\n averageRating: 4.5,\n reviewCount: 127,\n topReview: \"Great product!\"\n };\n } catch (e) {\n return { itemId: item.id, averageRating: 0, reviewCount: 0, fallback: true };\n }\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "combine_data",
|
||||
"summary": "Combine all enrichment data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any, parallel_results: any) {\n // Extract results from parallel branches\n const [priceResult, inventoryResult, reviewsResult] = parallel_results;\n return {\n ...item,\n pricing: priceResult,\n inventory: inventoryResult,\n reviews: reviewsResult,\n hasFallbacks: priceResult?.fallback || inventoryResult?.fallback || reviewsResult?.fallback\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
},
|
||||
"parallel_results": {
|
||||
"type": "javascript",
|
||||
"expr": "results.parallel_enrichment"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_result",
|
||||
"summary": "Return final result",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(enriched_item: any) {\n return {\n success: true,\n data: enriched_item,\n enrichedAt: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"enriched_item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.combine_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"item_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the item to enrich"
|
||||
}
|
||||
},
|
||||
"required": ["item_id"],
|
||||
"type": "object"
|
||||
}
|
||||
"summary": "Data enrichment flow with parallel processing",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "get_item",
|
||||
"summary": "Get item from input",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item_id: string) {\n // Mock item lookup\n return {\n id: item_id,\n name: \"Product \" + item_id,\n sku: \"SKU-\" + item_id\n };\n}",
|
||||
"input_transforms": {
|
||||
"item_id": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.item_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "parallel_enrichment",
|
||||
"summary": "Enrich data in parallel",
|
||||
"value": {
|
||||
"type": "branchall",
|
||||
"branches": [
|
||||
{
|
||||
"summary": "Price enrichment",
|
||||
"modules": [
|
||||
{
|
||||
"id": "enrich_price",
|
||||
"summary": "Call pricing API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock pricing API call with timeout handling\n try {\n return {\n itemId: item.id,\n price: 99.99,\n currency: \"USD\",\n discount: 10\n };\n } catch (e) {\n return { itemId: item.id, price: 0, currency: \"USD\", fallback: true };\n }\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Inventory enrichment",
|
||||
"modules": [
|
||||
{
|
||||
"id": "enrich_inventory",
|
||||
"summary": "Call inventory API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock inventory API call with timeout handling\n try {\n return {\n itemId: item.id,\n inStock: true,\n quantity: 150,\n warehouse: \"WH-001\"\n };\n } catch (e) {\n return { itemId: item.id, inStock: false, quantity: 0, fallback: true };\n }\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"summary": "Reviews enrichment",
|
||||
"modules": [
|
||||
{
|
||||
"id": "enrich_reviews",
|
||||
"summary": "Call reviews API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock reviews API call with timeout handling\n try {\n return {\n itemId: item.id,\n averageRating: 4.5,\n reviewCount: 127,\n topReview: \"Great product!\"\n };\n } catch (e) {\n return { itemId: item.id, averageRating: 0, reviewCount: 0, fallback: true };\n }\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "combine_data",
|
||||
"summary": "Combine all enrichment data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any, parallel_results: any) {\n // Extract results from parallel branches\n const [priceResult, inventoryResult, reviewsResult] = parallel_results;\n return {\n ...item,\n pricing: priceResult,\n inventory: inventoryResult,\n reviews: reviewsResult,\n hasFallbacks: priceResult?.fallback || inventoryResult?.fallback || reviewsResult?.fallback\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
},
|
||||
"parallel_results": {
|
||||
"type": "javascript",
|
||||
"expr": "results.parallel_enrichment"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_result",
|
||||
"summary": "Return final result",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(enriched_item: any) {\n return {\n success: true,\n data: enriched_item,\n enrichedAt: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"enriched_item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.combine_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"item_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the item to enrich"
|
||||
}
|
||||
},
|
||||
"required": ["item_id"],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { runVariantComparison, writeFlowComparisonResults, type ExpectedFlow } from './flowEvalRunner'
|
||||
import {
|
||||
runVariantComparison,
|
||||
writeFlowComparisonResults,
|
||||
type ExpectedFlow
|
||||
} from './flowEvalRunner'
|
||||
import { BASELINE_VARIANT, MINIMAL_SINGLE_TOOL_VARIANT } from './variants'
|
||||
// @ts-ignore - JSON import
|
||||
import expectedTest1 from './expected/test1.json'
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import type { ExtendedOpenFlow } from '$lib/components/flows/types'
|
||||
import { flowTools, prepareFlowSystemMessage, prepareFlowUserMessage, type FlowAIChatHelpers } from '../../flow/core'
|
||||
import {
|
||||
flowTools,
|
||||
prepareFlowSystemMessage,
|
||||
prepareFlowUserMessage,
|
||||
type FlowAIChatHelpers
|
||||
} from '../../flow/core'
|
||||
import { createFlowEvalHelpers } from './flowEvalHelpers'
|
||||
import { evaluateFlowComparison, type ExpectedFlow } from './flowEvalComparison'
|
||||
import {
|
||||
@@ -64,7 +69,11 @@ export async function runFlowEval(
|
||||
|
||||
// Resolve variant configuration
|
||||
const variantName = options?.variant?.name ?? 'baseline'
|
||||
const systemMessage = resolveSystemPrompt(options?.variant, flowDefaults, options?.customSystemPrompt)
|
||||
const systemMessage = resolveSystemPrompt(
|
||||
options?.variant,
|
||||
flowDefaults,
|
||||
options?.customSystemPrompt
|
||||
)
|
||||
const { toolDefs, tools } = resolveTools(options?.variant, flowDefaults)
|
||||
const model = resolveModel(options?.variant, options?.model)
|
||||
|
||||
|
||||
+51
-51
@@ -1,53 +1,53 @@
|
||||
{
|
||||
"summary": "Simple data pipeline",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_data",
|
||||
"summary": "Fetch data from API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n // Mock API call\n return [\n { id: 1, name: \"Item 1\", value: 100 },\n { id: 2, name: \"Item 2\", value: 200 },\n { id: 3, name: \"Item 3\", value: 300 }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "process_data",
|
||||
"summary": "Process the fetched data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any[]) {\n // Apply some transformation\n return data.map(item => ({\n ...item,\n value: item.value * 1.1,\n processed: true\n }));\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "save_results",
|
||||
"summary": "Save results to database",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any[]) {\n // Mock database save\n console.log(`Saving ${data.length} items to database`);\n return { saved: data.length, status: \"success\" };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
"summary": "Simple data pipeline",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "fetch_data",
|
||||
"summary": "Fetch data from API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n // Mock API call\n return [\n { id: 1, name: \"Item 1\", value: 100 },\n { id: 2, name: \"Item 2\", value: 200 },\n { id: 3, name: \"Item 3\", value: 300 }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "process_data",
|
||||
"summary": "Process the fetched data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any[]) {\n // Apply some transformation\n return data.map(item => ({\n ...item,\n value: item.value * 1.1,\n processed: true\n }));\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.fetch_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "save_results",
|
||||
"summary": "Save results to database",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(data: any[]) {\n // Mock database save\n console.log(`Saving ${data.length} items to database`);\n return { saved: data.length, status: \"success\" };\n}",
|
||||
"input_transforms": {
|
||||
"data": {
|
||||
"type": "javascript",
|
||||
"expr": "results.process_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
+66
-66
@@ -1,68 +1,68 @@
|
||||
{
|
||||
"summary": "Order processing flow",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "get_orders",
|
||||
"summary": "Fetch list of orders",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n // Mock orders from database\n return [\n { id: \"ORD-001\", type: \"express\", items: 3, total: 150 },\n { id: \"ORD-002\", type: \"standard\", items: 5, total: 280 },\n { id: \"ORD-003\", type: \"pickup\", items: 2, total: 75 },\n { id: \"ORD-004\", type: \"express\", items: 1, total: 50 }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "loop_orders",
|
||||
"summary": "Process each order",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_orders"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"parallel": false,
|
||||
"modules": [
|
||||
{
|
||||
"id": "process_order",
|
||||
"summary": "Process individual order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n console.log(`Processing order ${order.id}`);\n return {\n orderId: order.id,\n processed: true,\n timestamp: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "summarize",
|
||||
"summary": "Return processing summary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(results: any[]) {\n return {\n totalProcessed: results.length,\n processedAt: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"results": {
|
||||
"type": "javascript",
|
||||
"expr": "results.loop_orders"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
"summary": "Order processing flow",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "get_orders",
|
||||
"summary": "Fetch list of orders",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main() {\n // Mock orders from database\n return [\n { id: \"ORD-001\", type: \"express\", items: 3, total: 150 },\n { id: \"ORD-002\", type: \"standard\", items: 5, total: 280 },\n { id: \"ORD-003\", type: \"pickup\", items: 2, total: 75 },\n { id: \"ORD-004\", type: \"express\", items: 1, total: 50 }\n ];\n}",
|
||||
"input_transforms": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "loop_orders",
|
||||
"summary": "Process each order",
|
||||
"value": {
|
||||
"type": "forloopflow",
|
||||
"iterator": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_orders"
|
||||
},
|
||||
"skip_failures": false,
|
||||
"parallel": false,
|
||||
"modules": [
|
||||
{
|
||||
"id": "process_order",
|
||||
"summary": "Process individual order",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(order: any) {\n console.log(`Processing order ${order.id}`);\n return {\n orderId: order.id,\n processed: true,\n timestamp: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"order": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.iter.value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "summarize",
|
||||
"summary": "Return processing summary",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(results: any[]) {\n return {\n totalProcessed: results.length,\n processedAt: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"results": {
|
||||
"type": "javascript",
|
||||
"expr": "results.loop_orders"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
+118
-118
@@ -1,120 +1,120 @@
|
||||
{
|
||||
"summary": "Data enrichment flow",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "get_item",
|
||||
"summary": "Get item from input",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item_id: string) {\n // Mock item lookup\n return {\n id: item_id,\n name: \"Product \" + item_id,\n sku: \"SKU-\" + item_id\n };\n}",
|
||||
"input_transforms": {
|
||||
"item_id": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.item_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "enrich_price",
|
||||
"summary": "Call pricing API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock pricing API call\n return {\n itemId: item.id,\n price: 99.99,\n currency: \"USD\",\n discount: 10\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "enrich_inventory",
|
||||
"summary": "Call inventory API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock inventory API call\n return {\n itemId: item.id,\n inStock: true,\n quantity: 150,\n warehouse: \"WH-001\"\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "enrich_reviews",
|
||||
"summary": "Call reviews API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock reviews API call\n return {\n itemId: item.id,\n averageRating: 4.5,\n reviewCount: 127,\n topReview: \"Great product!\"\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "combine_data",
|
||||
"summary": "Combine all enrichment data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any, price: any, inventory: any, reviews: any) {\n return {\n ...item,\n pricing: price,\n inventory: inventory,\n reviews: reviews\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
},
|
||||
"price": {
|
||||
"type": "javascript",
|
||||
"expr": "results.enrich_price"
|
||||
},
|
||||
"inventory": {
|
||||
"type": "javascript",
|
||||
"expr": "results.enrich_inventory"
|
||||
},
|
||||
"reviews": {
|
||||
"type": "javascript",
|
||||
"expr": "results.enrich_reviews"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_result",
|
||||
"summary": "Return final result",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(enriched_item: any) {\n return {\n success: true,\n data: enriched_item,\n enrichedAt: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"enriched_item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.combine_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"item_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the item to enrich"
|
||||
}
|
||||
},
|
||||
"required": ["item_id"],
|
||||
"type": "object"
|
||||
}
|
||||
"summary": "Data enrichment flow",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "get_item",
|
||||
"summary": "Get item from input",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item_id: string) {\n // Mock item lookup\n return {\n id: item_id,\n name: \"Product \" + item_id,\n sku: \"SKU-\" + item_id\n };\n}",
|
||||
"input_transforms": {
|
||||
"item_id": {
|
||||
"type": "javascript",
|
||||
"expr": "flow_input.item_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "enrich_price",
|
||||
"summary": "Call pricing API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock pricing API call\n return {\n itemId: item.id,\n price: 99.99,\n currency: \"USD\",\n discount: 10\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "enrich_inventory",
|
||||
"summary": "Call inventory API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock inventory API call\n return {\n itemId: item.id,\n inStock: true,\n quantity: 150,\n warehouse: \"WH-001\"\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "enrich_reviews",
|
||||
"summary": "Call reviews API",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any) {\n // Mock reviews API call\n return {\n itemId: item.id,\n averageRating: 4.5,\n reviewCount: 127,\n topReview: \"Great product!\"\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "combine_data",
|
||||
"summary": "Combine all enrichment data",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(item: any, price: any, inventory: any, reviews: any) {\n return {\n ...item,\n pricing: price,\n inventory: inventory,\n reviews: reviews\n };\n}",
|
||||
"input_transforms": {
|
||||
"item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.get_item"
|
||||
},
|
||||
"price": {
|
||||
"type": "javascript",
|
||||
"expr": "results.enrich_price"
|
||||
},
|
||||
"inventory": {
|
||||
"type": "javascript",
|
||||
"expr": "results.enrich_inventory"
|
||||
},
|
||||
"reviews": {
|
||||
"type": "javascript",
|
||||
"expr": "results.enrich_reviews"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "return_result",
|
||||
"summary": "Return final result",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "bun",
|
||||
"content": "export async function main(enriched_item: any) {\n return {\n success: true,\n data: enriched_item,\n enrichedAt: new Date().toISOString()\n };\n}",
|
||||
"input_transforms": {
|
||||
"enriched_item": {
|
||||
"type": "javascript",
|
||||
"expr": "results.combine_data"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"item_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the item to enrich"
|
||||
}
|
||||
},
|
||||
"required": ["item_id"],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import OpenAI, { APIError } from 'openai'
|
||||
import type { ChatCompletionMessageParam, ChatCompletionSystemMessageParam } from 'openai/resources/chat/completions.mjs'
|
||||
import type {
|
||||
ChatCompletionMessageParam,
|
||||
ChatCompletionSystemMessageParam
|
||||
} from 'openai/resources/chat/completions.mjs'
|
||||
import type { ChatCompletionTool } from 'openai/resources/chat/completions.mjs'
|
||||
import type { TokenUsage, ToolCallDetail, EvalRunnerOptions } from './types'
|
||||
import type { Tool } from './baseVariants'
|
||||
@@ -52,16 +55,8 @@ export interface RunEvalParams<THelpers, TOutput> {
|
||||
export async function runEval<THelpers, TOutput>(
|
||||
params: RunEvalParams<THelpers, TOutput>
|
||||
): Promise<RawEvalResult<TOutput>> {
|
||||
const {
|
||||
systemMessage,
|
||||
userMessage,
|
||||
toolDefs,
|
||||
tools,
|
||||
helpers,
|
||||
apiKey,
|
||||
getOutput,
|
||||
options
|
||||
} = params
|
||||
const { systemMessage, userMessage, toolDefs, tools, helpers, apiKey, getOutput, options } =
|
||||
params
|
||||
|
||||
const client = new OpenAI({ baseURL: 'https://openrouter.ai/api/v1', apiKey })
|
||||
const model = options?.model ?? 'gpt-4o'
|
||||
|
||||
@@ -8,7 +8,7 @@ import { getDocumentationTool } from '../navigator/core'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { get } from 'svelte/store'
|
||||
|
||||
export const CHAT_SYSTEM_PROMPT = (username: string) =>`
|
||||
export const CHAT_SYSTEM_PROMPT = (username: string) => `
|
||||
You are Windmill's intelligent assistant, designed to interact with the platform via API endpoints and answer questions about its functionality. Your purpose is to help the user directly query and manipulate Windmill resources through API calls.
|
||||
|
||||
Windmill is an open-source developer platform for building internal tools, API integrations, background jobs, workflows, and user interfaces. It offers a unified system where scripts are automatically turned into sharable UIs and can be composed into flows or embedded in custom applications.
|
||||
@@ -76,4 +76,4 @@ export function prepareApiUserMessage(instructions: string): ChatCompletionUserM
|
||||
role: 'user',
|
||||
content: instructions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,22 @@
|
||||
</script>
|
||||
|
||||
<Modal bind:open title="AI Changes Will Be Lost">
|
||||
<div slot="title" class="flex items-center gap-2">
|
||||
<AlertTriangleIcon size={20} class="text-orange-500" />
|
||||
AI Changes Will Be Lost
|
||||
</div>
|
||||
<div class="py-4">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<AlertTriangleIcon size={20} class="text-orange-500" />
|
||||
<span class="font-medium">Warning</span>
|
||||
</div>
|
||||
<p class="text-gray-700 dark:text-gray-300">
|
||||
You have pending AI changes that will be rejected when saving. Do you want to continue?
|
||||
</p>
|
||||
</div>
|
||||
<div slot="actions">
|
||||
<div class="flex gap-2 justify-end">
|
||||
<Button variant="contained" color="red" on:click={handleConfirm}>
|
||||
Reject changes and save
|
||||
</Button>
|
||||
{#snippet actions()}
|
||||
<div>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<Button variant="contained" color="red" onclick={handleConfirm}>
|
||||
Reject changes and save
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Modal>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,65 +1,86 @@
|
||||
export const EDIT_PROMPT = {
|
||||
"system": "You are a helpful coding assistant for Windmill, a developer platform for running scripts. You modify code as instructed by the user. Each user message includes some contextual information which should guide your answer.\nOnly output code. Wrap the code in a code block. \nPut explanations directly in the code as comments.\nReturn the complete modified code.\n\nHere's how interactions have to look like:\nuser: {sample_question}\nassistant: ```language\n{code}\n```",
|
||||
"prompts": {
|
||||
"python3": {
|
||||
"prompt": "Here's my python3 code: \n```python\n{code}\n```\n<contextual_information>\nYou have to write a function in python called \"main\". Specify the parameter types. Do not call the main function. You should generally return the result.\nThe \"main\" function cannot be async. If you need to use async code, you can use the asyncio library.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. For Windmill to correctly detect the resources to be passed, the resource type name has to be exactly as specified in the following list:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nYou need to define the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose.\nThe resource type name has to be exactly as specified (has to be IN LOEWRCASE). If the type name conflicts with any imported methods, you have to rename the imported method with the conflicting name.\n<contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"deno": {
|
||||
"prompt": "Here's my TypeScript code in a deno running environment:\n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a \"main\" function like this: \"export async function main(...)\" and specify the parameter types but do not call it. You should generally return the result.\nIf needed, the standard fetch method is available globally, do not import it.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: \"{resource_type}Resource\". \nThe resource type name has to be exactly as specified.\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user's naming choices in the existing code.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"rust": {
|
||||
"prompt": "Here's my Rust code:\n```rust\n{code}\n```\n<contextual_information>\nPlease define a `main` function in Rust with this signature:\n```rust\npub fn main(...) -> Result<ReturnType, Box<dyn std::error::Error>>\n```\nbut do not call it. Favor idiomatic Rust patterns, ensuring safe handling of ownership and borrowing, robust error handling with `Result`, and concurrency if needed (`async`/`tokio` or std threading). \n\nFollow these guidelines:\n- Include necessary imports and modules only when needed.\n- Add comments explaining important operations and any unsafe usage (if absolutely required).\n- The generated code should be easily executable and testable in an integrated terminal.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"go": {
|
||||
"prompt": "Here's my go code: \n```go\n{code}\n```\n<contextual_information>\nWe have to export a \"main\" function. Import the packages you need. The return type of the function has to be ({return_type}, error). The file package has to be \"inner\"\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"bash": {
|
||||
"prompt": "Here's my bash code: \n```shell\n{code}\n```\n<contextual_information>\nDo not include \"#!/bin/bash\". Arguments are always string and can only be obtained with \"var1=\"$1\"\", \"var2=\"$2\"\", etc... You do not need to check if the arguments are present.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"postgresql": {
|
||||
"prompt": "Here's my PostgreSQL code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with `$1::{type}`, `$2::{type}`, etc... Name the parameters (without specifying the type) by adding comments before the statement like that: `-- $1 name1` or `-- $2 name = default` (one per row)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"mysql": {
|
||||
"prompt": "Here's my MySQL code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the statement like that: `-- ? name1 ({type})` or `-- ? name2 ({type}) = default` (one per row)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"bigquery": {
|
||||
"prompt": "Here's my BigQuery code: \n```sql\n{code}\n```\n<contextual_information>\nYou can define arguments by adding comments before the statement like that: `-- @name1 ({type})` or `-- @name2 ({type}) = default` (one per row). They can then be obtained directly in the statement with `@name1`, `@name2`, etc....\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"snowflake": {
|
||||
"prompt": "Here's my snowflake code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the statement like that: `-- ? name1 ({type})` or `-- ? name2 ({type}) = default` (one per row)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"mssql": {
|
||||
"prompt": "Here's my Microsoft SQL Server code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with @P1, @P2, etc.. Name the parameters by adding comments before the statement like that: `-- @P1 name1 ({type})` or `-- @P2 name2 ({type}) = default` (one per row)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"graphql": {
|
||||
"prompt": "Here's my graphql code: \n```graphql\n{code}\n```\n<contextual_information>\nAdd the needed arguments as query parameters.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"powershell": {
|
||||
"prompt": "Here's my powershell code: \n```powershell\n{code}\n```\n<contextual_information>\nArguments can be obtained by calling the param function on the first line like that: `param($ParamName1, $ParamName2 = \"default value\", [{type}]$ParamName3, ...)`\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"nativets": {
|
||||
"prompt": "Here's my TypeScript code: \n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a \"main\" function like this: \"export async function main(...)\" and specify the parameter types but do not call it. You should generally return the result.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: \"{resource_type}Resource\".\nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user's naming choices in the existing code.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"bun": {
|
||||
"prompt": "Here's my TypeScript code: \n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a \"main\" function like this: \"export async function main(...)\" and specify the parameter types but do not call it. You should generally return the result.\nIf needed, the standard fetch method is available globally, do not import it.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: \"{resource_type}Resource\". \nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user's naming choices in the existing code.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"php": {
|
||||
"prompt": "Here's my php code: \n```php\n{code}\n```\n<contextual_information>\nYou have to write a function in php called \"main\". Specify the parameter types. Do not call the main function. You should generally return the result. The script must start with `<?php`.\nYou can take as parameters resources which are classes containing credentials or configuration information. For Windmill to correctly detect the resources to be passed, the resource type name has to be exactly as specified in the following list:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nYou need to define the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose.\nBefore defining each type, check if the class already exists using class_exists.\nThe resource type name has to be exactly as specified.\nIf you need to import libraries, you need to specify them as comments in the following manner before the main function:\n```\n// require:\n// mylibrary/mylibrary\n// myotherlibrary/myotherlibrary@optionalversion\n```\nNo need to require autoload, it is already done.\n<contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"csharp": {
|
||||
"prompt": "Here's my C# code:\n```csharp\n{code}\n```\n<contextual_information>\nYou have to write C# code with a public static Main method inside a class. The class name is irrelevant. Specify the parameter types. Do not call the main function. You should generally return the result.\nNuGet packages can be added using the format: #r \"nuget: PackageName, Version\" at the top of the script.\nThe Main method signature should be: public static ReturnType Main(parameter types...)\nArguments are used to generate the input specification and create the frontend UI for the script.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"java": {
|
||||
"prompt": "Here's my Java code:\n```java\n{code}\n```\n<contextual_information>\nYou have to write Java code with a Main public class and a public static main() method. The return type can be Object or void. Do not call the main function. You should generally return the result.\nDependencies can be added using the format: //requirements://groupId:artifactId:version at the top of the script.\nThe method signature should be: public static Object main(parameter types...)\nArguments are used to generate the input specification and create the frontend UI for the script.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"frontend": {
|
||||
"prompt": "Here's my client-side javascript code: \n```javascript\n{code}\n```\n<contextual_information>\nYou can access the context object with the ctx global variable. \nThe app state is a store that can be used to store data. You can access and update the state object with the state global variable like this: state.foo = 'bar'\nYou can use the goto function to navigate to a specific URL: goto(path: string, newTab?: boolean)\nYou can use the openModal and closeModal functions to open and close a modal: openModal(id: string), closeModal(id: string)\nYou can use the setTab function to manually set the tab of a Tab component: setTab(id: string, index: string)\nYou can use the recompute function to recompute a component: recompute(id: string)\nYou can use the getAgGrid function to get the ag-grid instance of a table: getAgGrid(id: string)\nYou can use the setSelectedIndex function to select a row in a table or an AG Grid table: setSelectedIndex(id: string, index: number)\nThe setValue function is meant to set or force the value of a component: setValue(id: string, value: any)\nYou can validate a specific field of a form: validate(id: string, key: string)\nYou can validate all fields of a form: validateAll(id: string, key: string)\nYou can invalidate a specific field of a form: invalidate(id: string, key: string, error: string)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"transformer": {
|
||||
"prompt": "Here's my client-side javascript code: \n```javascript\n{code}\n```\n\n<contextual_information>\nThe code should process the variable `result` according to my instructions.\nThe variable `result` is available globally.\nAt the end of the code, the processed result has to be returned.\n\n<helpers>\nYou can access the context object with the ctx global variable. \nThe app state is a store that can be used to store data. You can access and update the state object with the state global variable like this: state.foo = 'bar'\nYou can use the goto function to navigate to a specific URL: goto(path: string, newTab?: boolean)\nYou can use the openModal and closeModal functions to open and close a modal: openModal(id: string), closeModal(id: string)\nYou can use the setTab function to manually set the tab of a Tab component: setTab(id: string, index: string)\nYou can use the recompute function to recompute a component: recompute(id: string)\nYou can use the getAgGrid function to get the ag-grid instance of a table: getAgGrid(id: string)\nYou can use the setSelectedIndex function to select a row in a table or an AG Grid table: setSelectedIndex(id: string, index: number)\nThe setValue function is meant to set or force the value of a component: setValue(id: string, value: any)\nYou can validate a specific field of a form: validate(id: string, key: string)\nYou can validate all fields of a form: validateAll(id: string, key: string)\nYou can invalidate a specific field of a form: invalidate(id: string, key: string, error: string)\n</helpers>\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
"duckdb": {
|
||||
"prompt": "Here's my DuckDB code:\n```sql\n{code}\n```\n<contextual_information>\nArguments are defined with comments like `-- $age (text) = 20` or `-- $name (text)` (one per row) and used in the statement with $age, $name, etc. To use Ducklake, attach it with `ATTACH 'ducklake' AS dl;` (for main ducklake) or `ATTACH 'ducklake://name' AS dl;` for named ducklakes. To connect to external databases, use `ATTACH '$res:path/to/resource' AS db (TYPE postgres);`. To read S3 files, use `SELECT * FROM read_csv('s3:///path/to/file.csv');` for default storage or `SELECT * FROM read_csv('s3://secondary_storage_name/path/to/file.csv');` for named storage.\n</contextual_information>\nMy instructions: {description}"
|
||||
}
|
||||
}
|
||||
};
|
||||
system:
|
||||
"You are a helpful coding assistant for Windmill, a developer platform for running scripts. You modify code as instructed by the user. Each user message includes some contextual information which should guide your answer.\nOnly output code. Wrap the code in a code block. \nPut explanations directly in the code as comments.\nReturn the complete modified code.\n\nHere's how interactions have to look like:\nuser: {sample_question}\nassistant: ```language\n{code}\n```",
|
||||
prompts: {
|
||||
python3: {
|
||||
prompt:
|
||||
'Here\'s my python3 code: \n```python\n{code}\n```\n<contextual_information>\nYou have to write a function in python called "main". Specify the parameter types. Do not call the main function. You should generally return the result.\nThe "main" function cannot be async. If you need to use async code, you can use the asyncio library.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. For Windmill to correctly detect the resources to be passed, the resource type name has to be exactly as specified in the following list:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nYou need to define the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose.\nThe resource type name has to be exactly as specified (has to be IN LOEWRCASE). If the type name conflicts with any imported methods, you have to rename the imported method with the conflicting name.\n<contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
deno: {
|
||||
prompt:
|
||||
'Here\'s my TypeScript code in a deno running environment:\n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a "main" function like this: "export async function main(...)" and specify the parameter types but do not call it. You should generally return the result.\nIf needed, the standard fetch method is available globally, do not import it.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: "{resource_type}Resource". \nThe resource type name has to be exactly as specified.\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user\'s naming choices in the existing code.\n</contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
rust: {
|
||||
prompt:
|
||||
"Here's my Rust code:\n```rust\n{code}\n```\n<contextual_information>\nPlease define a `main` function in Rust with this signature:\n```rust\npub fn main(...) -> Result<ReturnType, Box<dyn std::error::Error>>\n```\nbut do not call it. Favor idiomatic Rust patterns, ensuring safe handling of ownership and borrowing, robust error handling with `Result`, and concurrency if needed (`async`/`tokio` or std threading). \n\nFollow these guidelines:\n- Include necessary imports and modules only when needed.\n- Add comments explaining important operations and any unsafe usage (if absolutely required).\n- The generated code should be easily executable and testable in an integrated terminal.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
go: {
|
||||
prompt:
|
||||
'Here\'s my go code: \n```go\n{code}\n```\n<contextual_information>\nWe have to export a "main" function. Import the packages you need. The return type of the function has to be ({return_type}, error). The file package has to be "inner"\n</contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
bash: {
|
||||
prompt:
|
||||
'Here\'s my bash code: \n```shell\n{code}\n```\n<contextual_information>\nDo not include "#!/bin/bash". Arguments are always string and can only be obtained with "var1="$1"", "var2="$2"", etc... You do not need to check if the arguments are present.\n</contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
postgresql: {
|
||||
prompt:
|
||||
"Here's my PostgreSQL code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with `$1::{type}`, `$2::{type}`, etc... Name the parameters (without specifying the type) by adding comments before the statement like that: `-- $1 name1` or `-- $2 name = default` (one per row)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
mysql: {
|
||||
prompt:
|
||||
"Here's my MySQL code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the statement like that: `-- ? name1 ({type})` or `-- ? name2 ({type}) = default` (one per row)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
bigquery: {
|
||||
prompt:
|
||||
"Here's my BigQuery code: \n```sql\n{code}\n```\n<contextual_information>\nYou can define arguments by adding comments before the statement like that: `-- @name1 ({type})` or `-- @name2 ({type}) = default` (one per row). They can then be obtained directly in the statement with `@name1`, `@name2`, etc....\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
snowflake: {
|
||||
prompt:
|
||||
"Here's my snowflake code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the statement like that: `-- ? name1 ({type})` or `-- ? name2 ({type}) = default` (one per row)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
mssql: {
|
||||
prompt:
|
||||
"Here's my Microsoft SQL Server code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with @P1, @P2, etc.. Name the parameters by adding comments before the statement like that: `-- @P1 name1 ({type})` or `-- @P2 name2 ({type}) = default` (one per row)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
graphql: {
|
||||
prompt:
|
||||
"Here's my graphql code: \n```graphql\n{code}\n```\n<contextual_information>\nAdd the needed arguments as query parameters.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
powershell: {
|
||||
prompt:
|
||||
'Here\'s my powershell code: \n```powershell\n{code}\n```\n<contextual_information>\nArguments can be obtained by calling the param function on the first line like that: `param($ParamName1, $ParamName2 = "default value", [{type}]$ParamName3, ...)`\n</contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
nativets: {
|
||||
prompt:
|
||||
'Here\'s my TypeScript code: \n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a "main" function like this: "export async function main(...)" and specify the parameter types but do not call it. You should generally return the result.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: "{resource_type}Resource".\nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user\'s naming choices in the existing code.\n</contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
bun: {
|
||||
prompt:
|
||||
'Here\'s my TypeScript code: \n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a "main" function like this: "export async function main(...)" and specify the parameter types but do not call it. You should generally return the result.\nIf needed, the standard fetch method is available globally, do not import it.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: "{resource_type}Resource". \nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user\'s naming choices in the existing code.\n</contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
php: {
|
||||
prompt:
|
||||
'Here\'s my php code: \n```php\n{code}\n```\n<contextual_information>\nYou have to write a function in php called "main". Specify the parameter types. Do not call the main function. You should generally return the result. The script must start with `<?php`.\nYou can take as parameters resources which are classes containing credentials or configuration information. For Windmill to correctly detect the resources to be passed, the resource type name has to be exactly as specified in the following list:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nYou need to define the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose.\nBefore defining each type, check if the class already exists using class_exists.\nThe resource type name has to be exactly as specified.\nIf you need to import libraries, you need to specify them as comments in the following manner before the main function:\n```\n// require:\n// mylibrary/mylibrary\n// myotherlibrary/myotherlibrary@optionalversion\n```\nNo need to require autoload, it is already done.\n<contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
csharp: {
|
||||
prompt:
|
||||
'Here\'s my C# code:\n```csharp\n{code}\n```\n<contextual_information>\nYou have to write C# code with a public static Main method inside a class. The class name is irrelevant. Specify the parameter types. Do not call the main function. You should generally return the result.\nNuGet packages can be added using the format: #r "nuget: PackageName, Version" at the top of the script.\nThe Main method signature should be: public static ReturnType Main(parameter types...)\nArguments are used to generate the input specification and create the frontend UI for the script.\n</contextual_information>\nMy instructions: {description}'
|
||||
},
|
||||
java: {
|
||||
prompt:
|
||||
"Here's my Java code:\n```java\n{code}\n```\n<contextual_information>\nYou have to write Java code with a Main public class and a public static main() method. The return type can be Object or void. Do not call the main function. You should generally return the result.\nDependencies can be added using the format: //requirements://groupId:artifactId:version at the top of the script.\nThe method signature should be: public static Object main(parameter types...)\nArguments are used to generate the input specification and create the frontend UI for the script.\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
frontend: {
|
||||
prompt:
|
||||
"Here's my client-side javascript code: \n```javascript\n{code}\n```\n<contextual_information>\nYou can access the context object with the ctx global variable. \nThe app state is a store that can be used to store data. You can access and update the state object with the state global variable like this: state.foo = 'bar'\nYou can use the goto function to navigate to a specific URL: goto(path: string, newTab?: boolean)\nYou can use the openModal and closeModal functions to open and close a modal: openModal(id: string), closeModal(id: string)\nYou can use the setTab function to manually set the tab of a Tab component: setTab(id: string, index: string)\nYou can use the recompute function to recompute a component: recompute(id: string)\nYou can use the getAgGrid function to get the ag-grid instance of a table: getAgGrid(id: string)\nYou can use the setSelectedIndex function to select a row in a table or an AG Grid table: setSelectedIndex(id: string, index: number)\nThe setValue function is meant to set or force the value of a component: setValue(id: string, value: any)\nYou can validate a specific field of a form: validate(id: string, key: string)\nYou can validate all fields of a form: validateAll(id: string, key: string)\nYou can invalidate a specific field of a form: invalidate(id: string, key: string, error: string)\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
transformer: {
|
||||
prompt:
|
||||
"Here's my client-side javascript code: \n```javascript\n{code}\n```\n\n<contextual_information>\nThe code should process the variable `result` according to my instructions.\nThe variable `result` is available globally.\nAt the end of the code, the processed result has to be returned.\n\n<helpers>\nYou can access the context object with the ctx global variable. \nThe app state is a store that can be used to store data. You can access and update the state object with the state global variable like this: state.foo = 'bar'\nYou can use the goto function to navigate to a specific URL: goto(path: string, newTab?: boolean)\nYou can use the openModal and closeModal functions to open and close a modal: openModal(id: string), closeModal(id: string)\nYou can use the setTab function to manually set the tab of a Tab component: setTab(id: string, index: string)\nYou can use the recompute function to recompute a component: recompute(id: string)\nYou can use the getAgGrid function to get the ag-grid instance of a table: getAgGrid(id: string)\nYou can use the setSelectedIndex function to select a row in a table or an AG Grid table: setSelectedIndex(id: string, index: number)\nThe setValue function is meant to set or force the value of a component: setValue(id: string, value: any)\nYou can validate a specific field of a form: validate(id: string, key: string)\nYou can validate all fields of a form: validateAll(id: string, key: string)\nYou can invalidate a specific field of a form: invalidate(id: string, key: string, error: string)\n</helpers>\n</contextual_information>\nMy instructions: {description}"
|
||||
},
|
||||
duckdb: {
|
||||
prompt:
|
||||
"Here's my DuckDB code:\n```sql\n{code}\n```\n<contextual_information>\nArguments are defined with comments like `-- $age (text) = 20` or `-- $name (text)` (one per row) and used in the statement with $age, $name, etc. To use Ducklake, attach it with `ATTACH 'ducklake' AS dl;` (for main ducklake) or `ATTACH 'ducklake://name' AS dl;` for named ducklakes. To connect to external databases, use `ATTACH '$res:path/to/resource' AS db (TYPE postgres);`. To read S3 files, use `SELECT * FROM read_csv('s3:///path/to/file.csv');` for default storage or `SELECT * FROM read_csv('s3://secondary_storage_name/path/to/file.csv');` for named storage.\n</contextual_information>\nMy instructions: {description}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +1,78 @@
|
||||
export const FIX_PROMPT = {
|
||||
"system": "You are a helpful coding assistant for Windmill, a developer platform for running scripts. You fix the code shared by the user. Each user message includes some contextual information which should guide your answer.\nOnly output code. Wrap the code in a code block. \nExplain the error and the fix after generating the code inside an <explanation> tag.\nAlso put explanations directly in the code as comments.\nReturn the complete fixed code.\n\nHere's how interactions have to look like:\nuser: {sample_question}\nassistant: ```language\n{code}\n```\n<explanation>{explanation}</explanation>",
|
||||
"prompts": {
|
||||
"python3": {
|
||||
"prompt": "Here's my python3 code: \n```python\n{code}\n```\n<contextual_information>\nYou have to write a function in python called \"main\". Specify the parameter types. Do not call the main function. You should generally return the result.\nThe \"main\" function cannot be async. If you need to use async code, you can use the asyncio library.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. For Windmill to correctly detect the resources to be passed, the resource type name has to be exactly as specified in the following list:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nYou need to define the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose.\nThe resource type name has to be exactly as specified (has to be IN LOEWRCASE). If the type name conflicts with any imported methods, you have to rename the imported method with the conflicting name.\n<contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"deno": {
|
||||
"prompt": "Here's my TypeScript code in a deno running environment:\n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a \"main\" function like this: \"export async function main(...)\" and specify the parameter types but do not call it. You should generally return the result.\nIf needed, the standard fetch method is available globally, do not import it.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: \"{resource_type}Resource\".\nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user's naming choices in the existing code.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"rust": {
|
||||
"prompt": "Here's my Rust code:\n```rust\n{code}\n```\n<contextual_information>\nPlease define a `main` function in Rust with this signature:\n```rust\npub fn main(...) -> Result<ReturnType, Box<dyn std::error::Error>>\n```\nbut do not call it. Favor idiomatic Rust patterns, ensuring safe handling of ownership and borrowing, robust error handling with `Result`, and concurrency if needed (`async`/`tokio` or std threading). \n\n- Include necessary imports and modules only when needed.\n- Add comments explaining important operations and any unsafe usage (if absolutely required).\n- The generated code should be easily executable and testable in an integrated terminal.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"go": {
|
||||
"prompt": "Here's my go code: \n```go\n{code}\n```\n<contextual_information>\nWe have to export a \"main\" function. Import the packages you need. The return type of the function has to be ({return_type}, error). The file package has to be \"inner\"\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"bash": {
|
||||
"prompt": "Here's my bash code: \n```shell\n{code}\n```\n<contextual_information>\nDo not include \"#!/bin/bash\". Arguments are always string and can only be obtained with \"var1=\"$1\"\", \"var2=\"$2\"\", etc... You do not need to check if the arguments are present.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"postgresql": {
|
||||
"prompt": "Here's my PostgreSQL code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with `$1::{type}`, `$2::{type}`, etc... Name the parameters (without specifying the type) by adding comments before the statement like that: `-- $1 name1` or `-- $2 name = default` (one per row)\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"mysql": {
|
||||
"prompt": "Here's my MySQL code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the statement like that: `-- ? name1 ({type})` or `-- ? name2 ({type}) = default` (one per row)\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"bigquery": {
|
||||
"prompt": "Here's my BigQuery code: \n```sql\n{code}\n```\n<contextual_information>\nYou can define arguments by adding comments before the statement like that: `-- @name1 ({type})` or `-- @name2 ({type}) = default` (one per row). They can then be obtained directly in the statement with `@name1`, `@name2`, etc....\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"snowflake": {
|
||||
"prompt": "Here's my snowflake code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the statement like that: `-- ? name1 ({type})` or `-- ? name2 ({type}) = default` (one per row)\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"mssql": {
|
||||
"prompt": "Here's my Microsoft SQL Server code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with @P1, @P2, etc.. Name the parameters by adding comments before the statement like that: `-- @P1 name1 ({type})` or `-- @P2 name2 ({type}) = default` (one per row)\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"graphql": {
|
||||
"prompt": "Here's my graphql code: \n```graphql\n{code}\n```\n<contextual_information>\nAdd the needed arguments as query parameters.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"powershell": {
|
||||
"prompt": "Here's my powershell code: \n```powershell\n{code}\n```\n<contextual_information>\nArguments can be obtained by calling the param function on the first line like that: `param($ParamName1, $ParamName2 = \"default value\", [{type}]$ParamName3, ...)`\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"nativets": {
|
||||
"prompt": "Here's my TypeScript code: \n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a \"main\" function like this: \"export async function main(...)\" and specify the parameter types but do not call it. You should generally return the result.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: \"{resource_type}Resource\". \nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user's naming choices in the existing code.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"bun": {
|
||||
"prompt": "Here's my TypeScript code: \n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a \"main\" function like this: \"export async function main(...)\" and specify the parameter types but do not call it. You should generally return the result.\nIf needed, the standard fetch method is available globally, do not import it.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: \"{resource_type}Resource\".\nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user's naming choices in the existing code.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"php": {
|
||||
"prompt": "Here's my php code: \n```php\n{code}\n```\n<contextual_information>\nYou have to write a function in php called \"main\". Specify the parameter types. Do not call the main function. You should generally return the result. The script must start with `<?php`.\nYou can take as parameters resources which are classes containing credentials or configuration information. For Windmill to correctly detect the resources to be passed, the resource type name has to be exactly as specified in the following list:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nYou need to define the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose.\nBefore defining each type, check if the class already exists using class_exists.\nThe resource type name has to be exactly as specified.\nIf you need to import libraries, you need to specify them as comments in the following manner before the main function:\n```\n// require:\n// mylibrary/mylibrary\n// myotherlibrary/myotherlibrary@optionalversion\n```\nNo need to require autoload, it is already done.\n<contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"csharp": {
|
||||
"prompt": "Here's my C# code:\n```csharp\n{code}\n```\n<contextual_information>\nYou have to write C# code with a public static Main method inside a class. The class name is irrelevant. Specify the parameter types. Do not call the main function. You should generally return the result.\nNuGet packages can be added using the format: #r \"nuget: PackageName, Version\" at the top of the script.\nThe Main method signature should be: public static ReturnType Main(parameter types...)\nArguments are used to generate the input specification and create the frontend UI for the script.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"java": {
|
||||
"prompt": "Here's my Java code:\n```java\n{code}\n```\n<contextual_information>\nYou have to write Java code with a Main public class and a public static main() method. The return type can be Object or void. Do not call the main function. You should generally return the result.\nDependencies can be added using the format: //requirements://groupId:artifactId:version at the top of the script.\nThe method signature should be: public static Object main(parameter types...)\nArguments are used to generate the input specification and create the frontend UI for the script.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
"duckdb": {
|
||||
"prompt": "Here's my DuckDB code:\n```sql\n{code}\n```\n<contextual_information>\nArguments are defined with comments like `-- $age (text) = 20` or `-- $name (text)` (one per row) and used in the statement with $age, $name, etc. To use Ducklake, attach it with `ATTACH 'ducklake' AS dl;` (for main ducklake) or `ATTACH 'ducklake://name' AS dl;` for named ducklakes. To connect to external databases, use `ATTACH '$res:path/to/resource' AS db (TYPE postgres);`. To read S3 files, use `SELECT * FROM read_csv('s3:///path/to/file.csv');` for default storage or `SELECT * FROM read_csv('s3://secondary_storage_name/path/to/file.csv');` for named storage.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
}
|
||||
}
|
||||
};
|
||||
system:
|
||||
"You are a helpful coding assistant for Windmill, a developer platform for running scripts. You fix the code shared by the user. Each user message includes some contextual information which should guide your answer.\nOnly output code. Wrap the code in a code block. \nExplain the error and the fix after generating the code inside an <explanation> tag.\nAlso put explanations directly in the code as comments.\nReturn the complete fixed code.\n\nHere's how interactions have to look like:\nuser: {sample_question}\nassistant: ```language\n{code}\n```\n<explanation>{explanation}</explanation>",
|
||||
prompts: {
|
||||
python3: {
|
||||
prompt:
|
||||
'Here\'s my python3 code: \n```python\n{code}\n```\n<contextual_information>\nYou have to write a function in python called "main". Specify the parameter types. Do not call the main function. You should generally return the result.\nThe "main" function cannot be async. If you need to use async code, you can use the asyncio library.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. For Windmill to correctly detect the resources to be passed, the resource type name has to be exactly as specified in the following list:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nYou need to define the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose.\nThe resource type name has to be exactly as specified (has to be IN LOEWRCASE). If the type name conflicts with any imported methods, you have to rename the imported method with the conflicting name.\n<contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
deno: {
|
||||
prompt:
|
||||
'Here\'s my TypeScript code in a deno running environment:\n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a "main" function like this: "export async function main(...)" and specify the parameter types but do not call it. You should generally return the result.\nIf needed, the standard fetch method is available globally, do not import it.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: "{resource_type}Resource".\nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user\'s naming choices in the existing code.\n</contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
rust: {
|
||||
prompt:
|
||||
"Here's my Rust code:\n```rust\n{code}\n```\n<contextual_information>\nPlease define a `main` function in Rust with this signature:\n```rust\npub fn main(...) -> Result<ReturnType, Box<dyn std::error::Error>>\n```\nbut do not call it. Favor idiomatic Rust patterns, ensuring safe handling of ownership and borrowing, robust error handling with `Result`, and concurrency if needed (`async`/`tokio` or std threading). \n\n- Include necessary imports and modules only when needed.\n- Add comments explaining important operations and any unsafe usage (if absolutely required).\n- The generated code should be easily executable and testable in an integrated terminal.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
go: {
|
||||
prompt:
|
||||
'Here\'s my go code: \n```go\n{code}\n```\n<contextual_information>\nWe have to export a "main" function. Import the packages you need. The return type of the function has to be ({return_type}, error). The file package has to be "inner"\n</contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
bash: {
|
||||
prompt:
|
||||
'Here\'s my bash code: \n```shell\n{code}\n```\n<contextual_information>\nDo not include "#!/bin/bash". Arguments are always string and can only be obtained with "var1="$1"", "var2="$2"", etc... You do not need to check if the arguments are present.\n</contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
postgresql: {
|
||||
prompt:
|
||||
"Here's my PostgreSQL code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with `$1::{type}`, `$2::{type}`, etc... Name the parameters (without specifying the type) by adding comments before the statement like that: `-- $1 name1` or `-- $2 name = default` (one per row)\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
mysql: {
|
||||
prompt:
|
||||
"Here's my MySQL code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the statement like that: `-- ? name1 ({type})` or `-- ? name2 ({type}) = default` (one per row)\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
bigquery: {
|
||||
prompt:
|
||||
"Here's my BigQuery code: \n```sql\n{code}\n```\n<contextual_information>\nYou can define arguments by adding comments before the statement like that: `-- @name1 ({type})` or `-- @name2 ({type}) = default` (one per row). They can then be obtained directly in the statement with `@name1`, `@name2`, etc....\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
snowflake: {
|
||||
prompt:
|
||||
"Here's my snowflake code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with ?. Name the parameters by adding comments before the statement like that: `-- ? name1 ({type})` or `-- ? name2 ({type}) = default` (one per row)\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
mssql: {
|
||||
prompt:
|
||||
"Here's my Microsoft SQL Server code: \n```sql\n{code}\n```\n<contextual_information>\nArguments can be obtained directly in the statement with @P1, @P2, etc.. Name the parameters by adding comments before the statement like that: `-- @P1 name1 ({type})` or `-- @P2 name2 ({type}) = default` (one per row)\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
graphql: {
|
||||
prompt:
|
||||
"Here's my graphql code: \n```graphql\n{code}\n```\n<contextual_information>\nAdd the needed arguments as query parameters.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
powershell: {
|
||||
prompt:
|
||||
'Here\'s my powershell code: \n```powershell\n{code}\n```\n<contextual_information>\nArguments can be obtained by calling the param function on the first line like that: `param($ParamName1, $ParamName2 = "default value", [{type}]$ParamName3, ...)`\n</contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
nativets: {
|
||||
prompt:
|
||||
'Here\'s my TypeScript code: \n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a "main" function like this: "export async function main(...)" and specify the parameter types but do not call it. You should generally return the result.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: "{resource_type}Resource". \nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user\'s naming choices in the existing code.\n</contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
bun: {
|
||||
prompt:
|
||||
'Here\'s my TypeScript code: \n```typescript\n{code}\n```\n<contextual_information>\nWe have to export a "main" function like this: "export async function main(...)" and specify the parameter types but do not call it. You should generally return the result.\nIf needed, the standard fetch method is available globally, do not import it.\nYou can take as parameters resources which are dictionaries containing credentials or configuration information. Name the resource parameters like this: "{resource_type}Resource".\nThe following resource types are available:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nOnly define the type for resources that are actually needed to achieve the function purpose. The resource type name has to be exactly as specified. If the type name conflicts with the imported object, rename the imported object NOT THE TYPE.\nNaming conventions are guidelines, but follow the user\'s naming choices in the existing code.\n</contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
php: {
|
||||
prompt:
|
||||
'Here\'s my php code: \n```php\n{code}\n```\n<contextual_information>\nYou have to write a function in php called "main". Specify the parameter types. Do not call the main function. You should generally return the result. The script must start with `<?php`.\nYou can take as parameters resources which are classes containing credentials or configuration information. For Windmill to correctly detect the resources to be passed, the resource type name has to be exactly as specified in the following list:\n<resourceTypes>\n{resourceTypes}\n</resourceTypes>\nYou need to define the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose.\nBefore defining each type, check if the class already exists using class_exists.\nThe resource type name has to be exactly as specified.\nIf you need to import libraries, you need to specify them as comments in the following manner before the main function:\n```\n// require:\n// mylibrary/mylibrary\n// myotherlibrary/myotherlibrary@optionalversion\n```\nNo need to require autoload, it is already done.\n<contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
csharp: {
|
||||
prompt:
|
||||
'Here\'s my C# code:\n```csharp\n{code}\n```\n<contextual_information>\nYou have to write C# code with a public static Main method inside a class. The class name is irrelevant. Specify the parameter types. Do not call the main function. You should generally return the result.\nNuGet packages can be added using the format: #r "nuget: PackageName, Version" at the top of the script.\nThe Main method signature should be: public static ReturnType Main(parameter types...)\nArguments are used to generate the input specification and create the frontend UI for the script.\n</contextual_information>\nI get the following error: {error}\nFix my code.'
|
||||
},
|
||||
java: {
|
||||
prompt:
|
||||
"Here's my Java code:\n```java\n{code}\n```\n<contextual_information>\nYou have to write Java code with a Main public class and a public static main() method. The return type can be Object or void. Do not call the main function. You should generally return the result.\nDependencies can be added using the format: //requirements://groupId:artifactId:version at the top of the script.\nThe method signature should be: public static Object main(parameter types...)\nArguments are used to generate the input specification and create the frontend UI for the script.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
},
|
||||
duckdb: {
|
||||
prompt:
|
||||
"Here's my DuckDB code:\n```sql\n{code}\n```\n<contextual_information>\nArguments are defined with comments like `-- $age (text) = 20` or `-- $name (text)` (one per row) and used in the statement with $age, $name, etc. To use Ducklake, attach it with `ATTACH 'ducklake' AS dl;` (for main ducklake) or `ATTACH 'ducklake://name' AS dl;` for named ducklakes. To connect to external databases, use `ATTACH '$res:path/to/resource' AS db (TYPE postgres);`. To read S3 files, use `SELECT * FROM read_csv('s3:///path/to/file.csv');` for default storage or `SELECT * FROM read_csv('s3://secondary_storage_name/path/to/file.csv');` for named storage.\n</contextual_information>\nI get the following error: {error}\nFix my code."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user