Compare commits

...

2 Commits

Author SHA1 Message Date
centdix
4af6e741e4 Merge branch 'main' into fg/revert 2025-08-29 09:04:04 +00:00
centdix
16611c51de Revert "feat(aichat): give advanced options tools to flow mode (#6463)"
This reverts commit b26cea9d3e.
2025-08-29 08:59:49 +00:00
10 changed files with 5 additions and 292 deletions

View File

@@ -29,7 +29,9 @@
try {
const parsed = JSON.parse(obj[key])
obj[key] = parsed
} catch {}
} catch (e) {
console.error('Failed to parse JSON:', e)
}
}
return JSON.stringify(obj, null, 2)
} catch {

View File

@@ -185,8 +185,7 @@
}
}
Object.keys(newModule).forEach((k) => delete newModule[k])
Object.assign(newModule, $state.snapshot(oldModule))
newModule.value = oldModule.value
}
refreshStateStore(flowStore)
@@ -499,75 +498,6 @@
refreshStateStore(flowStore)
}
setModuleStatus(id, 'modified')
},
setForLoopOptions: async (id, opts) => {
const module = getModule(id)
if (!module) {
throw new Error('Module not found')
}
if (module.value.type !== 'forloopflow') {
throw new Error('Module is not a forloopflow')
}
// Apply skip_failures if provided
if (typeof opts.skip_failures === 'boolean') {
module.value.skip_failures = opts.skip_failures
}
// Apply parallel if provided
if (typeof opts.parallel === 'boolean') {
module.value.parallel = opts.parallel
}
// Handle parallelism
if (opts.parallel === false) {
// If parallel is disabled, clear parallelism
module.value.parallelism = undefined
} else if (opts.parallelism !== undefined) {
if (opts.parallelism === null) {
// Explicitly clear parallelism
module.value.parallelism = undefined
} else if (module.value.parallel || opts.parallel === true) {
// Only set parallelism if parallel is enabled
const n = Math.max(1, Math.floor(Math.abs(opts.parallelism)))
module.value.parallelism = n
}
}
refreshStateStore(flowStore)
setModuleStatus(id, 'modified')
},
setModuleControlOptions: async (id, opts) => {
const module = getModule(id)
if (!module) {
throw new Error('Module not found')
}
// Handle stop_after_if
if (typeof opts.stop_after_if === 'boolean') {
if (opts.stop_after_if === false) {
module.stop_after_if = undefined
} else {
module.stop_after_if = {
expr: opts.stop_after_if_expr ?? '',
skip_if_stopped: opts.stop_after_if
}
}
}
// Handle skip_if
if (typeof opts.skip_if === 'boolean') {
if (opts.skip_if === false) {
module.skip_if = undefined
} else {
module.skip_if = {
expr: opts.skip_if_expr ?? ''
}
}
}
refreshStateStore(flowStore)
setModuleStatus(id, 'modified')
}
}

View File

