mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
improvement(response-copilot): prefer builder mode + fix builder/editor mode conversions (#1648)
* improvement(response-copilot): make it use builder mode over editor mode to prevent json formatting issues * change placeholder text * fix conversion between builder and editor mode
This commit is contained in:
committed by
GitHub
parent
ba8acbba07
commit
701bf2b510
@@ -44,10 +44,20 @@ export function Dropdown({
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
const previousModeRef = useRef<string | null>(null)
|
||||
|
||||
// For response dataMode conversion - get builderData and data sub-blocks
|
||||
const [builderData] = useSubBlockValue<any[]>(blockId, 'builderData')
|
||||
const [, setData] = useSubBlockValue<string>(blockId, 'data')
|
||||
const [builderData, setBuilderData] = useSubBlockValue<any[]>(blockId, 'builderData')
|
||||
const [data, setData] = useSubBlockValue<string>(blockId, 'data')
|
||||
|
||||
// Keep refs with latest values to avoid stale closures
|
||||
const builderDataRef = useRef(builderData)
|
||||
const dataRef = useRef(data)
|
||||
|
||||
useEffect(() => {
|
||||
builderDataRef.current = builderData
|
||||
dataRef.current = data
|
||||
}, [builderData, data])
|
||||
|
||||
// Use preview value when in preview mode, otherwise use store value or prop value
|
||||
const value = isPreview ? previewValue : propValue !== undefined ? propValue : storeValue
|
||||
@@ -103,23 +113,89 @@ export function Dropdown({
|
||||
}
|
||||
}, [storeInitialized, value, defaultOptionValue, setStoreValue])
|
||||
|
||||
// Helper function to normalize variable references in JSON strings
|
||||
const normalizeVariableReferences = (jsonString: string): string => {
|
||||
// Replace unquoted variable references with quoted ones
|
||||
// Pattern: <variable.name> -> "<variable.name>"
|
||||
return jsonString.replace(/([^"]<[^>]+>)/g, '"$1"')
|
||||
}
|
||||
|
||||
// Helper function to convert JSON string to builder data format
|
||||
const convertJsonToBuilderData = (jsonString: string): any[] => {
|
||||
try {
|
||||
// Always normalize variable references first
|
||||
const normalizedJson = normalizeVariableReferences(jsonString)
|
||||
const parsed = JSON.parse(normalizedJson)
|
||||
|
||||
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
||||
return Object.entries(parsed).map(([key, value]) => {
|
||||
const fieldType = inferType(value)
|
||||
const fieldValue =
|
||||
fieldType === 'object' || fieldType === 'array' ? JSON.stringify(value, null, 2) : value
|
||||
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
name: key,
|
||||
type: fieldType,
|
||||
value: fieldValue,
|
||||
collapsed: false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return []
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to infer field type from value
|
||||
const inferType = (value: any): 'string' | 'number' | 'boolean' | 'object' | 'array' => {
|
||||
if (typeof value === 'boolean') return 'boolean'
|
||||
if (typeof value === 'number') return 'number'
|
||||
if (Array.isArray(value)) return 'array'
|
||||
if (typeof value === 'object' && value !== null) return 'object'
|
||||
return 'string'
|
||||
}
|
||||
|
||||
// Handle data conversion when dataMode changes
|
||||
useEffect(() => {
|
||||
if (subBlockId !== 'dataMode' || isPreview || disabled) return
|
||||
|
||||
const currentMode = storeValue
|
||||
const previousMode = previousModeRef.current
|
||||
|
||||
// Only convert if the mode actually changed
|
||||
if (previousMode !== null && previousMode !== currentMode) {
|
||||
// Builder to Editor mode (structured → json)
|
||||
if (currentMode === 'json' && previousMode === 'structured') {
|
||||
const currentBuilderData = builderDataRef.current
|
||||
if (
|
||||
currentBuilderData &&
|
||||
Array.isArray(currentBuilderData) &&
|
||||
currentBuilderData.length > 0
|
||||
) {
|
||||
const jsonString = ResponseBlockHandler.convertBuilderDataToJsonString(currentBuilderData)
|
||||
setData(jsonString)
|
||||
}
|
||||
}
|
||||
// Editor to Builder mode (json → structured)
|
||||
else if (currentMode === 'structured' && previousMode === 'json') {
|
||||
const currentData = dataRef.current
|
||||
if (currentData && typeof currentData === 'string' && currentData.trim().length > 0) {
|
||||
const builderArray = convertJsonToBuilderData(currentData)
|
||||
setBuilderData(builderArray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the previous mode ref
|
||||
previousModeRef.current = currentMode
|
||||
}, [storeValue, subBlockId, isPreview, disabled, setData, setBuilderData])
|
||||
|
||||
// Event handlers
|
||||
const handleSelect = (selectedValue: string) => {
|
||||
if (!isPreview && !disabled) {
|
||||
// Handle conversion when switching from Builder to Editor mode in response blocks
|
||||
if (
|
||||
subBlockId === 'dataMode' &&
|
||||
storeValue === 'structured' &&
|
||||
selectedValue === 'json' &&
|
||||
builderData &&
|
||||
Array.isArray(builderData) &&
|
||||
builderData.length > 0
|
||||
) {
|
||||
// Convert builderData to JSON string for editor mode
|
||||
const jsonString = ResponseBlockHandler.convertBuilderDataToJsonString(builderData)
|
||||
setData(jsonString)
|
||||
}
|
||||
|
||||
setStoreValue(selectedValue)
|
||||
}
|
||||
setOpen(false)
|
||||
|
||||
@@ -83,9 +83,8 @@ export function FieldFormat({
|
||||
const [activeSourceBlockId, setActiveSourceBlockId] = useState<string | null>(null)
|
||||
const accessiblePrefixes = useAccessibleReferencePrefixes(blockId)
|
||||
|
||||
// Use preview value when in preview mode, otherwise use store value
|
||||
const value = isPreview ? previewValue : storeValue
|
||||
const fields: Field[] = value || []
|
||||
const fields: Field[] = Array.isArray(value) ? value : []
|
||||
|
||||
useEffect(() => {
|
||||
const initial: Record<string, string> = {}
|
||||
@@ -547,7 +546,7 @@ export function ResponseFormat(
|
||||
emptyMessage='No response fields defined'
|
||||
showType={false}
|
||||
showValue={true}
|
||||
valuePlaceholder='Enter test value'
|
||||
valuePlaceholder='Enter return value'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export const ResponseBlock: BlockConfig<ResponseBlockOutput> = {
|
||||
docsLink: 'https://docs.sim.ai/blocks/response',
|
||||
bestPractices: `
|
||||
- Only use this if the trigger block is the API Trigger.
|
||||
- Prefer the editor mode over the builder mode.
|
||||
- Prefer the builder mode over the editor mode.
|
||||
- This is usually used as the last block in the workflow.
|
||||
`,
|
||||
category: 'blocks',
|
||||
|
||||
Reference in New Issue
Block a user