mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(socket): sync deploy button state across collaborators (#4206)
* fix(socket): sync deploy button state across collaborators Broadcast workflow-deployed events via socket so all connected users invalidate their deployment query cache when any user deploys, undeploys, activates a version, or triggers a deploy through chat/form endpoints. * fix(socket): check response status on deployment notification Log a warning when the socket server returns a non-2xx status for deployment notifications, matching the pattern in lifecycle.ts. * improvement(config): consolidate socket server URL into getSocketServerUrl/getSocketUrl Replace all inline `env.SOCKET_SERVER_URL || 'http://localhost:3002'` and `getEnv('NEXT_PUBLIC_SOCKET_URL') || 'http://localhost:3002'` with centralized utility functions in urls.ts, matching the getBaseUrl() pattern. * improvement(config): consolidate Ollama URL and CSP socket/Ollama hardcodes Add getOllamaUrl() to urls.ts and replace inline env.OLLAMA_URL fallbacks in the provider and API route. Update CSP to use getSocketUrl(), getOllamaUrl(), and a local toWebSocketUrl() helper instead of hardcoded localhost strings. * lint * fix(tests): add missing mocks for new URL utility exports Update lifecycle, async execute, and chat manage test mocks to include getSocketServerUrl, getOllamaUrl, and notifySocketDeploymentChanged. * fix(csp): remove urls.ts import to fix next.config.ts build CSP is loaded by next.config.ts which transpiles outside the @/ alias context. Use local constants instead of importing from urls.ts. * fix(queries): invalidate chat and form status on deployment change Add chatStatus and formStatus to invalidateDeploymentQueries so all deployment-related queries refresh when any user deploys or undeploys.
This commit is contained in:
@@ -89,6 +89,7 @@ vi.mock('@/lib/workflows/persistence/utils', () => ({
|
||||
}))
|
||||
vi.mock('@/lib/workflows/orchestration', () => ({
|
||||
performChatUndeploy: mockPerformChatUndeploy,
|
||||
notifySocketDeploymentChanged: vi.fn().mockResolvedValue(undefined),
|
||||
}))
|
||||
vi.mock('drizzle-orm', () => ({
|
||||
and: vi.fn((...conditions: unknown[]) => ({ type: 'and', conditions })),
|
||||
|
||||
@@ -9,7 +9,7 @@ import { getSession } from '@/lib/auth'
|
||||
import { isDev } from '@/lib/core/config/feature-flags'
|
||||
import { encryptSecret } from '@/lib/core/security/encryption'
|
||||
import { getEmailDomain } from '@/lib/core/utils/urls'
|
||||
import { performChatUndeploy } from '@/lib/workflows/orchestration'
|
||||
import { notifySocketDeploymentChanged, performChatUndeploy } from '@/lib/workflows/orchestration'
|
||||
import { deployWorkflow } from '@/lib/workflows/persistence/utils'
|
||||
import { checkChatAccess } from '@/app/api/chat/utils'
|
||||
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
|
||||
@@ -155,6 +155,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
||||
logger.info(
|
||||
`Redeployed workflow ${existingChat[0].workflowId} for chat update (v${deployResult.version})`
|
||||
)
|
||||
await notifySocketDeploymentChanged(existingChat[0].workflowId)
|
||||
}
|
||||
|
||||
let encryptedPassword
|
||||
|
||||
@@ -10,6 +10,7 @@ import { isDev } from '@/lib/core/config/feature-flags'
|
||||
import { encryptSecret } from '@/lib/core/security/encryption'
|
||||
import { getEmailDomain } from '@/lib/core/utils/urls'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { notifySocketDeploymentChanged } from '@/lib/workflows/orchestration'
|
||||
import { deployWorkflow } from '@/lib/workflows/persistence/utils'
|
||||
import {
|
||||
checkWorkflowAccessForFormCreation,
|
||||
@@ -152,6 +153,8 @@ export async function POST(request: NextRequest) {
|
||||
`${workflowRecord.isDeployed ? 'Redeployed' : 'Auto-deployed'} workflow ${workflowId} for form (v${result.version})`
|
||||
)
|
||||
|
||||
await notifySocketDeploymentChanged(workflowId)
|
||||
|
||||
let encryptedPassword = null
|
||||
if (authType === 'password' && password) {
|
||||
const { encrypted } = await encryptSecret(password)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { getOllamaUrl } from '@/lib/core/utils/urls'
|
||||
import type { ModelsObject } from '@/providers/ollama/types'
|
||||
import { filterBlacklistedModels, isProviderBlacklisted } from '@/providers/utils'
|
||||
|
||||
const logger = createLogger('OllamaModelsAPI')
|
||||
const OLLAMA_HOST = env.OLLAMA_URL || 'http://localhost:11434'
|
||||
const OLLAMA_HOST = getOllamaUrl()
|
||||
|
||||
/**
|
||||
* Get available Ollama models
|
||||
|
||||
@@ -53,6 +53,7 @@ vi.mock('@/lib/core/utils/request', () => ({
|
||||
|
||||
vi.mock('@/lib/core/utils/urls', () => ({
|
||||
getBaseUrl: vi.fn().mockReturnValue('http://localhost:3000'),
|
||||
getOllamaUrl: vi.fn().mockReturnValue('http://localhost:11434'),
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/execution/call-chain', () => ({
|
||||
|
||||
@@ -7,6 +7,7 @@ import { z } from 'zod'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { getSocketServerUrl } from '@/lib/core/utils/urls'
|
||||
import { extractAndPersistCustomTools } from '@/lib/workflows/persistence/custom-tools-persistence'
|
||||
import {
|
||||
loadWorkflowFromNormalizedTables,
|
||||
@@ -305,8 +306,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
|
||||
logger.info(`[${requestId}] Successfully saved workflow ${workflowId} state in ${elapsed}ms`)
|
||||
|
||||
try {
|
||||
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||
const notifyResponse = await fetch(`${socketUrl}/api/workflow-updated`, {
|
||||
const notifyResponse = await fetch(`${getSocketServerUrl()}/api/workflow-updated`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { useParams } from 'next/navigation'
|
||||
import type { Socket } from 'socket.io-client'
|
||||
import { getEnv } from '@/lib/core/config/env'
|
||||
import { getSocketUrl } from '@/lib/core/utils/urls'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import {
|
||||
type SocketJoinCommand,
|
||||
@@ -102,6 +102,7 @@ interface SocketContextType {
|
||||
onWorkflowDeleted: (handler: (data: any) => void) => void
|
||||
onWorkflowReverted: (handler: (data: any) => void) => void
|
||||
onWorkflowUpdated: (handler: (data: any) => void) => void
|
||||
onWorkflowDeployed: (handler: (data: any) => void) => void
|
||||
onOperationConfirmed: (handler: (data: any) => void) => void
|
||||
onOperationFailed: (handler: (data: any) => void) => void
|
||||
}
|
||||
@@ -132,6 +133,7 @@ const SocketContext = createContext<SocketContextType>({
|
||||
onWorkflowDeleted: () => {},
|
||||
onWorkflowReverted: () => {},
|
||||
onWorkflowUpdated: () => {},
|
||||
onWorkflowDeployed: () => {},
|
||||
onOperationConfirmed: () => {},
|
||||
onOperationFailed: () => {},
|
||||
})
|
||||
@@ -176,6 +178,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
||||
workflowDeleted?: (data: any) => void
|
||||
workflowReverted?: (data: any) => void
|
||||
workflowUpdated?: (data: any) => void
|
||||
workflowDeployed?: (data: any) => void
|
||||
operationConfirmed?: (data: any) => void
|
||||
operationFailed?: (data: any) => void
|
||||
}>({})
|
||||
@@ -337,7 +340,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
||||
const initializeSocket = async () => {
|
||||
try {
|
||||
const { io } = await import('socket.io-client')
|
||||
const socketUrl = getEnv('NEXT_PUBLIC_SOCKET_URL') || 'http://localhost:3002'
|
||||
const socketUrl = getSocketUrl()
|
||||
|
||||
logger.info('Attempting to connect to Socket.IO server', {
|
||||
url: socketUrl,
|
||||
@@ -550,6 +553,11 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
||||
eventHandlers.current.workflowUpdated?.(data)
|
||||
})
|
||||
|
||||
socketInstance.on('workflow-deployed', (data) => {
|
||||
logger.info(`Workflow ${data.workflowId} deployment state changed`)
|
||||
eventHandlers.current.workflowDeployed?.(data)
|
||||
})
|
||||
|
||||
const rehydrateWorkflowStores = async (workflowId: string, workflowState: any) => {
|
||||
const [
|
||||
{ useOperationQueueStore },
|
||||
@@ -994,6 +1002,10 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
||||
eventHandlers.current.workflowUpdated = handler
|
||||
}, [])
|
||||
|
||||
const onWorkflowDeployed = useCallback((handler: (data: any) => void) => {
|
||||
eventHandlers.current.workflowDeployed = handler
|
||||
}, [])
|
||||
|
||||
const onOperationConfirmed = useCallback((handler: (data: any) => void) => {
|
||||
eventHandlers.current.operationConfirmed = handler
|
||||
}, [])
|
||||
@@ -1029,6 +1041,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
||||
onWorkflowDeleted,
|
||||
onWorkflowReverted,
|
||||
onWorkflowUpdated,
|
||||
onWorkflowDeployed,
|
||||
onOperationConfirmed,
|
||||
onOperationFailed,
|
||||
}),
|
||||
@@ -1058,6 +1071,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
||||
onWorkflowDeleted,
|
||||
onWorkflowReverted,
|
||||
onWorkflowUpdated,
|
||||
onWorkflowDeployed,
|
||||
onOperationConfirmed,
|
||||
onOperationFailed,
|
||||
]
|
||||
|
||||
@@ -42,6 +42,8 @@ export function invalidateDeploymentQueries(queryClient: QueryClient, workflowId
|
||||
queryClient.invalidateQueries({ queryKey: deploymentKeys.info(workflowId) }),
|
||||
queryClient.invalidateQueries({ queryKey: deploymentKeys.deployedState(workflowId) }),
|
||||
queryClient.invalidateQueries({ queryKey: deploymentKeys.versions(workflowId) }),
|
||||
queryClient.invalidateQueries({ queryKey: deploymentKeys.chatStatus(workflowId) }),
|
||||
queryClient.invalidateQueries({ queryKey: deploymentKeys.formStatus(workflowId) }),
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import type { Edge } from 'reactflow'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { useSession } from '@/lib/auth/auth-client'
|
||||
@@ -7,6 +8,7 @@ import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { useSocket } from '@/app/workspace/providers/socket-provider'
|
||||
import { getBlock } from '@/blocks'
|
||||
import { normalizeName, RESERVED_BLOCK_NAMES } from '@/executor/constants'
|
||||
import { invalidateDeploymentQueries } from '@/hooks/queries/deployments'
|
||||
import { useUndoRedo } from '@/hooks/use-undo-redo'
|
||||
import {
|
||||
BLOCK_OPERATIONS,
|
||||
@@ -34,6 +36,7 @@ import { findAllDescendantNodes, isBlockProtected } from '@/stores/workflows/wor
|
||||
const logger = createLogger('CollaborativeWorkflow')
|
||||
|
||||
export function useCollaborativeWorkflow() {
|
||||
const queryClient = useQueryClient()
|
||||
const undoRedo = useUndoRedo()
|
||||
const isUndoRedoInProgress = useRef(false)
|
||||
const lastDiffOperationId = useRef<string | null>(null)
|
||||
@@ -125,6 +128,7 @@ export function useCollaborativeWorkflow() {
|
||||
onWorkflowDeleted,
|
||||
onWorkflowReverted,
|
||||
onWorkflowUpdated,
|
||||
onWorkflowDeployed,
|
||||
onOperationConfirmed,
|
||||
onOperationFailed,
|
||||
} = useSocket()
|
||||
@@ -645,6 +649,15 @@ export function useCollaborativeWorkflow() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleWorkflowDeployed = (data: any) => {
|
||||
const { workflowId } = data
|
||||
logger.info(`Workflow ${workflowId} deployment state changed`)
|
||||
|
||||
if (workflowId !== activeWorkflowId) return
|
||||
|
||||
invalidateDeploymentQueries(queryClient, workflowId)
|
||||
}
|
||||
|
||||
const handleOperationConfirmed = (data: any) => {
|
||||
const { operationId } = data
|
||||
logger.debug('Operation confirmed', { operationId })
|
||||
@@ -664,6 +677,7 @@ export function useCollaborativeWorkflow() {
|
||||
onWorkflowDeleted(handleWorkflowDeleted)
|
||||
onWorkflowReverted(handleWorkflowReverted)
|
||||
onWorkflowUpdated(handleWorkflowUpdated)
|
||||
onWorkflowDeployed(handleWorkflowDeployed)
|
||||
onOperationConfirmed(handleOperationConfirmed)
|
||||
onOperationFailed(handleOperationFailed)
|
||||
}, [
|
||||
@@ -673,9 +687,11 @@ export function useCollaborativeWorkflow() {
|
||||
onWorkflowDeleted,
|
||||
onWorkflowReverted,
|
||||
onWorkflowUpdated,
|
||||
onWorkflowDeployed,
|
||||
onOperationConfirmed,
|
||||
onOperationFailed,
|
||||
activeWorkflowId,
|
||||
queryClient,
|
||||
confirmOperation,
|
||||
failOperation,
|
||||
emitWorkflowOperation,
|
||||
|
||||
@@ -10,7 +10,7 @@ export interface ToolRuntimeSchemaEntry {
|
||||
}
|
||||
|
||||
export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
['agent']: {
|
||||
agent: {
|
||||
parameters: {
|
||||
properties: {
|
||||
request: {
|
||||
@@ -23,7 +23,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['auth']: {
|
||||
auth: {
|
||||
parameters: {
|
||||
properties: {
|
||||
request: {
|
||||
@@ -36,7 +36,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['check_deployment_status']: {
|
||||
check_deployment_status: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -48,7 +48,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['complete_job']: {
|
||||
complete_job: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -61,7 +61,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['context_write']: {
|
||||
context_write: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -78,7 +78,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['crawl_website']: {
|
||||
crawl_website: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -113,7 +113,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['create_file']: {
|
||||
create_file: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -149,7 +149,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
required: ['success', 'message'],
|
||||
},
|
||||
},
|
||||
['create_folder']: {
|
||||
create_folder: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -170,7 +170,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['create_job']: {
|
||||
create_job: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -220,7 +220,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['create_workflow']: {
|
||||
create_workflow: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -245,7 +245,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['create_workspace_mcp_server']: {
|
||||
create_workspace_mcp_server: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -266,7 +266,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['debug']: {
|
||||
debug: {
|
||||
parameters: {
|
||||
properties: {
|
||||
context: {
|
||||
@@ -285,7 +285,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['delete_file']: {
|
||||
delete_file: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -314,7 +314,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
required: ['success', 'message'],
|
||||
},
|
||||
},
|
||||
['delete_folder']: {
|
||||
delete_folder: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -330,7 +330,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['delete_workflow']: {
|
||||
delete_workflow: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -346,7 +346,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['delete_workspace_mcp_server']: {
|
||||
delete_workspace_mcp_server: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -359,7 +359,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['deploy']: {
|
||||
deploy: {
|
||||
parameters: {
|
||||
properties: {
|
||||
request: {
|
||||
@@ -373,7 +373,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['deploy_api']: {
|
||||
deploy_api: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -447,7 +447,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
],
|
||||
},
|
||||
},
|
||||
['deploy_chat']: {
|
||||
deploy_chat: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -595,7 +595,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
],
|
||||
},
|
||||
},
|
||||
['deploy_mcp']: {
|
||||
deploy_mcp: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -711,7 +711,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
required: ['deploymentType', 'deploymentStatus'],
|
||||
},
|
||||
},
|
||||
['download_to_workspace_file']: {
|
||||
download_to_workspace_file: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -730,7 +730,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['edit_content']: {
|
||||
edit_content: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -762,7 +762,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
required: ['success', 'message'],
|
||||
},
|
||||
},
|
||||
['edit_workflow']: {
|
||||
edit_workflow: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -801,13 +801,13 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['file']: {
|
||||
file: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['function_execute']: {
|
||||
function_execute: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -868,7 +868,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['generate_api_key']: {
|
||||
generate_api_key: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -886,7 +886,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['generate_image']: {
|
||||
generate_image: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -923,7 +923,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['generate_visualization']: {
|
||||
generate_visualization: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -963,7 +963,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_block_outputs']: {
|
||||
get_block_outputs: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -984,7 +984,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_block_upstream_references']: {
|
||||
get_block_upstream_references: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1006,7 +1006,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_deployed_workflow_state']: {
|
||||
get_deployed_workflow_state: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1019,7 +1019,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_deployment_version']: {
|
||||
get_deployment_version: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1036,7 +1036,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_execution_summary']: {
|
||||
get_execution_summary: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1063,7 +1063,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_job_logs']: {
|
||||
get_job_logs: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1088,7 +1088,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_page_contents']: {
|
||||
get_page_contents: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1116,14 +1116,14 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_platform_actions']: {
|
||||
get_platform_actions: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_workflow_data']: {
|
||||
get_workflow_data: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1142,7 +1142,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['get_workflow_logs']: {
|
||||
get_workflow_logs: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1168,7 +1168,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['glob']: {
|
||||
glob: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1187,7 +1187,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['grep']: {
|
||||
grep: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1234,7 +1234,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['job']: {
|
||||
job: {
|
||||
parameters: {
|
||||
properties: {
|
||||
request: {
|
||||
@@ -1247,7 +1247,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['knowledge']: {
|
||||
knowledge: {
|
||||
parameters: {
|
||||
properties: {
|
||||
request: {
|
||||
@@ -1260,7 +1260,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['knowledge_base']: {
|
||||
knowledge_base: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1452,7 +1452,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
required: ['success', 'message'],
|
||||
},
|
||||
},
|
||||
['list_folders']: {
|
||||
list_folders: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1464,14 +1464,14 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
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: {
|
||||
@@ -1483,7 +1483,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['manage_credential']: {
|
||||
manage_credential: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1512,7 +1512,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['manage_custom_tool']: {
|
||||
manage_custom_tool: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1591,7 +1591,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['manage_job']: {
|
||||
manage_job: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1661,7 +1661,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['manage_mcp_tool']: {
|
||||
manage_mcp_tool: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1712,7 +1712,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['manage_skill']: {
|
||||
manage_skill: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1744,7 +1744,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['materialize_file']: {
|
||||
materialize_file: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1778,7 +1778,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['move_folder']: {
|
||||
move_folder: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1796,7 +1796,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['move_workflow']: {
|
||||
move_workflow: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1816,7 +1816,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['oauth_get_auth_link']: {
|
||||
oauth_get_auth_link: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1830,7 +1830,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['oauth_request_access']: {
|
||||
oauth_request_access: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1844,7 +1844,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['open_resource']: {
|
||||
open_resource: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1872,7 +1872,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['read']: {
|
||||
read: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1899,7 +1899,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['redeploy']: {
|
||||
redeploy: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -1967,7 +1967,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
],
|
||||
},
|
||||
},
|
||||
['rename_file']: {
|
||||
rename_file: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2002,7 +2002,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
required: ['success', 'message'],
|
||||
},
|
||||
},
|
||||
['rename_workflow']: {
|
||||
rename_workflow: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2019,7 +2019,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['research']: {
|
||||
research: {
|
||||
parameters: {
|
||||
properties: {
|
||||
topic: {
|
||||
@@ -2032,7 +2032,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['respond']: {
|
||||
respond: {
|
||||
parameters: {
|
||||
additionalProperties: true,
|
||||
properties: {
|
||||
@@ -2055,7 +2055,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['restore_resource']: {
|
||||
restore_resource: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2073,7 +2073,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['revert_to_version']: {
|
||||
revert_to_version: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2090,7 +2090,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['run']: {
|
||||
run: {
|
||||
parameters: {
|
||||
properties: {
|
||||
context: {
|
||||
@@ -2107,7 +2107,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['run_block']: {
|
||||
run_block: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2139,7 +2139,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['run_from_block']: {
|
||||
run_from_block: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2171,7 +2171,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['run_workflow']: {
|
||||
run_workflow: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2199,7 +2199,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['run_workflow_until_block']: {
|
||||
run_workflow_until_block: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2231,7 +2231,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['scrape_page']: {
|
||||
scrape_page: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2252,7 +2252,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['search_documentation']: {
|
||||
search_documentation: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2269,7 +2269,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['search_library_docs']: {
|
||||
search_library_docs: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2290,7 +2290,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['search_online']: {
|
||||
search_online: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2331,7 +2331,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['search_patterns']: {
|
||||
search_patterns: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2353,7 +2353,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['set_block_enabled']: {
|
||||
set_block_enabled: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2375,7 +2375,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['set_environment_variables']: {
|
||||
set_environment_variables: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2409,7 +2409,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['set_global_workflow_variables']: {
|
||||
set_global_workflow_variables: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2447,7 +2447,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['superagent']: {
|
||||
superagent: {
|
||||
parameters: {
|
||||
properties: {
|
||||
task: {
|
||||
@@ -2461,7 +2461,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['table']: {
|
||||
table: {
|
||||
parameters: {
|
||||
properties: {
|
||||
request: {
|
||||
@@ -2474,7 +2474,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['tool_search_tool_regex']: {
|
||||
tool_search_tool_regex: {
|
||||
parameters: {
|
||||
properties: {
|
||||
case_insensitive: {
|
||||
@@ -2495,7 +2495,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['update_job_history']: {
|
||||
update_job_history: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2513,7 +2513,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['update_workspace_mcp_server']: {
|
||||
update_workspace_mcp_server: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2538,7 +2538,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['user_memory']: {
|
||||
user_memory: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2586,7 +2586,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['user_table']: {
|
||||
user_table: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -2777,13 +2777,13 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
|
||||
required: ['success', 'message'],
|
||||
},
|
||||
},
|
||||
['workflow']: {
|
||||
workflow: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
},
|
||||
resultSchema: undefined,
|
||||
},
|
||||
['workspace_file']: {
|
||||
workspace_file: {
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
|
||||
import type { ExecutionContext, ToolCallResult } from '@/lib/copilot/request/types'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { getSocketServerUrl } from '@/lib/core/utils/urls'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { executeWorkflow } from '@/lib/workflows/executor/execute-workflow'
|
||||
import {
|
||||
@@ -147,8 +148,7 @@ function findDescendants(containerId: string, blocksById: Record<string, BlockSt
|
||||
}
|
||||
|
||||
function notifyWorkflowUpdated(workflowId: string): void {
|
||||
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||
fetch(`${socketUrl}/api/workflow-updated`, {
|
||||
fetch(`${getSocketServerUrl()}/api/workflow-updated`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
type ServerToolContext,
|
||||
} from '@/lib/copilot/tools/server/base-tool'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { getSocketServerUrl } from '@/lib/core/utils/urls'
|
||||
import {
|
||||
applyTargetedLayout,
|
||||
getTargetedLayoutImpact,
|
||||
@@ -284,8 +285,7 @@ export const editWorkflowServerTool: BaseServerTool<EditWorkflowParams, unknown>
|
||||
|
||||
logger.info('Workflow state persisted to database', { workflowId })
|
||||
|
||||
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||
fetch(`${socketUrl}/api/workflow-updated`, {
|
||||
fetch(`${getSocketServerUrl()}/api/workflow-updated`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -3,8 +3,19 @@ import { isDev, isHosted, isReactGrabEnabled } from '../config/feature-flags'
|
||||
|
||||
/**
|
||||
* Content Security Policy (CSP) configuration builder
|
||||
*
|
||||
* NOTE: This file is loaded by next.config.ts at build time, before @/ path
|
||||
* aliases are resolved. Do NOT import from ../utils/urls (which uses @/ imports).
|
||||
* Keep all URL constants local to this file.
|
||||
*/
|
||||
|
||||
const DEFAULT_SOCKET_URL = 'http://localhost:3002'
|
||||
const DEFAULT_OLLAMA_URL = 'http://localhost:11434'
|
||||
|
||||
function toWebSocketUrl(httpUrl: string): string {
|
||||
return httpUrl.replace('http://', 'ws://').replace('https://', 'wss://')
|
||||
}
|
||||
|
||||
function getHostnameFromUrl(url: string | undefined): string[] {
|
||||
if (!url) return []
|
||||
try {
|
||||
@@ -156,14 +167,11 @@ export const buildTimeCSPDirectives: CSPDirectives = {
|
||||
'connect-src': [
|
||||
...STATIC_CONNECT_SRC,
|
||||
env.NEXT_PUBLIC_APP_URL || '',
|
||||
...(env.OLLAMA_URL ? [env.OLLAMA_URL] : isDev ? ['http://localhost:11434'] : []),
|
||||
...(env.OLLAMA_URL ? [env.OLLAMA_URL] : isDev ? [DEFAULT_OLLAMA_URL] : []),
|
||||
...(env.NEXT_PUBLIC_SOCKET_URL
|
||||
? [
|
||||
env.NEXT_PUBLIC_SOCKET_URL,
|
||||
env.NEXT_PUBLIC_SOCKET_URL.replace('http://', 'ws://').replace('https://', 'wss://'),
|
||||
]
|
||||
? [env.NEXT_PUBLIC_SOCKET_URL, toWebSocketUrl(env.NEXT_PUBLIC_SOCKET_URL)]
|
||||
: isDev
|
||||
? ['http://localhost:3002', 'ws://localhost:3002']
|
||||
? [DEFAULT_SOCKET_URL, toWebSocketUrl(DEFAULT_SOCKET_URL)]
|
||||
: []),
|
||||
...getHostnameFromUrl(env.NEXT_PUBLIC_BRAND_LOGO_URL),
|
||||
...getHostnameFromUrl(env.NEXT_PUBLIC_PRIVACY_URL),
|
||||
@@ -201,13 +209,9 @@ export function buildCSPString(directives: CSPDirectives): string {
|
||||
export function generateRuntimeCSP(): string {
|
||||
const appUrl = getEnv('NEXT_PUBLIC_APP_URL') || ''
|
||||
|
||||
const socketUrl = getEnv('NEXT_PUBLIC_SOCKET_URL') || (isDev ? 'http://localhost:3002' : '')
|
||||
const socketWsUrl = socketUrl
|
||||
? socketUrl.replace('http://', 'ws://').replace('https://', 'wss://')
|
||||
: isDev
|
||||
? 'ws://localhost:3002'
|
||||
: ''
|
||||
const ollamaUrl = getEnv('OLLAMA_URL') || (isDev ? 'http://localhost:11434' : '')
|
||||
const socketUrl = getEnv('NEXT_PUBLIC_SOCKET_URL') || (isDev ? DEFAULT_SOCKET_URL : '')
|
||||
const socketWsUrl = socketUrl ? toWebSocketUrl(socketUrl) : ''
|
||||
const ollamaUrl = getEnv('OLLAMA_URL') || (isDev ? DEFAULT_OLLAMA_URL : '')
|
||||
|
||||
const brandLogoDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_BRAND_LOGO_URL'))
|
||||
const brandFaviconDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_BRAND_FAVICON_URL'))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getEnv } from '@/lib/core/config/env'
|
||||
import { env, getEnv } from '@/lib/core/config/env'
|
||||
import { isProd } from '@/lib/core/config/feature-flags'
|
||||
|
||||
/** Canonical base URL for the public-facing marketing site. No trailing slash. */
|
||||
@@ -100,3 +100,30 @@ export function getEmailDomain(): string {
|
||||
return isProd ? 'sim.ai' : 'localhost:3000'
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_SOCKET_URL = 'http://localhost:3002'
|
||||
const DEFAULT_OLLAMA_URL = 'http://localhost:11434'
|
||||
|
||||
/**
|
||||
* Returns the socket server URL for server-side internal API calls.
|
||||
* Reads from SOCKET_SERVER_URL with a localhost fallback for development.
|
||||
*/
|
||||
export function getSocketServerUrl(): string {
|
||||
return env.SOCKET_SERVER_URL || DEFAULT_SOCKET_URL
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the socket server URL for client-side Socket.IO connections.
|
||||
* Reads from NEXT_PUBLIC_SOCKET_URL with a localhost fallback for development.
|
||||
*/
|
||||
export function getSocketUrl(): string {
|
||||
return getEnv('NEXT_PUBLIC_SOCKET_URL') || DEFAULT_SOCKET_URL
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Ollama server URL.
|
||||
* Reads from OLLAMA_URL with a localhost fallback for development.
|
||||
*/
|
||||
export function getOllamaUrl(): string {
|
||||
return env.OLLAMA_URL || DEFAULT_OLLAMA_URL
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ vi.mock('@/lib/core/config/env', () => ({
|
||||
SOCKET_SERVER_URL: 'http://socket.test',
|
||||
INTERNAL_API_SECRET: 'secret',
|
||||
},
|
||||
getEnv: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/core/utils/urls', () => ({
|
||||
getSocketServerUrl: vi.fn().mockReturnValue('http://socket.test'),
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/core/telemetry', () => ({
|
||||
|
||||
@@ -18,6 +18,7 @@ import { env } from '@/lib/core/config/env'
|
||||
import { getRedisClient } from '@/lib/core/config/redis'
|
||||
import { PlatformEvents } from '@/lib/core/telemetry'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { getSocketServerUrl } from '@/lib/core/utils/urls'
|
||||
import { mcpPubSub } from '@/lib/mcp/pubsub'
|
||||
import { getWorkflowById } from '@/lib/workflows/utils'
|
||||
|
||||
@@ -31,8 +32,7 @@ interface ArchiveWorkflowOptions {
|
||||
|
||||
async function notifyWorkflowArchived(workflowId: string, requestId: string): Promise<void> {
|
||||
try {
|
||||
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||
const socketResponse = await fetch(`${socketUrl}/api/workflow-deleted`, {
|
||||
const socketResponse = await fetch(`${getSocketServerUrl()}/api/workflow-deleted`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -5,7 +5,7 @@ import { NextRequest } from 'next/server'
|
||||
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { getBaseUrl } from '@/lib/core/utils/urls'
|
||||
import { getBaseUrl, getSocketServerUrl } from '@/lib/core/utils/urls'
|
||||
import { removeMcpToolsForWorkflow, syncMcpToolsForWorkflow } from '@/lib/mcp/workflow-mcp-sync'
|
||||
import { captureServerEvent } from '@/lib/posthog/server'
|
||||
import {
|
||||
@@ -31,6 +31,30 @@ import type { WorkflowState } from '@/stores/workflows/workflow/types'
|
||||
|
||||
const logger = createLogger('DeployOrchestration')
|
||||
|
||||
/**
|
||||
* Notifies the socket server that a workflow's deployment state has changed,
|
||||
* so all connected clients can refresh their deployment queries.
|
||||
*/
|
||||
export async function notifySocketDeploymentChanged(workflowId: string): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(`${getSocketServerUrl()}/api/workflow-deployed`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': env.INTERNAL_API_SECRET,
|
||||
},
|
||||
body: JSON.stringify({ workflowId }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
logger.warn(
|
||||
`Socket deployment notification failed (${response.status}) for workflow ${workflowId}`
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error sending workflow deployed event to socket server', error)
|
||||
}
|
||||
}
|
||||
|
||||
export interface PerformFullDeployParams {
|
||||
workflowId: string
|
||||
userId: string
|
||||
@@ -222,6 +246,8 @@ export async function performFullDeploy(
|
||||
request,
|
||||
})
|
||||
|
||||
await notifySocketDeploymentChanged(workflowId)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
deployedAt,
|
||||
@@ -296,6 +322,8 @@ export async function performFullUndeploy(
|
||||
description: `Undeployed workflow "${(workflowData.name as string) || workflowId}"`,
|
||||
})
|
||||
|
||||
await notifySocketDeploymentChanged(workflowId)
|
||||
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
@@ -509,6 +537,8 @@ export async function performActivateVersion(
|
||||
},
|
||||
})
|
||||
|
||||
await notifySocketDeploymentChanged(workflowId)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
deployedAt: result.deployedAt,
|
||||
@@ -596,8 +626,7 @@ export async function performRevertToVersion(
|
||||
.where(eq(workflowTable.id, workflowId))
|
||||
|
||||
try {
|
||||
const socketServerUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||
await fetch(`${socketServerUrl}/api/workflow-reverted`, {
|
||||
await fetch(`${getSocketServerUrl()}/api/workflow-reverted`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -7,6 +7,7 @@ export {
|
||||
performChatUndeploy,
|
||||
} from './chat-deploy'
|
||||
export {
|
||||
notifySocketDeploymentChanged,
|
||||
type PerformActivateVersionParams,
|
||||
type PerformActivateVersionResult,
|
||||
type PerformFullDeployParams,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import OpenAI from 'openai'
|
||||
import type { ChatCompletionCreateParamsStreaming } from 'openai/resources/chat/completions'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { getOllamaUrl } from '@/lib/core/utils/urls'
|
||||
import type { StreamingExecution } from '@/executor/types'
|
||||
import { MAX_TOOL_ITERATIONS } from '@/providers'
|
||||
import type { ModelsObject } from '@/providers/ollama/types'
|
||||
@@ -18,7 +18,7 @@ import { useProvidersStore } from '@/stores/providers'
|
||||
import { executeTool } from '@/tools'
|
||||
|
||||
const logger = createLogger('OllamaProvider')
|
||||
const OLLAMA_HOST = env.OLLAMA_URL || 'http://localhost:11434'
|
||||
const OLLAMA_HOST = getOllamaUrl()
|
||||
|
||||
export const ollamaProvider: ProviderConfig = {
|
||||
id: 'ollama',
|
||||
|
||||
@@ -238,4 +238,21 @@ export class MemoryRoomManager implements IRoomManager {
|
||||
|
||||
logger.info(`Notified ${room.users.size} users about workflow update: ${workflowId}`)
|
||||
}
|
||||
|
||||
async handleWorkflowDeployed(workflowId: string): Promise<void> {
|
||||
logger.info(`Handling workflow deployed notification for ${workflowId}`)
|
||||
|
||||
const room = this.workflowRooms.get(workflowId)
|
||||
if (!room) {
|
||||
logger.debug(`No active room found for deployed workflow ${workflowId}`)
|
||||
return
|
||||
}
|
||||
|
||||
this._io.to(workflowId).emit('workflow-deployed', {
|
||||
workflowId,
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
|
||||
logger.info(`Notified ${room.users.size} users about workflow deployment change: ${workflowId}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,4 +439,22 @@ export class RedisRoomManager implements IRoomManager {
|
||||
const userCount = await this.getUniqueUserCount(workflowId)
|
||||
logger.info(`Notified ${userCount} users about workflow update: ${workflowId}`)
|
||||
}
|
||||
|
||||
async handleWorkflowDeployed(workflowId: string): Promise<void> {
|
||||
logger.info(`Handling workflow deployed notification for ${workflowId}`)
|
||||
|
||||
const hasRoom = await this.hasWorkflowRoom(workflowId)
|
||||
if (!hasRoom) {
|
||||
logger.debug(`No active room found for deployed workflow ${workflowId}`)
|
||||
return
|
||||
}
|
||||
|
||||
this._io.to(workflowId).emit('workflow-deployed', {
|
||||
workflowId,
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
|
||||
const userCount = await this.getUniqueUserCount(workflowId)
|
||||
logger.info(`Notified ${userCount} users about workflow deployment change: ${workflowId}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,4 +138,9 @@ export interface IRoomManager {
|
||||
* Handle workflow update - notify users
|
||||
*/
|
||||
handleWorkflowUpdate(workflowId: string): Promise<void>
|
||||
|
||||
/**
|
||||
* Handle workflow deployment change - notify users to refresh deployment state
|
||||
*/
|
||||
handleWorkflowDeployed(workflowId: string): Promise<void>
|
||||
}
|
||||
|
||||
@@ -122,6 +122,20 @@ export function createHttpHandler(roomManager: IRoomManager, logger: Logger) {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle workflow deployment change notifications from the main API
|
||||
if (req.method === 'POST' && req.url === '/api/workflow-deployed') {
|
||||
try {
|
||||
const body = await readRequestBody(req)
|
||||
const { workflowId } = JSON.parse(body)
|
||||
await roomManager.handleWorkflowDeployed(workflowId)
|
||||
sendSuccess(res)
|
||||
} catch (error) {
|
||||
logger.error('Error handling workflow deployed notification:', error)
|
||||
sendError(res, 'Failed to process deployment notification')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle workflow revert notifications from the main API
|
||||
if (req.method === 'POST' && req.url === '/api/workflow-reverted') {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user