Skip to content

Commit d7da73d

Browse files
committed
fix: guard the registry lookups, and scope the search-stale doc to its callers
`getBlock` normalizes its argument with `type.replace(...)`, so it throws on `undefined` where the `getAllBlocks().find(...)` it replaced returned `undefined` harmlessly. Both call sites can be reached without a type: `tool-input` reads `state.blocks[blockId]?.type`, which is undefined once the block is deleted while the panel is mounted — and `Record` indexing hides that from the compiler, so it would have thrown during render. `agent-handler`'s `tool.type` is optional and the compiler did catch it. Also index the skill lookup in `resolveSkillsLabel`, which runs a `.find()` inside a `.map()` for every block on the canvas — the case the memoised map in `skill-input` addressed for one component while leaving the hot path. `providers/utils.ts` keeps its `getAllBlocks().find(...)`: it takes the registry as an injected dependency precisely so a client-reachable module never imports it, and reaching for `getBlock` there would cross that boundary. The new constant's doc claimed search-backed selectors take a shorter window. Several still sit on `SELECTOR_STALE`, so it now describes the value its three callers share rather than asserting a rule the tree does not follow.
1 parent 5db2767 commit d7da73d

4 files changed

Lines changed: 12 additions & 8 deletions

File tree

  • apps/sim

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tool-input/tool-input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ export const ToolInput = memo(function ToolInput({
520520
// subBlock): shown in the picker but greyed out with a tooltip instead of added.
521521
const blockType = useWorkflowStore(useCallback((state) => state.blocks[blockId]?.type, [blockId]))
522522
const unsupportedToolTypes = useMemo<readonly ('mcp' | 'custom-tool')[]>(() => {
523-
const block = getBlock(blockType)
523+
const block = blockType ? getBlock(blockType) : undefined
524524
return block?.subBlocks.find((sb) => sb.id === subBlockId)?.unsupportedToolTypes ?? []
525525
}, [blockType, subBlockId])
526526
const mcpUnsupported = unsupportedToolTypes.includes('mcp')

apps/sim/executor/handlers/agent/agent-handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { selectModelBoundFileInputPaths } from '@/lib/uploads/utils/model-input'
3232
import { hydrateUserFilesWithBase64 } from '@/lib/uploads/utils/user-file-base64.server'
3333
import { resolveCustomBlockToolBinding } from '@/lib/workflows/custom-blocks/operations'
3434
import { getCustomToolById } from '@/lib/workflows/custom-tools/operations'
35-
import { getAllBlocks } from '@/blocks'
35+
import { getAllBlocks, getBlock } from '@/blocks'
3636
import { assembleCustomBlockInputMapping, isCustomBlockType } from '@/blocks/custom/build-config'
3737
import type { BlockOutput } from '@/blocks/types'
3838
import { normalizeFileInput } from '@/blocks/utils'
@@ -857,7 +857,7 @@ export class AgentBlockHandler implements BlockHandler {
857857
)
858858
if (tool.type === 'mcp' || tool.type === 'custom-tool') return alignedParams
859859

860-
const blockInputs = getAllBlocks().find((block) => block.type === tool.type)?.inputs
860+
const blockInputs = tool.type ? getBlock(tool.type)?.inputs : undefined
861861
return prepareResolvedSecretProjectedInputs(alignedParams, blockInputs, formattedParams)
862862
}
863863

apps/sim/hooks/selectors/providers/shared.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import type { SelectorContext, SelectorKey } from '@/hooks/selectors/types'
33
export const SELECTOR_STALE = 60 * 1000
44

55
/**
6-
* Stale window for selectors whose result set is search-backed.
6+
* The shorter stale window carried by `google.drive`, `jira.issues` and
7+
* `webflow.items`, whose listings turn over faster than {@link SELECTOR_STALE}
8+
* assumes.
79
*
8-
* Shorter than {@link SELECTOR_STALE} because the query key carries the search
9-
* term, so a stale entry is a stale answer to a question the user is still
10-
* typing rather than a stale copy of a stable list.
10+
* Not every search-backed selector uses it — several still sit on
11+
* {@link SELECTOR_STALE} — so treat this as the value those three share rather
12+
* than a rule about search.
1113
*/
1214
export const SELECTOR_SEARCH_STALE = 15 * 1000
1315

apps/sim/lib/workflows/subblocks/display.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,13 +556,15 @@ export function resolveSkillsLabel(
556556
if (subBlock?.type !== 'skill-input') return null
557557
if (!Array.isArray(rawValue) || rawValue.length === 0) return null
558558

559+
const skillsById = new Map(skills.map((skill) => [skill.id, skill]))
560+
559561
const names = rawValue
560562
.map((skill: unknown) => {
561563
if (!skill || typeof skill !== 'object') return null
562564
const s = skill as { skillId?: string; name?: string }
563565

564566
if (s.skillId) {
565-
const found = skills.find((candidate) => candidate.id === s.skillId)
567+
const found = skillsById.get(s.skillId)
566568
if (found?.name) return found.name
567569
}
568570
if (typeof s.name === 'string' && s.name) return s.name

0 commit comments

Comments
 (0)