mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-26 15:28:03 -05:00
Compare commits
5 Commits
fix/kb-ws-
...
fix/multi-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a90c04e1c | ||
|
|
5b3cc2ba0d | ||
|
|
7ba07bc428 | ||
|
|
0c69f8b061 | ||
|
|
57e6203625 |
@@ -581,6 +581,18 @@ export const GmailV2Block: BlockConfig<GmailToolResponse> = {
|
|||||||
results: { type: 'json', description: 'Search/read summary results' },
|
results: { type: 'json', description: 'Search/read summary results' },
|
||||||
attachments: { type: 'json', description: 'Downloaded attachments (if enabled)' },
|
attachments: { type: 'json', description: 'Downloaded attachments (if enabled)' },
|
||||||
|
|
||||||
|
// Draft-specific outputs
|
||||||
|
draftId: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Draft ID',
|
||||||
|
condition: { field: 'operation', value: 'draft_gmail' },
|
||||||
|
},
|
||||||
|
messageId: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Gmail message ID for the draft',
|
||||||
|
condition: { field: 'operation', value: 'draft_gmail' },
|
||||||
|
},
|
||||||
|
|
||||||
// Trigger outputs (unchanged)
|
// Trigger outputs (unchanged)
|
||||||
email_id: { type: 'string', description: 'Gmail message ID' },
|
email_id: { type: 'string', description: 'Gmail message ID' },
|
||||||
thread_id: { type: 'string', description: 'Gmail thread ID' },
|
thread_id: { type: 'string', description: 'Gmail thread ID' },
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { getBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
|
|
||||||
import { normalizeName } from '@/executor/constants'
|
import { normalizeName } from '@/executor/constants'
|
||||||
import type { ExecutionContext } from '@/executor/types'
|
import type { ExecutionContext } from '@/executor/types'
|
||||||
import type { OutputSchema } from '@/executor/utils/block-reference'
|
import type { OutputSchema } from '@/executor/utils/block-reference'
|
||||||
|
import type { SerializedBlock } from '@/serializer/types'
|
||||||
|
import type { ToolConfig } from '@/tools/types'
|
||||||
|
import { getTool } from '@/tools/utils'
|
||||||
|
|
||||||
export interface BlockDataCollection {
|
export interface BlockDataCollection {
|
||||||
blockData: Record<string, unknown>
|
blockData: Record<string, unknown>
|
||||||
@@ -9,6 +11,32 @@ export interface BlockDataCollection {
|
|||||||
blockOutputSchemas: Record<string, OutputSchema>
|
blockOutputSchemas: Record<string, OutputSchema>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getBlockSchema(
|
||||||
|
block: SerializedBlock,
|
||||||
|
toolConfig?: ToolConfig
|
||||||
|
): OutputSchema | undefined {
|
||||||
|
const isTrigger =
|
||||||
|
block.metadata?.category === 'triggers' ||
|
||||||
|
(block.config?.params as Record<string, unknown> | undefined)?.triggerMode === true
|
||||||
|
|
||||||
|
// Triggers use saved outputs (defines the trigger payload schema)
|
||||||
|
if (isTrigger && block.outputs && Object.keys(block.outputs).length > 0) {
|
||||||
|
return block.outputs as OutputSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
// When a tool is selected, tool outputs are the source of truth
|
||||||
|
if (toolConfig?.outputs && Object.keys(toolConfig.outputs).length > 0) {
|
||||||
|
return toolConfig.outputs as OutputSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to saved outputs for blocks without tools
|
||||||
|
if (block.outputs && Object.keys(block.outputs).length > 0) {
|
||||||
|
return block.outputs as OutputSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
export function collectBlockData(ctx: ExecutionContext): BlockDataCollection {
|
export function collectBlockData(ctx: ExecutionContext): BlockDataCollection {
|
||||||
const blockData: Record<string, unknown> = {}
|
const blockData: Record<string, unknown> = {}
|
||||||
const blockNameMapping: Record<string, string> = {}
|
const blockNameMapping: Record<string, string> = {}
|
||||||
@@ -18,24 +46,21 @@ export function collectBlockData(ctx: ExecutionContext): BlockDataCollection {
|
|||||||
if (state.output !== undefined) {
|
if (state.output !== undefined) {
|
||||||
blockData[id] = state.output
|
blockData[id] = state.output
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const workflowBlock = ctx.workflow?.blocks?.find((b) => b.id === id)
|
const workflowBlocks = ctx.workflow?.blocks ?? []
|
||||||
if (!workflowBlock) continue
|
for (const block of workflowBlocks) {
|
||||||
|
const id = block.id
|
||||||
|
|
||||||
if (workflowBlock.metadata?.name) {
|
if (block.metadata?.name) {
|
||||||
blockNameMapping[normalizeName(workflowBlock.metadata.name)] = id
|
blockNameMapping[normalizeName(block.metadata.name)] = id
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockType = workflowBlock.metadata?.id
|
const toolId = block.config?.tool
|
||||||
if (blockType) {
|
const toolConfig = toolId ? getTool(toolId) : undefined
|
||||||
const params = workflowBlock.config?.params as Record<string, unknown> | undefined
|
const schema = getBlockSchema(block, toolConfig)
|
||||||
const subBlocks = params
|
if (schema && Object.keys(schema).length > 0) {
|
||||||
? Object.fromEntries(Object.entries(params).map(([k, v]) => [k, { value: v }]))
|
blockOutputSchemas[id] = schema
|
||||||
: undefined
|
|
||||||
const schema = getBlockOutputs(blockType, subBlocks)
|
|
||||||
if (schema && Object.keys(schema).length > 0) {
|
|
||||||
blockOutputSchemas[id] = schema
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -378,8 +378,30 @@ function buildManualTriggerOutput(
|
|||||||
return mergeFilesIntoOutput(output, workflowInput)
|
return mergeFilesIntoOutput(output, workflowInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildIntegrationTriggerOutput(workflowInput: unknown): NormalizedBlockOutput {
|
function buildIntegrationTriggerOutput(
|
||||||
return isPlainObject(workflowInput) ? (workflowInput as NormalizedBlockOutput) : {}
|
workflowInput: unknown,
|
||||||
|
structuredInput: Record<string, unknown>,
|
||||||
|
hasStructured: boolean
|
||||||
|
): NormalizedBlockOutput {
|
||||||
|
const output: NormalizedBlockOutput = {}
|
||||||
|
|
||||||
|
if (hasStructured) {
|
||||||
|
for (const [key, value] of Object.entries(structuredInput)) {
|
||||||
|
output[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPlainObject(workflowInput)) {
|
||||||
|
for (const [key, value] of Object.entries(workflowInput)) {
|
||||||
|
if (value !== undefined && value !== null) {
|
||||||
|
output[key] = value
|
||||||
|
} else if (!Object.hasOwn(output, key)) {
|
||||||
|
output[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergeFilesIntoOutput(output, workflowInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractSubBlocks(block: SerializedBlock): Record<string, unknown> | undefined {
|
function extractSubBlocks(block: SerializedBlock): Record<string, unknown> | undefined {
|
||||||
@@ -428,7 +450,7 @@ export function buildStartBlockOutput(options: StartBlockOutputOptions): Normali
|
|||||||
return buildManualTriggerOutput(finalInput, workflowInput)
|
return buildManualTriggerOutput(finalInput, workflowInput)
|
||||||
|
|
||||||
case StartBlockPath.EXTERNAL_TRIGGER:
|
case StartBlockPath.EXTERNAL_TRIGGER:
|
||||||
return buildIntegrationTriggerOutput(workflowInput)
|
return buildIntegrationTriggerOutput(workflowInput, structuredInput, hasStructured)
|
||||||
|
|
||||||
case StartBlockPath.LEGACY_STARTER:
|
case StartBlockPath.LEGACY_STARTER:
|
||||||
return buildLegacyStarterOutput(
|
return buildLegacyStarterOutput(
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { getBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
|
|
||||||
import {
|
import {
|
||||||
isReference,
|
isReference,
|
||||||
normalizeName,
|
normalizeName,
|
||||||
parseReferencePath,
|
parseReferencePath,
|
||||||
SPECIAL_REFERENCE_PREFIXES,
|
SPECIAL_REFERENCE_PREFIXES,
|
||||||
} from '@/executor/constants'
|
} from '@/executor/constants'
|
||||||
|
import { getBlockSchema } from '@/executor/utils/block-data'
|
||||||
import {
|
import {
|
||||||
InvalidFieldError,
|
InvalidFieldError,
|
||||||
type OutputSchema,
|
type OutputSchema,
|
||||||
@@ -67,15 +67,9 @@ export class BlockResolver implements Resolver {
|
|||||||
blockData[blockId] = output
|
blockData[blockId] = output
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockType = block.metadata?.id
|
|
||||||
const params = block.config?.params as Record<string, unknown> | undefined
|
|
||||||
const subBlocks = params
|
|
||||||
? Object.fromEntries(Object.entries(params).map(([k, v]) => [k, { value: v }]))
|
|
||||||
: undefined
|
|
||||||
const toolId = block.config?.tool
|
const toolId = block.config?.tool
|
||||||
const toolConfig = toolId ? getTool(toolId) : undefined
|
const toolConfig = toolId ? getTool(toolId) : undefined
|
||||||
const outputSchema =
|
const outputSchema = getBlockSchema(block, toolConfig)
|
||||||
toolConfig?.outputs ?? (blockType ? getBlockOutputs(blockType, subBlocks) : block.outputs)
|
|
||||||
|
|
||||||
if (outputSchema && Object.keys(outputSchema).length > 0) {
|
if (outputSchema && Object.keys(outputSchema).length > 0) {
|
||||||
blockOutputSchemas[blockId] = outputSchema
|
blockOutputSchemas[blockId] = outputSchema
|
||||||
|
|||||||
@@ -618,13 +618,6 @@ export function getToolOutputs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates output paths for a tool-based block.
|
|
||||||
*
|
|
||||||
* @param blockConfig - The block configuration containing tools config
|
|
||||||
* @param subBlocks - SubBlock values for tool selection and condition evaluation
|
|
||||||
* @returns Array of output paths for the tool, or empty array on error
|
|
||||||
*/
|
|
||||||
export function getToolOutputPaths(
|
export function getToolOutputPaths(
|
||||||
blockConfig: BlockConfig,
|
blockConfig: BlockConfig,
|
||||||
subBlocks?: Record<string, SubBlockWithValue>
|
subBlocks?: Record<string, SubBlockWithValue>
|
||||||
@@ -634,12 +627,22 @@ export function getToolOutputPaths(
|
|||||||
if (!outputs || Object.keys(outputs).length === 0) return []
|
if (!outputs || Object.keys(outputs).length === 0) return []
|
||||||
|
|
||||||
if (subBlocks && blockConfig.outputs) {
|
if (subBlocks && blockConfig.outputs) {
|
||||||
const filteredBlockOutputs = filterOutputsByCondition(blockConfig.outputs, subBlocks)
|
|
||||||
const allowedKeys = new Set(Object.keys(filteredBlockOutputs))
|
|
||||||
|
|
||||||
const filteredOutputs: Record<string, any> = {}
|
const filteredOutputs: Record<string, any> = {}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(outputs)) {
|
for (const [key, value] of Object.entries(outputs)) {
|
||||||
if (allowedKeys.has(key)) {
|
const blockOutput = blockConfig.outputs[key]
|
||||||
|
|
||||||
|
if (!blockOutput || typeof blockOutput !== 'object') {
|
||||||
|
filteredOutputs[key] = value
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const condition = 'condition' in blockOutput ? blockOutput.condition : undefined
|
||||||
|
if (condition) {
|
||||||
|
if (evaluateOutputCondition(condition, subBlocks)) {
|
||||||
|
filteredOutputs[key] = value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
filteredOutputs[key] = value
|
filteredOutputs[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user