From 4c3002f97df895d8a2d1cca424272f7b27537752 Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Wed, 18 Feb 2026 18:38:37 -0800 Subject: [PATCH] Checkpoint --- apps/sim/lib/copilot/vfs/workspace-vfs.ts | 38 ++++++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/apps/sim/lib/copilot/vfs/workspace-vfs.ts b/apps/sim/lib/copilot/vfs/workspace-vfs.ts index 10b1fabd4..a01be27cf 100644 --- a/apps/sim/lib/copilot/vfs/workspace-vfs.ts +++ b/apps/sim/lib/copilot/vfs/workspace-vfs.ts @@ -12,7 +12,7 @@ import { import { createLogger } from '@sim/logger' import { and, count, desc, eq, isNull } from 'drizzle-orm' import { getAllBlocks } from '@/blocks/registry' -import { getLatestVersionTools } from '@/tools/utils' +import { getLatestVersionTools, stripVersionSuffix } from '@/tools/utils' import { tools as toolRegistry } from '@/tools/registry' import { loadWorkflowFromNormalizedTables } from '@/lib/workflows/persistence/utils' import { sanitizeForCopilot } from '@/lib/workflows/sanitization/json-sanitizer' @@ -50,6 +50,11 @@ let staticComponentFiles: Map | null = null /** * Build the static component files from block and tool registries. * This only needs to happen once per process. + * + * Integration paths are derived deterministically from the block registry's + * `tools.access` arrays rather than splitting tool IDs on underscores. + * Each block declares which tools it owns, and the block type (minus version + * suffix) becomes the service directory name. */ function getStaticComponentFiles(): Map { if (staticComponentFiles) return staticComponentFiles @@ -61,18 +66,41 @@ function getStaticComponentFiles(): Map { staticComponentFiles.set(path, serializeBlockSchema(block)) } + // Build a reverse index: tool ID → service name from block registry. + // The block type (stripped of version suffix) is used as the service directory. + const toolToService = new Map() + for (const block of allBlocks) { + if (!block.tools?.access) continue + const service = stripVersionSuffix(block.type) + for (const toolId of block.tools.access) { + toolToService.set(toolId, service) + } + } + const latestTools = getLatestVersionTools(toolRegistry) + let integrationCount = 0 for (const [toolId, tool] of Object.entries(latestTools)) { - const parts = toolId.split('_') - const service = parts[0] - const operation = parts.slice(1).join('_') || 'default' + const baseName = stripVersionSuffix(toolId) + const service = toolToService.get(toolId) ?? toolToService.get(baseName) + if (!service) { + logger.debug('Tool not associated with any block, skipping VFS entry', { toolId }) + continue + } + + // Derive operation name by stripping the service prefix + const prefix = `${service}_` + const operation = baseName.startsWith(prefix) + ? baseName.slice(prefix.length) + : baseName + const path = `components/integrations/${service}/${operation}.json` staticComponentFiles.set(path, serializeIntegrationSchema(tool)) + integrationCount++ } logger.info('Static component files built', { blocks: allBlocks.length, - integrations: Object.keys(latestTools).length, + integrations: integrationCount, }) return staticComponentFiles