@@ -1,5 +1,4 @@
import { ScriptService, type FlowModule, type RawScript, type Script, JobService } from '$lib/gen'
import { emitUiIntent } from './uiIntents'
import type {
ChatCompletionSystemMessageParam,
ChatCompletionUserMessageParam
@@ -58,23 +57,6 @@ export interface FlowAIChatHelpers {
addBranch: (id: string) => Promise<void>
removeBranch: (id: string, branchIndex: number) => Promise<void>
setForLoopIteratorExpression: (id: string, expression: string) => Promise<void>
setForLoopOptions: (
id: string,
opts: {
skip_failures?: boolean | null
parallel?: boolean | null
parallelism?: number | null
}
) => Promise<void>
setModuleControlOptions: (
id: string,
opts: {
stop_after_if?: boolean | null
stop_after_if_expr?: string | null
skip_if?: boolean | null
skip_if_expr?: string | null
}
) => Promise<void>
setCode: (id: string, code: string) => Promise<void>
}
@@ -214,67 +196,6 @@ const setForLoopIteratorExpressionToolDef = createToolDef(
'Set the iterator JavaScript expression for the given forloop step'
)
const setForLoopOptionsSchema = z.object({
id: z.string().describe('The id of the forloop step to configure'),
skip_failures: z
.boolean()
.nullable()
.optional()
.describe('Whether to skip failures in the loop (null to not change)'),
parallel: z
.boolean()
.nullable()
.optional()
.describe('Whether to run iterations in parallel (null to not change)'),
parallelism: z
.number()
.int()
.min(1)
.nullable()
.optional()
.describe('Maximum number of parallel iterations (null to not change)')
})
const setForLoopOptionsToolDef = createToolDef(
setForLoopOptionsSchema,
'set_forloop_options',
'Set advanced options for a forloop step: skip_failures, parallel, and parallelism'
)
const setModuleControlOptionsSchema = z.object({
id: z.string().describe('The id of the module to configure'),
stop_after_if: z
.boolean()
.nullable()
.optional()
.describe('Early stop condition (true to set, false to clear, null to not change)'),
stop_after_if_expr: z
.string()
.nullable()
.optional()
.describe(
'JavaScript expression for early stop condition. Can use `flow_input` or `result`. `result` is the result of the step. `results.<step_id>` is not supported, do not use it. Only used if stop_after_if is true. Example: `flow_input.x > 10` or `result === "failure"`'
),
skip_if: z
.boolean()
.nullable()
.optional()
.describe('Skip condition (true to set, false to clear, null to not change)'),
skip_if_expr: z
.string()
.nullable()
.optional()
.describe(
'JavaScript expression for skip condition. Can use `flow_input` or `results.<step_id>`. Only used if skip_if is true. Example: `flow_input.x > 10` or `results.a === "failure"`'
)
})
const setModuleControlOptionsToolDef = createToolDef(
setModuleControlOptionsSchema,
'set_module_control_options',
'Set control options for any module: stop_after_if (early stop) and skip_if (conditional skip)'
)
const setBranchPredicateSchema = z.object({
id: z.string().describe('The id of the branchone step to set the predicates for'),
branchIndex: z
@@ -637,68 +558,6 @@ export const flowTools: Tool<FlowAIChatHelpers>[] = [
return `Forloop '${parsedArgs.id}' iterator expression set`
}
},
{
def: setForLoopOptionsToolDef,
fn: async ({ args, helpers, toolId, toolCallbacks }) => {
const parsedArgs = setForLoopOptionsSchema.parse(args)
await helpers.setForLoopOptions(parsedArgs.id, {
skip_failures: parsedArgs.skip_failures,
parallel: parsedArgs.parallel,
parallelism: parsedArgs.parallelism
})
helpers.selectStep(parsedArgs.id)
const message = `Set forloop '${parsedArgs.id}' options`
toolCallbacks.setToolStatus(toolId, {
content: message
})
return `${message}: ${JSON.stringify(parsedArgs)}`
}
},
{
def: setModuleControlOptionsToolDef,
fn: async ({ args, helpers, toolId, toolCallbacks }) => {
const parsedArgs = setModuleControlOptionsSchema.parse(args)
await helpers.setModuleControlOptions(parsedArgs.id, {
stop_after_if: parsedArgs.stop_after_if,
stop_after_if_expr: parsedArgs.stop_after_if_expr,
skip_if: parsedArgs.skip_if,
skip_if_expr: parsedArgs.skip_if_expr
})
helpers.selectStep(parsedArgs.id)
// Emit UI intent to show early-stop tab when stop_after_if is configured
const modules = helpers.getModules()
const module = findModuleById(modules, parsedArgs.id)
if (!module) {
throw new Error(`Module with id '${parsedArgs.id}' not found in flow.`)
}
const moduleType = module?.value.type
const hasSpecificComponents = ['forloopflow', 'whileloopflow', 'branchall', 'branchone']
const prefix = hasSpecificComponents.includes(moduleType) ? `${moduleType}` : 'flow'
if (typeof parsedArgs.stop_after_if === 'boolean') {
emitUiIntent({
kind: 'open_module_tab',
componentId: `${prefix}-${parsedArgs.id}`,
tab: 'early-stop'
})
}
if (typeof parsedArgs.skip_if === 'boolean') {
emitUiIntent({
kind: 'open_module_tab',
componentId: `${prefix}-${parsedArgs.id}`,
tab: 'skip'
})
}
const message = `Set module '${parsedArgs.id}' control options`
toolCallbacks.setToolStatus(toolId, {
content: message
})
return `${message}: ${JSON.stringify(parsedArgs)}`
}
},
{
def: resourceTypeToolDef,
fn: async ({ args, toolId, workspace, toolCallbacks }) => {
@@ -931,17 +790,10 @@ When creating new steps, follow this process for EACH step:
### Special Step Types
For special step types, follow these additional steps:
- For forloop steps:
- Set the iterator expression using set_forloop_iterator_expression
- Set advanced options (parallel, parallelism, skip_failures) using set_forloop_options
- For forloop steps: Set the iterator expression using set_forloop_iterator_expression
- For branchone steps: Set the predicates for each branch using set_branch_predicate
- For branchall steps: No additional setup needed
### Module Control Options
For any module type, you can set control flow options using set_module_control_options:
- **stop_after_if**: Early stop condition - stops the module if expression evaluates to true. Can use "flow_input" or "result". "result" is the result of the step. "results.<step_id>" is not supported, do not use it. Example: "flow_input.x > 10" or "result === "failure""
- **skip_if**: Skip condition - skips the module entirely if expression evaluates to true. Can use "flow_input" or "results.<step_id>". Example: "flow_input.x > 10" or "results.a === "failure""
### Step Insertion Rules
When adding steps, carefully consider the execution order:
1. Steps are executed in the order they appear in the flow definition, not in the order they were added
@@ -962,7 +814,6 @@ When adding steps, carefully consider the execution order:
### JavaScript Expressions
For step inputs, forloop iterator expressions and branch predicates, use JavaScript expressions with these variables:
- Step results: results.stepid or results.stepid.property_name
- Break condition (stop_after_if) in for loops: result (contains the result of the last iteration)
- Loop iterator: flow_input.iter.value (inside loops)
- Flow inputs: flow_input.property_name
- Static values: Use JavaScript syntax (e.g., "hello", true, 3)
@@ -971,12 +822,6 @@ Note: These variables are only accessible in step inputs, forloop iterator expre
For truly static values in step inputs (those not linked to previous steps or loop iterations), prefer using flow inputs by default unless explicitly specified otherwise. This makes the flow more configurable and reusable. For example, instead of hardcoding an email address in a step input, create a flow input for it.
### For Loop Advanced Options
When configuring for-loop steps, consider these options:
- **parallel: true** - Run iterations in parallel for independent operations (significantly faster for I/O bound tasks)
- **parallelism: N** - Limit concurrent iterations (only applies when parallel=true). Use to prevent overwhelming external APIs
- **skip_failures: true** - Continue processing remaining iterations even if some fail. Failed iterations return error objects as results
### Special Modules
- Preprocessor: Runs before the first step when triggered externally
- ID: 'preprocessor'

View File

@@ -1,9 +0,0 @@
import { writable, type Writable } from 'svelte/store'
export type UiIntent = { kind: 'open_module_tab'; componentId: string; tab: string }
export const uiIntentStore: Writable<UiIntent | null> = writable(null)
export function emitUiIntent(intent: UiIntent) {
uiIntentStore.set(intent)
}

View File

@@ -1,17 +0,0 @@
import { uiIntentStore, type UiIntent } from './uiIntents'
import { onDestroy } from 'svelte'
type Handlers = {
openTab?: (tab: string) => void
}
export function useUiIntent(componentId: string, handlers: Handlers) {
const unsub = uiIntentStore.subscribe((intent: UiIntent | null) => {
if (!intent || intent.componentId !== componentId) return
if (intent.kind === 'open_module_tab') handlers.openTab?.(intent.tab)
uiIntentStore.set(null)
})
onDestroy(() => unsub())
}

View File

@@ -15,7 +15,6 @@
import { enterpriseLicense } from '$lib/stores'
import FlowModuleSkip from './FlowModuleSkip.svelte'
import TabsV2 from '$lib/components/common/tabs/TabsV2.svelte'
import { useUiIntent } from '$lib/components/copilot/chat/flow/useUiIntent'
interface Props {
noEditor: boolean
@@ -32,12 +31,6 @@
})
let selected = $state('early-stop')
useUiIntent(`branchall-${flowModule.id}`, {
openTab: (tab) => {
selected = tab
}
})
</script>
<div class="h-full flex flex-col w-full" id="flow-editor-branch-all-wrapper">

View File

@@ -15,7 +15,6 @@
import FlowModuleMock from './FlowModuleMock.svelte'
import { enterpriseLicense } from '$lib/stores'
import FlowModuleSkip from './FlowModuleSkip.svelte'
import { useUiIntent } from '$lib/components/copilot/chat/flow/useUiIntent'
interface Props {
// import FlowRetries from './FlowRetries.svelte'
@@ -40,12 +39,6 @@
})
let selected = $state('early-stop')
useUiIntent(`branchone-${flowModule.id}`, {
openTab: (tab) => {
selected = tab
}
})
</script>
<div class="h-full" id="flow-editor-branch-one-wrapper">

View File

@@ -27,7 +27,6 @@
import PropPickerWrapper, { CONNECT } from '../propPicker/PropPickerWrapper.svelte'
import type { PropPickerContext } from '$lib/components/prop_picker'
import TabsV2 from '$lib/components/common/tabs/TabsV2.svelte'
import { useUiIntent } from '$lib/components/copilot/chat/flow/useUiIntent'
const { previewArgs, flowStateStore, flowStore, currentEditor } =
getContext<FlowEditorContext>('FlowEditorContext')
@@ -51,13 +50,6 @@
let editor: SimpleEditor | undefined = $state(undefined)
let selected: string = $state('early-stop')
// UI Intent handling for AI tool control
useUiIntent(`forloopflow-${mod.id}`, {
openTab: (tab) => {
selected = tab
}
})
const { flowPropPickerConfig } = getContext<PropPickerContext>('PropPickerContext')
flowPropPickerConfig.set(undefined)

View File

@@ -54,8 +54,6 @@
import { refreshStateStore } from '$lib/svelte5Utils.svelte'
import { getStepHistoryLoaderContext } from '$lib/components/stepHistoryLoader.svelte'
import AssetsDropdownButton from '$lib/components/assets/AssetsDropdownButton.svelte'
import { useUiIntent } from '$lib/components/copilot/chat/flow/useUiIntent'
import { editor as meditor } from 'monaco-editor'
const {
selectedId,
@@ -137,13 +135,6 @@
let assets = $derived((flowModule.value.type === 'rawscript' && flowModule.value.assets) || [])
// UI Intent handling for AI tool control
useUiIntent(`flow-${flowModule.id}`, {
openTab: (tab) => {
selectAdvanced(tab)
}
})
function onModulesChange(savedModule: FlowModule | undefined, flowModule: FlowModule) {
// console.log('onModulesChange', savedModule, flowModule)
return savedModule?.value?.type === 'rawscript' &&

View File

@@ -19,7 +19,6 @@
import FlowModuleDeleteAfterUse from './FlowModuleDeleteAfterUse.svelte'
import FlowModuleSkip from './FlowModuleSkip.svelte'
import TabsV2 from '$lib/components/common/tabs/TabsV2.svelte'
import { useUiIntent } from '$lib/components/copilot/chat/flow/useUiIntent'
const { flowStateStore } = getContext<FlowEditorContext>('FlowEditorContext')
@@ -39,12 +38,6 @@
let job: Job | undefined = $state(undefined)
let previewIterationArgs = $derived(flowStateStore.val[mod.id]?.previewArgs ?? {})
useUiIntent(`whileloopflow-${mod.id}`, {
openTab: (tab) => {
selected = tab
}
})
</script>
<Drawer bind:open={previewOpen} alwaysOpen size="75%">