Compare commits

..

1 Commits

Author SHA1 Message Date
Siddharth Ganesan
88b29c9719 Fix? 2025-12-15 19:24:12 -08:00
8 changed files with 40 additions and 43 deletions

View File

@@ -188,7 +188,6 @@ DATABASE_URL="postgresql://postgres:your_password@localhost:5432/simstudio"
Then run the migrations:
```bash
cd apps/sim # Required so drizzle picks correct .env file
bunx drizzle-kit migrate --config=./drizzle.config.ts
```

View File

@@ -109,7 +109,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
{FOOTER_BLOCKS.map((block) => (
<Link
key={block}
href={`https://docs.sim.ai/blocks/${block.toLowerCase().replaceAll(' ', '-')}`}
href={`https://docs.sim.ai/blocks/${block.toLowerCase().replace(' ', '-')}`}
target='_blank'
rel='noopener noreferrer'
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'

View File

@@ -91,7 +91,8 @@ export function FieldFormat({
placeholder = 'fieldName',
showType = true,
showValue = false,
valuePlaceholder = 'Enter default value',
valuePlaceholder = 'Enter test value',
config,
}: FieldFormatProps) {
const [storeValue, setStoreValue] = useSubBlockValue<Field[]>(blockId, subBlockId)
const valueInputRefs = useRef<Record<string, HTMLInputElement | HTMLTextAreaElement>>({})
@@ -453,6 +454,7 @@ export function FieldFormat({
)
}
// Export specific components for backward compatibility
export function InputFormat(props: Omit<FieldFormatProps, 'title' | 'placeholder'>) {
return <FieldFormat {...props} title='Input' placeholder='firstName' />
}

View File

@@ -155,15 +155,6 @@ export const ScheduleBlock: BlockConfig = {
condition: { field: 'scheduleType', value: ['minutes', 'hourly'], not: true },
},
{
id: 'inputFormat',
title: 'Input Format',
type: 'input-format',
description:
'Define input parameters that will be available when the schedule triggers. Use Value to set default values for scheduled executions.',
mode: 'trigger',
},
{
id: 'scheduleSave',
type: 'schedule-save',

View File

@@ -557,6 +557,14 @@ export class WorkflowDiffEngine {
const existingBlock = existingBlockMap[key]?.block
// Merge with existing block if found, otherwise use proposed
// Deep merge subBlocks to preserve runtime values (webhookId, triggerPath, etc.)
const mergedSubBlocks = existingBlock
? {
...existingBlock.subBlocks,
...proposedBlock.subBlocks,
}
: proposedBlock.subBlocks
const finalBlock: BlockState & BlockWithDiff = existingBlock
? {
...existingBlock,
@@ -564,6 +572,8 @@ export class WorkflowDiffEngine {
id: finalId,
// Preserve position from proposed or fallback to existing
position: proposedBlock.position || existingBlock.position,
// Use deep-merged subBlocks to preserve runtime values
subBlocks: mergedSubBlocks,
}
: {
...proposedBlock,

View File

@@ -402,7 +402,8 @@ export class Serializer {
// Second pass: filter by mode and conditions
Object.entries(block.subBlocks).forEach(([id, subBlock]) => {
const matchingConfigs = blockConfig.subBlocks.filter((config) => config.id === id)
// Find the corresponding subblock config to check its mode and condition
const subBlockConfig = blockConfig.subBlocks.find((config) => config.id === id)
// Include field if it matches current mode OR if it's the starter inputFormat with values
const hasStarterInputFormatValues =
@@ -416,17 +417,13 @@ export class Serializer {
const isLegacyAgentField =
isAgentBlock && ['systemPrompt', 'userPrompt', 'memories'].includes(id)
const anyConditionMet =
matchingConfigs.length === 0
? true
: matchingConfigs.some(
(config) =>
shouldIncludeField(config, isAdvancedMode) &&
evaluateCondition(config.condition, allValues)
)
// Check if field's condition is met (conditionally-hidden fields should be excluded)
const conditionMet = subBlockConfig
? evaluateCondition(subBlockConfig.condition, allValues)
: true
if (
(matchingConfigs.length > 0 && anyConditionMet) ||
(subBlockConfig && shouldIncludeField(subBlockConfig, isAdvancedMode) && conditionMet) ||
hasStarterInputFormatValues ||
isLegacyAgentField
) {
@@ -543,26 +540,26 @@ export class Serializer {
// Iterate through the tool's parameters, not the block's subBlocks
Object.entries(currentTool.params || {}).forEach(([paramId, paramConfig]) => {
if (paramConfig.required && paramConfig.visibility === 'user-only') {
const matchingConfigs = blockConfig.subBlocks?.filter((sb: any) => sb.id === paramId) || []
const subBlockConfig = blockConfig.subBlocks?.find((sb: any) => sb.id === paramId)
let shouldValidateParam = true
if (matchingConfigs.length > 0) {
if (subBlockConfig) {
const isAdvancedMode = block.advancedMode ?? false
const includedByMode = shouldIncludeField(subBlockConfig, isAdvancedMode)
shouldValidateParam = matchingConfigs.some((subBlockConfig: any) => {
const includedByMode = shouldIncludeField(subBlockConfig, isAdvancedMode)
// Check visibility condition
const includedByCondition = evaluateCondition(subBlockConfig.condition, params)
const includedByCondition = evaluateCondition(subBlockConfig.condition, params)
// Check if field is required based on its required condition (if it's a condition object)
const isRequired = (() => {
if (!subBlockConfig.required) return false
if (typeof subBlockConfig.required === 'boolean') return subBlockConfig.required
// If required is a condition object, evaluate it
return evaluateCondition(subBlockConfig.required, params)
})()
const isRequired = (() => {
if (!subBlockConfig.required) return false
if (typeof subBlockConfig.required === 'boolean') return subBlockConfig.required
return evaluateCondition(subBlockConfig.required, params)
})()
return includedByMode && includedByCondition && isRequired
})
shouldValidateParam = includedByMode && includedByCondition && isRequired
}
if (!shouldValidateParam) {
@@ -571,12 +568,7 @@ export class Serializer {
const fieldValue = params[paramId]
if (fieldValue === undefined || fieldValue === null || fieldValue === '') {
const activeConfig = matchingConfigs.find(
(config: any) =>
shouldIncludeField(config, block.advancedMode ?? false) &&
evaluateCondition(config.condition, params)
)
const displayName = activeConfig?.title || paramId
const displayName = subBlockConfig?.title || paramId
missingFields.push(displayName)
}
}
@@ -604,6 +596,8 @@ export class Serializer {
const accessibleIds = new Set<string>(ancestorIds)
accessibleIds.add(blockId)
// Only add starter block if it's actually upstream (already in ancestorIds)
// Don't add it just because it exists on the canvas
if (starterBlock && ancestorIds.includes(starterBlock.id)) {
accessibleIds.add(starterBlock.id)
}

View File

@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "simstudio",
@@ -25,7 +26,6 @@
"rss-parser": "3.13.0",
"socket.io-client": "4.8.1",
"twilio": "5.9.0",
"zod": "^3.24.2",
},
"devDependencies": {
"@biomejs/biome": "2.0.0-beta.5",
@@ -3936,6 +3936,8 @@
"oauth2-mock-server/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="],
"ollama-ai-provider-v2/zod": ["zod@4.2.0", "", {}, "sha512-Bd5fw9wlIhtqCCxotZgdTOMwGm1a0u75wARVEY9HMs1X17trvA/lMi4+MGK5EUfYkXVTbX8UDiDKW4OgzHVUZw=="],
"openai/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="],
"openai/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],

View File

@@ -38,7 +38,6 @@
"next-runtime-env": "3.3.0",
"@modelcontextprotocol/sdk": "1.20.2",
"@t3-oss/env-nextjs": "0.13.4",
"zod": "^3.24.2",
"@tanstack/react-query": "5.90.8",
"@tanstack/react-query-devtools": "5.90.2",
"@types/fluent-ffmpeg": "2.1.28",