From 945c526ede7da33485e9531b34be5e8d406605c7 Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Sun, 14 Jun 2026 22:27:36 -0700 Subject: [PATCH 1/6] feat(mothership): add enrichment_run server tool for one-off lookups Implement the Sim-side handler for the copilot enrichment_run tool: runs the enrichment provider cascade for a single entity and returns the result inline, surfacing the hosted-key cost as _serviceCost for per-round billing (matching the media tools). Registered in the server-tool router. Regenerate the copilot tool catalog/schemas to include enrichment_run. --- .../lib/copilot/generated/tool-catalog-v1.ts | 137 ++++---- .../lib/copilot/generated/tool-schemas-v1.ts | 319 +++++++++--------- .../tools/server/enrichment/enrichment-run.ts | 66 ++++ apps/sim/lib/copilot/tools/server/router.ts | 2 + 4 files changed, 289 insertions(+), 235 deletions(-) create mode 100644 apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts diff --git a/apps/sim/lib/copilot/generated/tool-catalog-v1.ts b/apps/sim/lib/copilot/generated/tool-catalog-v1.ts index 4abbd46b8db..a6b42aba811 100644 --- a/apps/sim/lib/copilot/generated/tool-catalog-v1.ts +++ b/apps/sim/lib/copilot/generated/tool-catalog-v1.ts @@ -30,6 +30,7 @@ export interface ToolCatalogEntry { | 'download_to_workspace_file' | 'edit_content' | 'edit_workflow' + | 'enrichment_run' | 'ffmpeg' | 'file' | 'function_execute' @@ -97,7 +98,6 @@ export interface ToolCatalogEntry { | 'set_global_workflow_variables' | 'superagent' | 'table' - | 'touch_plan' | 'update_deployment_version' | 'update_job_history' | 'update_workspace_mcp_server' @@ -131,6 +131,7 @@ export interface ToolCatalogEntry { | 'download_to_workspace_file' | 'edit_content' | 'edit_workflow' + | 'enrichment_run' | 'ffmpeg' | 'file' | 'function_execute' @@ -198,7 +199,6 @@ export interface ToolCatalogEntry { | 'set_global_workflow_variables' | 'superagent' | 'table' - | 'touch_plan' | 'update_deployment_version' | 'update_job_history' | 'update_workspace_mcp_server' @@ -1073,6 +1073,54 @@ export const EditWorkflow: ToolCatalogEntry = { requiredPermission: 'write', } +export const EnrichmentRun: ToolCatalogEntry = { + id: 'enrichment_run', + name: 'enrichment_run', + route: 'sim', + mode: 'async', + parameters: { + type: 'object', + properties: { + enrichmentId: { + type: 'string', + description: + "Which enrichment to run. Discover the full set and each one's inputs/outputs via user_table.list_enrichments.", + enum: [ + 'work-email', + 'phone-number', + 'company-domain', + 'company-info', + 'email-verification', + ], + }, + inputs: { + type: 'object', + description: + 'Map of the enrichment\'s input id → value, e.g. { "fullName": "Jane Doe", "companyDomain": "acme.com" }. Provide a value for every required input.', + }, + }, + required: ['enrichmentId', 'inputs'], + }, + resultSchema: { + type: 'object', + properties: { + matched: { + type: 'boolean', + description: 'True when a provider returned a non-empty result.', + }, + provider: { + type: 'string', + description: 'Label of the provider that produced the result, or null on no match.', + }, + result: { + type: 'object', + description: 'Mapped output values from the winning provider (empty object on no match).', + }, + }, + required: ['matched', 'result'], + }, +} + export const Ffmpeg: ToolCatalogEntry = { id: 'ffmpeg', name: 'ffmpeg', @@ -1106,7 +1154,7 @@ export const Ffmpeg: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1126,7 +1174,7 @@ export const Ffmpeg: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1207,8 +1255,7 @@ export const Ffmpeg: ToolCatalogEntry = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1287,7 +1334,7 @@ export const FunctionExecute: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1307,7 +1354,7 @@ export const FunctionExecute: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1372,8 +1419,7 @@ export const FunctionExecute: ToolCatalogEntry = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1449,7 +1495,7 @@ export const GenerateAudio: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1469,7 +1515,7 @@ export const GenerateAudio: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1539,8 +1585,7 @@ export const GenerateAudio: ToolCatalogEntry = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1599,7 +1644,7 @@ export const GenerateImage: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1619,7 +1664,7 @@ export const GenerateImage: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1674,8 +1719,7 @@ export const GenerateImage: ToolCatalogEntry = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1737,7 +1781,7 @@ export const GenerateVideo: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1757,7 +1801,7 @@ export const GenerateVideo: ToolCatalogEntry = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1833,8 +1877,7 @@ export const GenerateVideo: ToolCatalogEntry = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -3694,54 +3737,6 @@ export const Table: ToolCatalogEntry = { internal: true, } -export const TouchPlan: ToolCatalogEntry = { - id: 'touch_plan', - name: 'touch_plan', - route: 'sim', - mode: 'async', - parameters: { - type: 'object', - properties: { - name: { - type: 'string', - description: - 'Plan file name or relative path under .plans, e.g. "implementation.md" or "phase-1/implementation.md". If no extension is supplied, ".md" is appended.', - }, - scope: { - type: 'string', - description: - 'Plan scope. Use "workspace" for root .plans/** main-agent plans. Use "workflow" for workflows/{workflow}/.plans/** subplans. If omitted with workflowPath, workflow scope is assumed; otherwise workspace scope is assumed.', - enum: ['workspace', 'workflow'], - }, - title: { - type: 'string', - description: 'Optional short user-visible label for the plan creation.', - }, - workflowPath: { - type: 'string', - description: - 'Required for scope "workflow". Canonical workflow VFS path, e.g. "workflows/My%20Workflow" or "workflows/Folder/My%20Workflow". Copy paths verbatim from glob/read/grep output — they are percent-encoded per segment (spaces are %20, an in-name slash is %2F; parentheses and dots stay literal). Both the encoded path and the plain name resolve, so copy the returned path exactly rather than retyping or decoding it. Do not use workflow IDs.', - }, - }, - required: ['name'], - }, - resultSchema: { - type: 'object', - properties: { - data: { - type: 'object', - description: - 'Contains id, name, scope, vfsPath, backingVfsPath, and workflowId for workflow plans. Use vfsPath for follow-up workspace_file calls.', - }, - message: { type: 'string', description: 'Human-readable outcome.' }, - success: { type: 'boolean', description: 'Whether the plan file was created.' }, - }, - required: ['success', 'message'], - }, - requiredPermission: 'write', - capabilities: ['file_output'], -} - export const UpdateDeploymentVersion: ToolCatalogEntry = { id: 'update_deployment_version', name: 'update_deployment_version', @@ -4627,6 +4622,7 @@ export const TOOL_CATALOG: Record = { [DownloadToWorkspaceFile.id]: DownloadToWorkspaceFile, [EditContent.id]: EditContent, [EditWorkflow.id]: EditWorkflow, + [EnrichmentRun.id]: EnrichmentRun, [Ffmpeg.id]: Ffmpeg, [File.id]: File, [FunctionExecute.id]: FunctionExecute, @@ -4694,7 +4690,6 @@ export const TOOL_CATALOG: Record = { [SetGlobalWorkflowVariables.id]: SetGlobalWorkflowVariables, [Superagent.id]: Superagent, [Table.id]: Table, - [TouchPlan.id]: TouchPlan, [UpdateDeploymentVersion.id]: UpdateDeploymentVersion, [UpdateJobHistory.id]: UpdateJobHistory, [UpdateWorkspaceMcpServer.id]: UpdateWorkspaceMcpServer, diff --git a/apps/sim/lib/copilot/generated/tool-schemas-v1.ts b/apps/sim/lib/copilot/generated/tool-schemas-v1.ts index 0c4c0d06517..77888ddef2c 100644 --- a/apps/sim/lib/copilot/generated/tool-schemas-v1.ts +++ b/apps/sim/lib/copilot/generated/tool-schemas-v1.ts @@ -10,7 +10,7 @@ export interface ToolRuntimeSchemaEntry { } export const TOOL_RUNTIME_SCHEMAS: Record = { - agent: { + ['agent']: { parameters: { properties: { request: { @@ -23,7 +23,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - auth: { + ['auth']: { parameters: { properties: { request: { @@ -36,7 +36,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - check_deployment_status: { + ['check_deployment_status']: { parameters: { type: 'object', properties: { @@ -48,7 +48,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - complete_job: { + ['complete_job']: { parameters: { type: 'object', properties: { @@ -61,7 +61,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - crawl_website: { + ['crawl_website']: { parameters: { type: 'object', properties: { @@ -96,7 +96,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - create_file: { + ['create_file']: { parameters: { type: 'object', properties: { @@ -162,7 +162,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { required: ['success', 'message'], }, }, - create_file_folder: { + ['create_file_folder']: { parameters: { type: 'object', properties: { @@ -180,7 +180,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - create_folder: { + ['create_folder']: { parameters: { type: 'object', properties: { @@ -201,7 +201,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - create_workflow: { + ['create_workflow']: { parameters: { type: 'object', properties: { @@ -226,7 +226,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - create_workspace_mcp_server: { + ['create_workspace_mcp_server']: { parameters: { type: 'object', properties: { @@ -259,7 +259,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - delete_file: { + ['delete_file']: { parameters: { type: 'object', properties: { @@ -289,7 +289,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { required: ['success', 'message'], }, }, - delete_file_folder: { + ['delete_file_folder']: { parameters: { type: 'object', properties: { @@ -305,7 +305,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - delete_folder: { + ['delete_folder']: { parameters: { type: 'object', properties: { @@ -321,7 +321,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - delete_workflow: { + ['delete_workflow']: { parameters: { type: 'object', properties: { @@ -337,7 +337,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - delete_workspace_mcp_server: { + ['delete_workspace_mcp_server']: { parameters: { type: 'object', properties: { @@ -350,7 +350,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - deploy: { + ['deploy']: { parameters: { properties: { request: { @@ -364,7 +364,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - deploy_api: { + ['deploy_api']: { parameters: { type: 'object', properties: { @@ -448,7 +448,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { ], }, }, - deploy_chat: { + ['deploy_chat']: { parameters: { type: 'object', properties: { @@ -607,7 +607,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { ], }, }, - deploy_mcp: { + ['deploy_mcp']: { parameters: { type: 'object', properties: { @@ -723,7 +723,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { required: ['deploymentType', 'deploymentStatus'], }, }, - diff_workflows: { + ['diff_workflows']: { parameters: { type: 'object', properties: { @@ -747,7 +747,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - download_to_workspace_file: { + ['download_to_workspace_file']: { parameters: { type: 'object', properties: { @@ -796,7 +796,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - edit_content: { + ['edit_content']: { parameters: { type: 'object', properties: { @@ -828,7 +828,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { required: ['success', 'message'], }, }, - edit_workflow: { + ['edit_workflow']: { parameters: { type: 'object', properties: { @@ -867,7 +867,50 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - ffmpeg: { + ['enrichment_run']: { + parameters: { + type: 'object', + properties: { + enrichmentId: { + type: 'string', + description: + "Which enrichment to run. Discover the full set and each one's inputs/outputs via user_table.list_enrichments.", + enum: [ + 'work-email', + 'phone-number', + 'company-domain', + 'company-info', + 'email-verification', + ], + }, + inputs: { + type: 'object', + description: + 'Map of the enrichment\'s input id → value, e.g. { "fullName": "Jane Doe", "companyDomain": "acme.com" }. Provide a value for every required input.', + }, + }, + required: ['enrichmentId', 'inputs'], + }, + resultSchema: { + type: 'object', + properties: { + matched: { + type: 'boolean', + description: 'True when a provider returned a non-empty result.', + }, + provider: { + type: 'string', + description: 'Label of the provider that produced the result, or null on no match.', + }, + result: { + type: 'object', + description: 'Mapped output values from the winning provider (empty object on no match).', + }, + }, + required: ['matched', 'result'], + }, + }, + ['ffmpeg']: { parameters: { type: 'object', properties: { @@ -902,7 +945,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -922,7 +965,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1009,8 +1052,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1049,7 +1091,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - file: { + ['file']: { parameters: { properties: { prompt: { @@ -1062,7 +1104,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - function_execute: { + ['function_execute']: { parameters: { type: 'object', properties: { @@ -1086,7 +1128,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1106,7 +1148,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1177,8 +1219,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1201,7 +1242,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - generate_api_key: { + ['generate_api_key']: { parameters: { type: 'object', properties: { @@ -1219,7 +1260,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - generate_audio: { + ['generate_audio']: { parameters: { type: 'object', properties: { @@ -1243,7 +1284,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1263,7 +1304,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1339,8 +1380,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1372,7 +1412,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - generate_image: { + ['generate_image']: { parameters: { type: 'object', properties: { @@ -1396,7 +1436,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1416,7 +1456,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1477,8 +1517,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1501,7 +1540,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - generate_video: { + ['generate_video']: { parameters: { type: 'object', properties: { @@ -1534,7 +1573,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS folder path, e.g. "files/Reports" or "workflows/My%20Workflow/.plans". By default this mounts at "/home/user/{path}". Workflow alias directories mount under "/home/user/workflows/...".', + 'Canonical VFS folder path, e.g. "files/Reports". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1554,7 +1593,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { path: { type: 'string', description: - 'Canonical VFS file path, e.g. "files/Reports/sales.csv" or "workflows/My%20Workflow/changelog.md". By default this mounts at "/home/user/{path}". Workflow alias paths mount under "/home/user/workflows/...".', + 'Canonical VFS file path, e.g. "files/Reports/sales.csv". By default this mounts at "/home/user/{path}".', }, sandboxPath: { type: 'string', @@ -1636,8 +1675,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, path: { type: 'string', - description: - 'Canonical destination VFS path, e.g. "files/Reports/chart.png", "workflows/My%20Workflow/changelog.md", or "workflows/My%20Workflow/.plans/plan.md".', + description: 'Canonical destination VFS path, e.g. "files/Reports/chart.png".', }, sandboxPath: { type: 'string', @@ -1669,7 +1707,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - get_block_outputs: { + ['get_block_outputs']: { parameters: { type: 'object', properties: { @@ -1690,7 +1728,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - get_block_upstream_references: { + ['get_block_upstream_references']: { parameters: { type: 'object', properties: { @@ -1712,7 +1750,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - get_deployed_workflow_state: { + ['get_deployed_workflow_state']: { parameters: { type: 'object', properties: { @@ -1725,7 +1763,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - get_deployment_log: { + ['get_deployment_log']: { parameters: { type: 'object', properties: { @@ -1738,7 +1776,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - get_job_logs: { + ['get_job_logs']: { parameters: { type: 'object', properties: { @@ -1763,7 +1801,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - get_page_contents: { + ['get_page_contents']: { parameters: { type: 'object', properties: { @@ -1791,14 +1829,14 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - get_platform_actions: { + ['get_platform_actions']: { parameters: { type: 'object', properties: {}, }, resultSchema: undefined, }, - get_workflow_data: { + ['get_workflow_data']: { parameters: { type: 'object', properties: { @@ -1817,7 +1855,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - get_workflow_run_options: { + ['get_workflow_run_options']: { parameters: { type: 'object', properties: { @@ -1830,7 +1868,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - glob: { + ['glob']: { parameters: { type: 'object', properties: { @@ -1849,7 +1887,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - grep: { + ['grep']: { parameters: { type: 'object', properties: { @@ -1897,7 +1935,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - job: { + ['job']: { parameters: { properties: { request: { @@ -1910,7 +1948,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - knowledge: { + ['knowledge']: { parameters: { properties: { request: { @@ -1923,7 +1961,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - knowledge_base: { + ['knowledge_base']: { parameters: { type: 'object', properties: { @@ -2116,7 +2154,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { required: ['success', 'message'], }, }, - list_file_folders: { + ['list_file_folders']: { parameters: { type: 'object', properties: { @@ -2128,7 +2166,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - list_folders: { + ['list_folders']: { parameters: { type: 'object', properties: { @@ -2140,7 +2178,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - list_integration_tools: { + ['list_integration_tools']: { parameters: { properties: { integration: { @@ -2154,14 +2192,14 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - list_user_workspaces: { + ['list_user_workspaces']: { parameters: { type: 'object', properties: {}, }, resultSchema: undefined, }, - list_workspace_mcp_servers: { + ['list_workspace_mcp_servers']: { parameters: { type: 'object', properties: { @@ -2174,7 +2212,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - load_deployment: { + ['load_deployment']: { parameters: { type: 'object', properties: { @@ -2193,7 +2231,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - load_integration_tool: { + ['load_integration_tool']: { parameters: { properties: { tool_ids: { @@ -2210,7 +2248,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - manage_credential: { + ['manage_credential']: { parameters: { type: 'object', properties: { @@ -2239,7 +2277,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - manage_custom_tool: { + ['manage_custom_tool']: { parameters: { type: 'object', properties: { @@ -2319,7 +2357,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - manage_job: { + ['manage_job']: { parameters: { type: 'object', properties: { @@ -2394,7 +2432,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - manage_mcp_tool: { + ['manage_mcp_tool']: { parameters: { type: 'object', properties: { @@ -2446,7 +2484,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - manage_skill: { + ['manage_skill']: { parameters: { type: 'object', properties: { @@ -2479,7 +2517,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - materialize_file: { + ['materialize_file']: { parameters: { type: 'object', properties: { @@ -2503,7 +2541,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - media: { + ['media']: { parameters: { properties: { prompt: { @@ -2516,7 +2554,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - move_file: { + ['move_file']: { parameters: { type: 'object', properties: { @@ -2537,7 +2575,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - move_file_folder: { + ['move_file_folder']: { parameters: { type: 'object', properties: { @@ -2555,7 +2593,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - move_folder: { + ['move_folder']: { parameters: { type: 'object', properties: { @@ -2573,7 +2611,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - move_workflow: { + ['move_workflow']: { parameters: { type: 'object', properties: { @@ -2593,7 +2631,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - oauth_get_auth_link: { + ['oauth_get_auth_link']: { parameters: { type: 'object', properties: { @@ -2607,7 +2645,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - oauth_request_access: { + ['oauth_request_access']: { parameters: { type: 'object', properties: { @@ -2621,7 +2659,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - open_resource: { + ['open_resource']: { parameters: { type: 'object', properties: { @@ -2655,7 +2693,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - promote_to_live: { + ['promote_to_live']: { parameters: { type: 'object', properties: { @@ -2674,7 +2712,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - query_logs: { + ['query_logs']: { parameters: { type: 'object', properties: { @@ -2785,7 +2823,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - read: { + ['read']: { parameters: { type: 'object', properties: { @@ -2812,7 +2850,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - redeploy: { + ['redeploy']: { parameters: { type: 'object', properties: { @@ -2891,7 +2929,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { ], }, }, - rename_file: { + ['rename_file']: { parameters: { type: 'object', properties: { @@ -2927,7 +2965,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { required: ['success', 'message'], }, }, - rename_file_folder: { + ['rename_file_folder']: { parameters: { type: 'object', properties: { @@ -2944,7 +2982,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - rename_workflow: { + ['rename_workflow']: { parameters: { type: 'object', properties: { @@ -2961,7 +2999,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - research: { + ['research']: { parameters: { properties: { topic: { @@ -2974,7 +3012,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - respond: { + ['respond']: { parameters: { additionalProperties: true, properties: { @@ -2997,7 +3035,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - restore_resource: { + ['restore_resource']: { parameters: { type: 'object', properties: { @@ -3015,7 +3053,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - run: { + ['run']: { parameters: { properties: { context: { @@ -3032,7 +3070,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - run_block: { + ['run_block']: { parameters: { type: 'object', properties: { @@ -3064,7 +3102,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - run_from_block: { + ['run_from_block']: { parameters: { type: 'object', properties: { @@ -3096,7 +3134,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - run_workflow: { + ['run_workflow']: { parameters: { type: 'object', properties: { @@ -3134,7 +3172,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - run_workflow_until_block: { + ['run_workflow_until_block']: { parameters: { type: 'object', properties: { @@ -3177,7 +3215,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - scrape_page: { + ['scrape_page']: { parameters: { type: 'object', properties: { @@ -3198,7 +3236,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - search_documentation: { + ['search_documentation']: { parameters: { type: 'object', properties: { @@ -3215,7 +3253,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - search_library_docs: { + ['search_library_docs']: { parameters: { type: 'object', properties: { @@ -3236,7 +3274,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - search_online: { + ['search_online']: { parameters: { type: 'object', properties: { @@ -3276,7 +3314,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - search_patterns: { + ['search_patterns']: { parameters: { type: 'object', properties: { @@ -3298,7 +3336,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - set_block_enabled: { + ['set_block_enabled']: { parameters: { type: 'object', properties: { @@ -3320,7 +3358,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - set_environment_variables: { + ['set_environment_variables']: { parameters: { type: 'object', properties: { @@ -3354,7 +3392,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - set_global_workflow_variables: { + ['set_global_workflow_variables']: { parameters: { type: 'object', properties: { @@ -3395,7 +3433,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - superagent: { + ['superagent']: { parameters: { properties: { task: { @@ -3409,7 +3447,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - table: { + ['table']: { parameters: { properties: { request: { @@ -3422,54 +3460,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - touch_plan: { - parameters: { - type: 'object', - properties: { - name: { - type: 'string', - description: - 'Plan file name or relative path under .plans, e.g. "implementation.md" or "phase-1/implementation.md". If no extension is supplied, ".md" is appended.', - }, - scope: { - type: 'string', - description: - 'Plan scope. Use "workspace" for root .plans/** main-agent plans. Use "workflow" for workflows/{workflow}/.plans/** subplans. If omitted with workflowPath, workflow scope is assumed; otherwise workspace scope is assumed.', - enum: ['workspace', 'workflow'], - }, - title: { - type: 'string', - description: 'Optional short user-visible label for the plan creation.', - }, - workflowPath: { - type: 'string', - description: - 'Required for scope "workflow". Canonical workflow VFS path, e.g. "workflows/My%20Workflow" or "workflows/Folder/My%20Workflow". Copy paths verbatim from glob/read/grep output — they are percent-encoded per segment (spaces are %20, an in-name slash is %2F; parentheses and dots stay literal). Both the encoded path and the plain name resolve, so copy the returned path exactly rather than retyping or decoding it. Do not use workflow IDs.', - }, - }, - required: ['name'], - }, - resultSchema: { - type: 'object', - properties: { - data: { - type: 'object', - description: - 'Contains id, name, scope, vfsPath, backingVfsPath, and workflowId for workflow plans. Use vfsPath for follow-up workspace_file calls.', - }, - message: { - type: 'string', - description: 'Human-readable outcome.', - }, - success: { - type: 'boolean', - description: 'Whether the plan file was created.', - }, - }, - required: ['success', 'message'], - }, - }, - update_deployment_version: { + ['update_deployment_version']: { parameters: { type: 'object', properties: { @@ -3498,7 +3489,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - update_job_history: { + ['update_job_history']: { parameters: { type: 'object', properties: { @@ -3516,7 +3507,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - update_workspace_mcp_server: { + ['update_workspace_mcp_server']: { parameters: { type: 'object', properties: { @@ -3541,7 +3532,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - user_memory: { + ['user_memory']: { parameters: { type: 'object', properties: { @@ -3590,7 +3581,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - user_table: { + ['user_table']: { parameters: { type: 'object', properties: { @@ -3952,7 +3943,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { required: ['success', 'message'], }, }, - workflow: { + ['workflow']: { parameters: { properties: { prompt: { @@ -3965,7 +3956,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, resultSchema: undefined, }, - workspace_file: { + ['workspace_file']: { parameters: { type: 'object', properties: { diff --git a/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts b/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts new file mode 100644 index 00000000000..8c1e3f3ea51 --- /dev/null +++ b/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts @@ -0,0 +1,66 @@ +import { createLogger } from '@sim/logger' +import { EnrichmentRun } from '@/lib/copilot/generated/tool-catalog-v1' +import type { BaseServerTool } from '@/lib/copilot/tools/server/base-tool' +import { getEnrichment } from '@/enrichments/registry' +import { runEnrichment } from '@/enrichments/run' + +interface EnrichmentRunParams { + enrichmentId: string + inputs?: Record +} + +interface EnrichmentRunResult { + matched: boolean + result: Record + provider: string | null + /** Hosted-key cost surfaced for per-round billing (omitted for BYOK / free). */ + _serviceCost?: { service: string; cost: number } +} + +/** + * Direct one-off enrichment lookup. Runs the same provider cascade as table + * enrichments (`runEnrichment`) for a single entity and returns the result + * inline — no table required. The hosted-key cost is surfaced as `_serviceCost` + * so copilot's per-round billing charges for it, matching how the media tools + * bill (see image/generate-image.ts). + */ +export const enrichmentRunServerTool: BaseServerTool = { + name: EnrichmentRun.id, + async execute(params: EnrichmentRunParams, context): Promise { + const logger = createLogger('EnrichmentRunServerTool') + const { enrichmentId, inputs } = params + + if (!enrichmentId || typeof enrichmentId !== 'string') { + throw new Error('enrichmentId is required') + } + const workspaceId = context?.workspaceId + if (!workspaceId) { + throw new Error('workspaceId is required to run an enrichment') + } + const enrichment = getEnrichment(enrichmentId) + if (!enrichment) { + throw new Error(`Unknown enrichment "${enrichmentId}"`) + } + + const { result, cost, error, provider } = await runEnrichment(enrichment, inputs ?? {}, { + workspaceId, + signal: context?.abortSignal, + }) + + const matched = Object.keys(result).length > 0 + logger.info('Enrichment run', { enrichmentId, matched, provider }) + + // A genuine "no match" returns normally (matched: false). Only surface an + // error when every provider that ran failed (infra/auth/rate-limit). + if (error && !matched) { + throw new Error(error) + } + + return { + matched, + result, + provider, + ...(cost > 0 ? { _serviceCost: { service: provider ?? enrichmentId, cost } } : {}), + } + }, +} diff --git a/apps/sim/lib/copilot/tools/server/router.ts b/apps/sim/lib/copilot/tools/server/router.ts index a151b25a511..27462e91285 100644 --- a/apps/sim/lib/copilot/tools/server/router.ts +++ b/apps/sim/lib/copilot/tools/server/router.ts @@ -31,6 +31,7 @@ import { import { getBlocksMetadataServerTool } from '@/lib/copilot/tools/server/blocks/get-blocks-metadata-tool' import { getTriggerBlocksServerTool } from '@/lib/copilot/tools/server/blocks/get-trigger-blocks' import { searchDocumentationServerTool } from '@/lib/copilot/tools/server/docs/search-documentation' +import { enrichmentRunServerTool } from '@/lib/copilot/tools/server/enrichment/enrichment-run' import { createFileServerTool } from '@/lib/copilot/tools/server/files/create-file' import { deleteFileServerTool } from '@/lib/copilot/tools/server/files/delete-file' import { downloadToWorkspaceFileServerTool } from '@/lib/copilot/tools/server/files/download-to-workspace-file' @@ -151,6 +152,7 @@ const baseServerToolRegistry: Record = { [setEnvironmentVariablesServerTool.name]: setEnvironmentVariablesServerTool, [getCredentialsServerTool.name]: getCredentialsServerTool, [knowledgeBaseServerTool.name]: knowledgeBaseServerTool, + [enrichmentRunServerTool.name]: enrichmentRunServerTool, [userTableServerTool.name]: userTableServerTool, [workspaceFileServerTool.name]: workspaceFileServerTool, [editContentServerTool.name]: editContentServerTool, From 8ed2e8164bf1a5d9aeebae360857001a435ae65b Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Sun, 14 Jun 2026 22:41:27 -0700 Subject: [PATCH 2/6] fix(mothership): remove leftover touch_plan tool references touch_plan was removed from the copilot tool catalog earlier, but the Sim side still referenced it. Regenerating the generated tool catalog (for enrichment_run) synced it to the current contract and dropped the stale TouchPlan export, which broke the build where router.ts still imported it. Remove the dead touch_plan server tool and its test, drop its router registration and WRITE_ACTIONS entry, simplify getServerToolRegistry (no more beta-gated server tools), and clean up stale "use touch_plan" guidance strings. --- .../copilot/tools/server/files/create-file.ts | 2 +- .../tools/server/files/touch-plan.test.ts | 143 ---------------- .../copilot/tools/server/files/touch-plan.ts | 152 ------------------ apps/sim/lib/copilot/tools/server/router.ts | 12 +- apps/sim/lib/copilot/vfs/resource-writer.ts | 4 +- 5 files changed, 3 insertions(+), 310 deletions(-) delete mode 100644 apps/sim/lib/copilot/tools/server/files/touch-plan.test.ts delete mode 100644 apps/sim/lib/copilot/tools/server/files/touch-plan.ts diff --git a/apps/sim/lib/copilot/tools/server/files/create-file.ts b/apps/sim/lib/copilot/tools/server/files/create-file.ts index d7b9489d6fd..146d0237773 100644 --- a/apps/sim/lib/copilot/tools/server/files/create-file.ts +++ b/apps/sim/lib/copilot/tools/server/files/create-file.ts @@ -56,7 +56,7 @@ export const createFileServerTool: BaseServerTool ({ - ensureWorkspaceAccess: vi.fn(), - resolveWorkflowAliasForWorkspace: vi.fn(), - writeWorkspaceFileByPath: vi.fn(), -})) - -vi.mock('@/lib/copilot/tools/handlers/access', () => ({ - ensureWorkspaceAccess: mocks.ensureWorkspaceAccess, -})) - -vi.mock('@/lib/copilot/vfs/workflow-alias-resolver', () => ({ - resolveWorkflowAliasForWorkspace: mocks.resolveWorkflowAliasForWorkspace, -})) - -vi.mock('@/lib/copilot/vfs/resource-writer', () => ({ - writeWorkspaceFileByPath: mocks.writeWorkspaceFileByPath, -})) - -vi.mock('@/lib/core/config/feature-flags', () => ({ - isMothershipBetaFeaturesEnabled: true, -})) - -import { touchPlanServerTool } from './touch-plan' - -describe('touch_plan server tool', () => { - beforeEach(() => { - vi.clearAllMocks() - mocks.ensureWorkspaceAccess.mockResolvedValue(undefined) - }) - - it('creates a workflow-local plan alias and returns backing metadata', async () => { - mocks.resolveWorkflowAliasForWorkspace.mockResolvedValue({ - kind: 'plan_file', - scope: 'workflow', - workflowId: 'wf_1', - workflowName: 'My Workflow', - workflowPath: 'workflows/My%20Workflow', - aliasPath: 'workflows/My%20Workflow/.plans/implementation.md', - backingPath: 'files/.plans/wf_1/implementation.md', - backingFolderPath: 'files/.plans/wf_1', - planRelativePath: 'implementation.md', - }) - mocks.writeWorkspaceFileByPath.mockResolvedValue({ - id: 'file-plan', - name: 'implementation.md', - vfsPath: 'workflows/My%20Workflow/.plans/implementation.md', - backingVfsPath: 'files/.plans/wf_1/implementation.md', - }) - - const result = await touchPlanServerTool.execute( - { workflowPath: 'workflows/My Workflow', name: 'implementation' }, - { userId: 'user-1', workspaceId: 'workspace-1' } - ) - - expect(mocks.resolveWorkflowAliasForWorkspace).toHaveBeenCalledWith({ - workspaceId: 'workspace-1', - path: 'workflows/My%20Workflow/.plans/implementation.md', - }) - expect(mocks.writeWorkspaceFileByPath).toHaveBeenCalledWith({ - workspaceId: 'workspace-1', - userId: 'user-1', - target: { - path: 'workflows/My%20Workflow/.plans/implementation.md', - mode: 'create', - mimeType: 'text/markdown', - }, - buffer: Buffer.from('', 'utf-8'), - inferredMimeType: 'text/markdown', - }) - expect(result).toMatchObject({ - success: true, - data: { - id: 'file-plan', - scope: 'workflow', - vfsPath: 'workflows/My%20Workflow/.plans/implementation.md', - backingVfsPath: 'files/.plans/wf_1/implementation.md', - workflowId: 'wf_1', - }, - }) - }) - - it('creates a workspace root plan alias and returns backing metadata', async () => { - mocks.resolveWorkflowAliasForWorkspace.mockResolvedValue({ - kind: 'plan_file', - scope: 'workspace', - aliasPath: '.plans/migration.md', - backingPath: 'files/.plans/workspace/migration.md', - backingFolderPath: 'files/.plans/workspace', - planRelativePath: 'migration.md', - }) - mocks.writeWorkspaceFileByPath.mockResolvedValue({ - id: 'file-root-plan', - name: 'migration.md', - vfsPath: '.plans/migration.md', - backingVfsPath: 'files/.plans/workspace/migration.md', - }) - - const result = await touchPlanServerTool.execute( - { scope: 'workspace', name: 'migration' }, - { userId: 'user-1', workspaceId: 'workspace-1' } - ) - - expect(mocks.resolveWorkflowAliasForWorkspace).toHaveBeenCalledWith({ - workspaceId: 'workspace-1', - path: '.plans/migration.md', - }) - expect(mocks.writeWorkspaceFileByPath).toHaveBeenCalledWith({ - workspaceId: 'workspace-1', - userId: 'user-1', - target: { - path: '.plans/migration.md', - mode: 'create', - mimeType: 'text/markdown', - }, - buffer: Buffer.from('', 'utf-8'), - inferredMimeType: 'text/markdown', - }) - expect(result).toMatchObject({ - success: true, - data: { - id: 'file-root-plan', - scope: 'workspace', - vfsPath: '.plans/migration.md', - backingVfsPath: 'files/.plans/workspace/migration.md', - }, - }) - }) - - it('rejects missing workflows before writing', async () => { - mocks.resolveWorkflowAliasForWorkspace.mockResolvedValue(null) - - const result = await touchPlanServerTool.execute( - { workflowPath: 'workflows/Missing', name: 'implementation.md' }, - { userId: 'user-1', workspaceId: 'workspace-1' } - ) - - expect(result.success).toBe(false) - expect(result.message).toContain('Workflow not found') - expect(mocks.writeWorkspaceFileByPath).not.toHaveBeenCalled() - }) -}) diff --git a/apps/sim/lib/copilot/tools/server/files/touch-plan.ts b/apps/sim/lib/copilot/tools/server/files/touch-plan.ts deleted file mode 100644 index 168903236ba..00000000000 --- a/apps/sim/lib/copilot/tools/server/files/touch-plan.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { createLogger } from '@sim/logger' -import { ensureWorkspaceAccess } from '@/lib/copilot/tools/handlers/access' -import { - assertServerToolNotAborted, - type BaseServerTool, - type ServerToolContext, -} from '@/lib/copilot/tools/server/base-tool' -import { - canonicalizeVfsPath, - decodeVfsPathSegments, - encodeVfsPathSegments, -} from '@/lib/copilot/vfs/path-utils' -import { writeWorkspaceFileByPath } from '@/lib/copilot/vfs/resource-writer' -import { resolveWorkflowAliasForWorkspace } from '@/lib/copilot/vfs/workflow-alias-resolver' -import { isMothershipBetaFeaturesEnabled } from '@/lib/core/config/feature-flags' - -const logger = createLogger('TouchPlanServerTool') -const TOUCH_PLAN_TOOL_ID = 'touch_plan' - -interface TouchPlanArgs { - scope?: 'workspace' | 'workflow' - workflowPath?: string - name: string - title?: string - args?: Record -} - -interface TouchPlanResult { - success: boolean - message: string - data?: { - id: string - name: string - vfsPath: string - backingVfsPath?: string - scope: 'workspace' | 'workflow' - workflowId?: string - } -} - -function normalizeWorkflowPath(path: string): string { - const trimmed = path.trim().replace(/^\/+|\/+$/g, '') - const withoutKnownLeaf = trimmed - .replace(/\/(meta|state|executions|deployment|versions|links)\.json$/, '') - .replace(/\/changelog\.md$/, '') - .replace(/\/\.plans$/, '') - - const canonical = canonicalizeVfsPath(withoutKnownLeaf) - if (!canonical.startsWith('workflows/')) { - throw new Error('workflowPath must be a canonical workflows/... VFS path') - } - return canonical -} - -function normalizePlanRelativePath(name: string): string { - const segments = decodeVfsPathSegments(name) - if (segments.length === 0) { - throw new Error('Plan name is required') - } - const leaf = segments.at(-1) ?? '' - const leafWithExtension = leaf.includes('.') ? leaf : `${leaf}.md` - return encodeVfsPathSegments([...segments.slice(0, -1), leafWithExtension]) -} - -export const touchPlanServerTool: BaseServerTool = { - name: TOUCH_PLAN_TOOL_ID, - async execute(params: TouchPlanArgs, context?: ServerToolContext): Promise { - if (!isMothershipBetaFeaturesEnabled) { - return { success: false, message: 'touch_plan is not available' } - } - if (!context?.userId) { - throw new Error('Authentication required') - } - const workspaceId = context.workspaceId - if (!workspaceId) { - return { success: false, message: 'Workspace ID is required' } - } - await ensureWorkspaceAccess(workspaceId, context.userId, 'write') - - const nested = params.args - const nestedScope = nested?.scope as TouchPlanArgs['scope'] | undefined - const scope = - params.scope || - nestedScope || - (params.workflowPath || nested?.workflowPath ? 'workflow' : 'workspace') - const workflowPath = params.workflowPath || (nested?.workflowPath as string) || '' - const name = params.name || (nested?.name as string) || '' - if (!name) { - return { success: false, message: 'touch_plan requires name' } - } - if (scope !== 'workspace' && scope !== 'workflow') { - return { success: false, message: 'touch_plan scope must be "workspace" or "workflow"' } - } - if (scope === 'workflow' && !workflowPath) { - return { - success: false, - message: 'touch_plan with workflow scope requires workflowPath and name', - } - } - - const planRelativePath = normalizePlanRelativePath(name) - const aliasPath = - scope === 'workspace' - ? `.plans/${planRelativePath}` - : `${normalizeWorkflowPath(workflowPath)}/.plans/${planRelativePath}` - const alias = await resolveWorkflowAliasForWorkspace({ workspaceId, path: aliasPath }) - if (!alias || alias.kind !== 'plan_file') { - return { - success: false, - message: - scope === 'workflow' - ? `Workflow not found for plan path: ${aliasPath}` - : `Unsupported workspace plan path: ${aliasPath}`, - } - } - - assertServerToolNotAborted(context) - const result = await writeWorkspaceFileByPath({ - workspaceId, - userId: context.userId, - target: { - path: aliasPath, - mode: 'create', - mimeType: 'text/markdown', - }, - buffer: Buffer.from('', 'utf-8'), - inferredMimeType: 'text/markdown', - }) - - logger.info('Workflow plan touched via copilot', { - workspaceId, - workflowId: alias.scope === 'workflow' ? alias.workflowId : undefined, - scope: alias.scope, - vfsPath: result.vfsPath, - backingVfsPath: result.backingVfsPath, - userId: context.userId, - }) - - return { - success: true, - message: `${alias.scope === 'workspace' ? 'Workspace' : 'Workflow'} plan "${result.vfsPath}" created successfully`, - data: { - id: result.id, - name: result.name, - vfsPath: result.vfsPath, - backingVfsPath: result.backingVfsPath, - scope: alias.scope, - workflowId: alias.scope === 'workflow' ? alias.workflowId : undefined, - }, - } - }, -} diff --git a/apps/sim/lib/copilot/tools/server/router.ts b/apps/sim/lib/copilot/tools/server/router.ts index 27462e91285..c62116d7f47 100644 --- a/apps/sim/lib/copilot/tools/server/router.ts +++ b/apps/sim/lib/copilot/tools/server/router.ts @@ -19,7 +19,6 @@ import { MoveFileFolder, RenameFile, RenameFileFolder, - TouchPlan, UserTable, WorkspaceFile, } from '@/lib/copilot/generated/tool-catalog-v1' @@ -45,7 +44,6 @@ import { renameFileFolderServerTool, } from '@/lib/copilot/tools/server/files/file-folders' import { renameFileServerTool } from '@/lib/copilot/tools/server/files/rename-file' -import { touchPlanServerTool } from '@/lib/copilot/tools/server/files/touch-plan' import { workspaceFileServerTool } from '@/lib/copilot/tools/server/files/workspace-file' import { validateGeneratedToolPayload } from '@/lib/copilot/tools/server/generated-schema' import { generateImageServerTool } from '@/lib/copilot/tools/server/image/generate-image' @@ -60,7 +58,6 @@ import { getCredentialsServerTool } from '@/lib/copilot/tools/server/user/get-cr import { setEnvironmentVariablesServerTool } from '@/lib/copilot/tools/server/user/set-environment-variables' import { editWorkflowServerTool } from '@/lib/copilot/tools/server/workflow/edit-workflow' import { queryLogsServerTool } from '@/lib/copilot/tools/server/workflow/query-logs' -import { isMothershipBetaFeaturesEnabled } from '@/lib/core/config/feature-flags' export type ExecuteResponseSuccess = z.output @@ -113,7 +110,6 @@ const WRITE_ACTIONS: Record = { [WorkspaceFile.id]: ['create', 'append', 'update', 'delete', 'rename', 'patch'], [editContentServerTool.name]: ['*'], [CreateFile.id]: ['*'], - [TouchPlan.id]: ['*'], [RenameFile.id]: ['*'], [DeleteFile.id]: ['*'], [MoveFile.id]: ['*'], @@ -157,7 +153,6 @@ const baseServerToolRegistry: Record = { [workspaceFileServerTool.name]: workspaceFileServerTool, [editContentServerTool.name]: editContentServerTool, [createFileServerTool.name]: createFileServerTool, - [touchPlanServerTool.name]: touchPlanServerTool, [renameFileServerTool.name]: renameFileServerTool, [deleteFileServerTool.name]: deleteFileServerTool, [moveFileServerTool.name]: moveFileServerTool, @@ -174,12 +169,7 @@ const baseServerToolRegistry: Record = { } function getServerToolRegistry(): Record { - if (isMothershipBetaFeaturesEnabled) { - return baseServerToolRegistry - } - const registry = { ...baseServerToolRegistry } - delete registry[touchPlanServerTool.name] - return registry + return baseServerToolRegistry } export function getRegisteredServerToolNames(): string[] { diff --git a/apps/sim/lib/copilot/vfs/resource-writer.ts b/apps/sim/lib/copilot/vfs/resource-writer.ts index 476c9186c83..460f6ba36dd 100644 --- a/apps/sim/lib/copilot/vfs/resource-writer.ts +++ b/apps/sim/lib/copilot/vfs/resource-writer.ts @@ -207,9 +207,7 @@ async function resolveWorkflowAliasFileTarget(args: { includeReservedSystemFolders: true, }) if (!folderId) { - throw new Error( - `Plan backing directory is not provisioned for ${args.alias.aliasPath}. Create the plan with touch_plan first.` - ) + throw new Error(`Plan backing directory is not provisioned for ${args.alias.aliasPath}.`) } return { From 65c49e700ac83239975a5e30b9aa421e181b79e7 Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Sun, 14 Jun 2026 22:55:40 -0700 Subject: [PATCH 3/6] chore(mothership): trigger dev redeploy From 8702ade2008586006dae7174a0f3ae359a3c16cf Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Sun, 14 Jun 2026 23:00:32 -0700 Subject: [PATCH 4/6] improvement(mothership): log billed cost on enrichment_run lookups --- apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts b/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts index 8c1e3f3ea51..5acc5b04551 100644 --- a/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts +++ b/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts @@ -48,7 +48,7 @@ export const enrichmentRunServerTool: BaseServerTool 0 - logger.info('Enrichment run', { enrichmentId, matched, provider }) + logger.info('Enrichment run', { enrichmentId, matched, provider, cost }) // A genuine "no match" returns normally (matched: false). Only surface an // error when every provider that ran failed (infra/auth/rate-limit). From 365825b2a2ad618cea9d7e44b508bf1f9f966024 Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Mon, 15 Jun 2026 10:47:21 -0700 Subject: [PATCH 5/6] fix(contracts): regenerate mship contracts --- .../lib/copilot/generated/tool-catalog-v1.ts | 3 +- .../lib/copilot/generated/tool-schemas-v1.ts | 3 +- package.json | 2 - scripts/generate-mship-contracts.ts | 1 - scripts/sync-request-trace-contract.ts | 77 ------------------- 5 files changed, 4 insertions(+), 82 deletions(-) delete mode 100644 scripts/sync-request-trace-contract.ts diff --git a/apps/sim/lib/copilot/generated/tool-catalog-v1.ts b/apps/sim/lib/copilot/generated/tool-catalog-v1.ts index a6b42aba811..0ab4a73d2a4 100644 --- a/apps/sim/lib/copilot/generated/tool-catalog-v1.ts +++ b/apps/sim/lib/copilot/generated/tool-catalog-v1.ts @@ -1110,7 +1110,8 @@ export const EnrichmentRun: ToolCatalogEntry = { }, provider: { type: 'string', - description: 'Label of the provider that produced the result, or null on no match.', + description: + 'Internal label of the provider that produced the result (billing/diagnostics only — do NOT surface it to the user), or null on no match.', }, result: { type: 'object', diff --git a/apps/sim/lib/copilot/generated/tool-schemas-v1.ts b/apps/sim/lib/copilot/generated/tool-schemas-v1.ts index 77888ddef2c..a93837798b1 100644 --- a/apps/sim/lib/copilot/generated/tool-schemas-v1.ts +++ b/apps/sim/lib/copilot/generated/tool-schemas-v1.ts @@ -900,7 +900,8 @@ export const TOOL_RUNTIME_SCHEMAS: Record = { }, provider: { type: 'string', - description: 'Label of the provider that produced the result, or null on no match.', + description: + 'Internal label of the provider that produced the result (billing/diagnostics only — do NOT surface it to the user), or null on no match.', }, result: { type: 'object', diff --git a/package.json b/package.json index 0dcaf676f30..ca2060fe57b 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,6 @@ "mship-contracts:check": "bun run scripts/sync-mothership-stream-contract.ts --check", "mship-tools:generate": "bun run scripts/sync-tool-catalog.ts", "mship-tools:check": "bun run scripts/sync-tool-catalog.ts --check", - "trace-contracts:generate": "bun run scripts/sync-request-trace-contract.ts", - "trace-contracts:check": "bun run scripts/sync-request-trace-contract.ts --check", "trace-spans-contract:generate": "bun run scripts/sync-trace-spans-contract.ts", "trace-spans-contract:check": "bun run scripts/sync-trace-spans-contract.ts --check", "trace-attributes-contract:generate": "bun run scripts/sync-trace-attributes-contract.ts", diff --git a/scripts/generate-mship-contracts.ts b/scripts/generate-mship-contracts.ts index 40526b39fc7..7509216598a 100644 --- a/scripts/generate-mship-contracts.ts +++ b/scripts/generate-mship-contracts.ts @@ -19,7 +19,6 @@ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..') const GENERATORS = [ 'scripts/sync-mothership-stream-contract.ts', 'scripts/sync-tool-catalog.ts', - 'scripts/sync-request-trace-contract.ts', 'scripts/sync-trace-spans-contract.ts', 'scripts/sync-trace-attributes-contract.ts', 'scripts/sync-trace-attribute-values-contract.ts', diff --git a/scripts/sync-request-trace-contract.ts b/scripts/sync-request-trace-contract.ts deleted file mode 100644 index 4813ed41527..00000000000 --- a/scripts/sync-request-trace-contract.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { mkdir, readFile, writeFile } from 'node:fs/promises' -import { dirname, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' -import { compile } from 'json-schema-to-typescript' -import { formatGeneratedSource } from './format-generated-source' - -const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)) -const ROOT = resolve(SCRIPT_DIR, '..') -const DEFAULT_CONTRACT_PATH = resolve( - ROOT, - '../copilot/copilot/contracts/request-trace-v1.schema.json' -) -const OUTPUT_PATH = resolve(ROOT, 'apps/sim/lib/copilot/generated/request-trace-v1.ts') - -function generateRuntimeConstants(schema: Record): string { - const defs = (schema.$defs ?? schema.definitions ?? {}) as Record - const lines: string[] = [] - - for (const [name, def] of Object.entries(defs)) { - if (!def || typeof def !== 'object') continue - const defObj = def as Record - const enumValues = defObj.enum - if (!Array.isArray(enumValues) || enumValues.length === 0) continue - if (!enumValues.every((v) => typeof v === 'string')) continue - - const entries = (enumValues as string[]) - .map((v) => ` ${JSON.stringify(v)}: ${JSON.stringify(v)}`) - .join(',\n') - - lines.push(`export const ${name} = {\n${entries},\n} as const;\n`) - } - - return lines.join('\n') -} - -async function main() { - const checkOnly = process.argv.includes('--check') - const inputPathArg = process.argv.find((arg) => arg.startsWith('--input=')) - const inputPath = inputPathArg - ? resolve(ROOT, inputPathArg.slice('--input='.length)) - : DEFAULT_CONTRACT_PATH - - const raw = await readFile(inputPath, 'utf8') - const schema = JSON.parse(raw) - const types = await compile(schema, 'RequestTraceV1SimReport', { - bannerComment: '// AUTO-GENERATED FILE. DO NOT EDIT.\n//', - unreachableDefinitions: true, - additionalProperties: false, - }) - - const constants = generateRuntimeConstants(schema) - const rendered = formatGeneratedSource( - constants ? `${types}\n${constants}\n` : types, - OUTPUT_PATH, - ROOT - ) - - if (checkOnly) { - const existing = await readFile(OUTPUT_PATH, 'utf8').catch(() => null) - if (existing !== rendered) { - throw new Error( - `Generated request trace contract is stale. Run: bun run trace-contracts:generate` - ) - } - console.log('Request trace contract is up to date.') - return - } - - await mkdir(dirname(OUTPUT_PATH), { recursive: true }) - await writeFile(OUTPUT_PATH, rendered, 'utf8') - console.log(`Generated request trace types -> ${OUTPUT_PATH}`) -} - -main().catch((err) => { - console.error(err) - process.exit(1) -}) From af0e48f043b0005586ac15ca8b6e7ce866ae4ceb Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Mon, 15 Jun 2026 10:50:19 -0700 Subject: [PATCH 6/6] fix(contracts): fix mship contracts --- apps/sim/lib/copilot/generated/tool-catalog-v1.ts | 1 + apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts | 2 +- apps/sim/lib/copilot/tools/server/router.ts | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/sim/lib/copilot/generated/tool-catalog-v1.ts b/apps/sim/lib/copilot/generated/tool-catalog-v1.ts index 0ab4a73d2a4..87178f69903 100644 --- a/apps/sim/lib/copilot/generated/tool-catalog-v1.ts +++ b/apps/sim/lib/copilot/generated/tool-catalog-v1.ts @@ -1120,6 +1120,7 @@ export const EnrichmentRun: ToolCatalogEntry = { }, required: ['matched', 'result'], }, + requiredPermission: 'write', } export const Ffmpeg: ToolCatalogEntry = { diff --git a/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts b/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts index 5acc5b04551..bde0e4873b5 100644 --- a/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts +++ b/apps/sim/lib/copilot/tools/server/enrichment/enrichment-run.ts @@ -6,7 +6,7 @@ import { runEnrichment } from '@/enrichments/run' interface EnrichmentRunParams { enrichmentId: string - inputs?: Record + inputs: Record } interface EnrichmentRunResult { diff --git a/apps/sim/lib/copilot/tools/server/router.ts b/apps/sim/lib/copilot/tools/server/router.ts index c62116d7f47..7780f97eb73 100644 --- a/apps/sim/lib/copilot/tools/server/router.ts +++ b/apps/sim/lib/copilot/tools/server/router.ts @@ -122,6 +122,8 @@ const WRITE_ACTIONS: Record = { [GenerateVideo.id]: ['generate'], [GenerateAudio.id]: ['generate'], [Ffmpeg.id]: ['*'], + // Paid external-provider lookups (hosted-key cost), like the media tools. + [enrichmentRunServerTool.name]: ['*'], } function isWritePermission(userPermission: string): boolean {