feat(logger): added logger to remainder of files

This commit is contained in:
Waleed Latif
2025-03-12 01:35:04 -07:00
parent fdfef2d254
commit decc138350
65 changed files with 419 additions and 361 deletions
+1 -1
View File
@@ -153,7 +153,7 @@ export async function GET(request: NextRequest) {
return NextResponse.json({ accessToken: credential.accessToken }, { status: 200 })
} catch (error) {
console.error('Error getting OAuth token:', error)
logger.error('Error getting OAuth token:', { error })
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}
+7 -2
View File
@@ -2,6 +2,9 @@ import { NextResponse } from 'next/server'
import { OpenAI } from 'openai'
import { ChatCompletionMessageParam } from 'openai/resources/chat/completions'
import { z } from 'zod'
import { createLogger } from '@/lib/logs/console-logger'
const logger = createLogger('ChatAPI')
// Validation schemas
const MessageSchema = z.object({
@@ -135,6 +138,8 @@ Only use the provided functions and respond naturally to the user's requests.`
}
export async function POST(request: Request) {
const requestId = crypto.randomUUID().slice(0, 8)
try {
// Validate API key
const apiKey = request.headers.get('X-OpenAI-Key')
@@ -175,7 +180,7 @@ export async function POST(request: Request) {
// Process tool calls if present
if (message.tool_calls) {
console.log(message.tool_calls)
logger.debug(`[${requestId}] Tool calls:`, { toolCalls: message.tool_calls })
const actions = message.tool_calls.map((call) => ({
name: call.function.name,
parameters: JSON.parse(call.function.arguments),
@@ -194,7 +199,7 @@ export async function POST(request: Request) {
"I'm not sure what changes to make to the workflow. Can you please provide more specific instructions?",
})
} catch (error) {
console.error('Chat API error:', error)
logger.error(`[${requestId}] Chat API error:`, { error })
// Handle specific error types
if (error instanceof z.ZodError) {
-1
View File
@@ -14,7 +14,6 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
const { id } = await params
try {
logger.debug(`[${requestId}] Persisting logs for workflow: ${id}`)
const validation = await validateWorkflowAccess(request, id, false)
if (validation.error) {
logger.warn(`[${requestId}] Workflow access validation failed: ${validation.error.message}`)
-1
View File
@@ -10,7 +10,6 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
try {
const { id } = await params
logger.debug(`[${requestId}] Checking status for workflow: ${id}`)
const validation = await validateWorkflowAccess(request, id, false)
if (validation.error) {
+4 -1
View File
@@ -1,6 +1,9 @@
import { NextRequest } from 'next/server'
import { createLogger } from '@/lib/logs/console-logger'
import { getWorkflowById } from '@/lib/workflows'
const logger = createLogger('WorkflowMiddleware')
export interface ValidationResult {
error?: { message: string; status: number }
workflow?: any
@@ -52,7 +55,7 @@ export async function validateWorkflowAccess(
}
return { workflow }
} catch (error) {
console.error('Validation error:', error)
logger.error('Validation error:', { error })
return {
error: {
message: 'Internal server error',
@@ -23,6 +23,7 @@ import {
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { useNotificationStore } from '@/stores/notifications/store'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
@@ -31,6 +32,8 @@ import { useWorkflowExecution } from '../../hooks/use-workflow-execution'
import { HistoryDropdownItem } from './components/history-dropdown-item/history-dropdown-item'
import { NotificationDropdownItem } from './components/notification-dropdown-item/notification-dropdown-item'
const logger = createLogger('ControlBar')
/**
* Control bar for managing workflows - handles editing, deletion, deployment,
* history, notifications and execution.
@@ -106,7 +109,7 @@ export function ControlBar() {
)
}
} catch (error) {
console.error('Failed to check deployment status:', error)
logger.error('Failed to check deployment status:', { error })
}
}
checkStatus()
+5 -2
View File
@@ -3,6 +3,9 @@
import { Component, ReactNode, useEffect } from 'react'
import { BotIcon } from 'lucide-react'
import { Card } from '@/components/ui/card'
import { createLogger } from '@/lib/logs/console-logger'
const logger = createLogger('ErrorBoundary')
// ======== Shared Error UI Component ========
interface ErrorUIProps {
@@ -81,7 +84,7 @@ interface NextErrorProps {
export function NextError({ error, reset }: NextErrorProps) {
useEffect(() => {
// Optionally log the error to an error reporting service
console.error('Workflow error:', error)
logger.error('Workflow error:', { error })
}, [error])
return <ErrorUI onReset={reset} />
@@ -96,7 +99,7 @@ export function NextGlobalError({
reset: () => void
}) {
useEffect(() => {
console.error('Global workspace error:', error)
logger.error('Global workspace error:', { error })
}, [error])
return (
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react'
import { ChevronDown, ChevronUp, Copy, Rocket, Terminal, X } from 'lucide-react'
import { useEffect, useState } from 'react'
import { Copy, Rocket, Terminal, X } from 'lucide-react'
import { ErrorIcon } from '@/components/icons'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import {
@@ -13,15 +13,17 @@ import {
AlertDialogTitle,
} from '@/components/ui/alert-dialog'
import { Button } from '@/components/ui/button'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { useNotificationStore } from '@/stores/notifications/store'
import { Notification, NotificationType } from '@/stores/notifications/types'
import { Notification } from '@/stores/notifications/types'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
const logger = createLogger('Notifications')
// Constants
const NOTIFICATION_TIMEOUT = 4000
const FADE_DURATION = 300
const MAX_MESSAGE_HEIGHT = 300 // Maximum height in pixels before truncation
// Icon mapping for notification types
const NotificationIcon = {
@@ -213,7 +215,7 @@ function NotificationAlert({
// Close the dialog
setIsDeleteDialogOpen(false)
} catch (error) {
console.error('Error deleting API deployment:', error)
logger.error('Error deleting API deployment:', { error })
}
}
@@ -4,12 +4,14 @@ import { highlight, languages } from 'prismjs'
import 'prismjs/components/prism-javascript'
import 'prismjs/themes/prism.css'
import Editor from 'react-simple-code-editor'
import { Button } from '@/components/ui/button'
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { useSubBlockValue } from '../hooks/use-sub-block-value'
const logger = createLogger('Code')
interface CodeProps {
blockId: string
subBlockId: string
@@ -148,7 +150,7 @@ export function Code({
}
}, 0)
} catch (error) {
console.error('Failed to parse drop data:', error)
logger.error('Failed to parse drop data:', { error })
}
}
@@ -10,10 +10,13 @@ import { Button } from '@/components/ui/button'
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
import { useSubBlockValue } from '../hooks/use-sub-block-value'
const logger = createLogger('ConditionInput')
interface ConditionalBlock {
id: string
title: string
@@ -145,7 +148,7 @@ export function ConditionInput({ blockId, subBlockId, isConnecting }: ConditionI
})
)
} catch (error) {
console.error('Error updating block value:', error, { blockId, newValue })
logger.error('Error updating block value:', { error, blockId, newValue })
}
}
@@ -280,7 +283,7 @@ export function ConditionInput({ blockId, subBlockId, isConnecting }: ConditionI
}
}, 0)
} catch (error) {
console.error('Failed to parse drop data:', error)
logger.error('Failed to parse drop data:', { error })
}
}
@@ -14,6 +14,7 @@ import {
import { OAuthRequiredModal } from '@/components/ui/oauth-required-modal'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { client } from '@/lib/auth-client'
import { createLogger } from '@/lib/logs/console-logger'
import {
Credential,
OAUTH_PROVIDERS,
@@ -24,6 +25,8 @@ import {
} from '@/lib/oauth'
import { saveToStorage } from '@/stores/workflows/persistence'
const logger = createLogger('CredentialSelector')
interface CredentialSelectorProps {
value: string
onChange: (value: string) => void
@@ -99,7 +102,7 @@ export function CredentialSelector({
}
}
} catch (error) {
console.error('Error fetching credentials:', error)
logger.error('Error fetching credentials:', { error })
} finally {
setIsLoading(false)
}
@@ -162,7 +165,7 @@ export function CredentialSelector({
callbackURL: window.location.href,
})
} catch (error) {
console.error('OAuth login error:', error)
logger.error('OAuth login error:', { error })
}
}
@@ -4,11 +4,13 @@ import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-drop
import { formatDisplayText } from '@/components/ui/formatted-text'
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
import { Textarea } from '@/components/ui/textarea'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
import { SubBlockConfig } from '@/blocks/types'
import { useSubBlockValue } from '../hooks/use-sub-block-value'
const logger = createLogger('LongInput')
interface LongInputProps {
placeholder?: string
blockId: string
@@ -105,7 +107,7 @@ export function LongInput({
}, 0)
})
} catch (error) {
console.error('Failed to parse drop data:', error)
logger.error('Failed to parse drop data:', { error })
}
}
@@ -4,10 +4,13 @@ import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-drop
import { formatDisplayText } from '@/components/ui/formatted-text'
import { Input } from '@/components/ui/input'
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { SubBlockConfig } from '@/blocks/types'
import { useSubBlockValue } from '../hooks/use-sub-block-value'
const logger = createLogger('ShortInput')
interface ShortInputProps {
placeholder?: string
password?: boolean
@@ -210,7 +213,7 @@ export function ShortInput({
}, 0)
})
} catch (error) {
console.error('Failed to parse drop data:', error)
logger.error('Failed to parse drop data:', { error })
}
}
@@ -12,10 +12,13 @@ import {
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
import { Label } from '@/components/ui/label'
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { useCustomToolsStore } from '@/stores/custom-tools/store'
import { CodeEditor } from '../code-editor/code-editor'
const logger = createLogger('CustomToolModal')
interface CustomToolModalProps {
open: boolean
onOpenChange: (open: boolean) => void
@@ -80,7 +83,7 @@ export function CustomToolModal({
setIsEditing(true)
setToolId(initialValues.id)
} catch (error) {
console.error('Error initializing form with initial values:', error)
logger.error('Error initializing form with initial values:', { error })
setSchemaError('Failed to load tool data. Please try again.')
}
} else if (open) {
@@ -233,9 +236,7 @@ export function CustomToolModal({
onSave(customTool)
handleClose()
} catch (error) {
console.error('Error saving custom tool:', error)
setSchemaError('Failed to save custom tool. Please check your inputs and try again.')
console.error('Error saving custom tool:', error)
logger.error('Error saving custom tool:', { error })
setSchemaError('Failed to save custom tool. Please check your inputs and try again.')
}
}
@@ -278,7 +279,7 @@ export function CustomToolModal({
setDropdownPosition({ top, left })
}
} catch (error) {
console.error('Error calculating cursor position:', error)
logger.error('Error calculating cursor position:', { error })
}
// Check if we should show the environment variables dropdown
@@ -4,8 +4,11 @@ import { CheckCircle2, ExternalLink } from 'lucide-react'
import { GithubIcon, StripeIcon, WhatsAppIcon } from '@/components/icons'
import { Button } from '@/components/ui/button'
import { WebhookModal } from '@/components/ui/webhook-modal'
import { createLogger } from '@/lib/logs/console-logger'
import { useSubBlockValue } from '../hooks/use-sub-block-value'
const logger = createLogger('WebhookConfig')
export interface WebhookProvider {
id: string
name: string
@@ -138,7 +141,7 @@ export function WebhookConfig({ blockId, subBlockId, isConnecting }: WebhookConf
}
}
} catch (error) {
console.error('Error checking webhook:', error)
logger.error('Error checking webhook:', { error })
}
}
@@ -198,7 +201,7 @@ export function WebhookConfig({ blockId, subBlockId, isConnecting }: WebhookConf
return true
} catch (error: any) {
console.error('Error saving webhook:', error)
logger.error('Error saving webhook:', { error })
setError(error.message || 'Failed to save webhook configuration')
return false
} finally {
@@ -228,7 +231,7 @@ export function WebhookConfig({ blockId, subBlockId, isConnecting }: WebhookConf
return true
} catch (error: any) {
console.error('Error deleting webhook:', error)
logger.error('Error deleting webhook:', { error })
setError(error.message || 'Failed to delete webhook')
return false
} finally {
+4 -1
View File
@@ -1,7 +1,10 @@
import { shallow } from 'zustand/shallow'
import { createLogger } from '@/lib/logs/console-logger'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
const logger = createLogger('useBlockConnections')
interface Field {
name: string
type: string
@@ -77,7 +80,7 @@ export function useBlockConnections(blockId: string) {
? JSON.parse(responseFormatValue)
: responseFormatValue // Handle case where it's already an object
} catch (e) {
console.error('Failed to parse response format:', e)
logger.error('Failed to parse response format:', { e })
responseFormat = undefined
}
+6 -27
View File
@@ -1,5 +1,6 @@
import { useCallback, useState } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { createLogger } from '@/lib/logs/console-logger'
import { useConsoleStore } from '@/stores/console/store'
import { useExecutionStore } from '@/stores/execution/store'
import { useNotificationStore } from '@/stores/notifications/store'
@@ -12,6 +13,8 @@ import { Executor } from '@/executor'
import { ExecutionResult } from '@/executor/types'
import { Serializer } from '@/serializer'
const logger = createLogger('useWorkflowExecution')
export function useWorkflowExecution() {
const { blocks, edges, loops } = useWorkflowStore()
const { activeWorkflowId } = useWorkflowRegistry()
@@ -61,7 +64,7 @@ export function useWorkflowExecution() {
window.localStorage.setItem(logListKey, JSON.stringify(logList))
} catch (error) {
console.error('Error storing logs in localStorage:', error)
logger.error('Error storing logs in localStorage:', { error })
}
return
}
@@ -80,7 +83,7 @@ export function useWorkflowExecution() {
throw new Error('Failed to persist logs')
}
} catch (error) {
console.error('Error persisting logs:', error)
logger.error('Error persisting logs:', { error })
}
}
@@ -112,30 +115,6 @@ export function useWorkflowExecution() {
{} as Record<string, Record<string, any>>
)
// Debug logging
console.group('Workflow Execution State')
console.log('Block Configurations:', blocks)
console.log(
'SubBlock Store Values:',
useSubBlockStore.getState().workflowValues[activeWorkflowId]
)
console.log('Merged Block States for Execution:', currentBlockStates)
// Debug any responseFormat fields
const blockWithResponseFormat = Object.entries(currentBlockStates).find(
([_id, state]) => state.responseFormat
)
if (blockWithResponseFormat) {
console.log(
'ResponseFormat found:',
blockWithResponseFormat[0],
typeof blockWithResponseFormat[1].responseFormat,
blockWithResponseFormat[1].responseFormat
)
}
console.groupEnd()
// Get environment variables
const envVars = getAllVariables()
const envVarValues = Object.entries(envVars).reduce(
@@ -189,7 +168,7 @@ export function useWorkflowExecution() {
// Persist logs after notification
await persistLogs(blockLogs, executionId)
} catch (error: any) {
console.error('Workflow Execution Error:', error)
logger.error('Workflow Execution Error:', { error })
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
+7 -8
View File
@@ -7,13 +7,11 @@ import ReactFlow, {
ConnectionLineType,
EdgeTypes,
NodeTypes,
Position,
ReactFlowProvider,
useReactFlow,
} from 'reactflow'
import 'reactflow/dist/style.css'
import { OAuthRequiredModal } from '@/components/ui/oauth-required-modal'
import { useNotificationStore } from '@/stores/notifications/store'
import { createLogger } from '@/lib/logs/console-logger'
import { useGeneralStore } from '@/stores/settings/general/store'
import { initializeSyncManagers, isSyncInitialized } from '@/stores/sync-registry'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
@@ -28,6 +26,8 @@ import { LoopInput } from './components/workflow-loop/components/loop-input/loop
import { LoopLabel } from './components/workflow-loop/components/loop-label/loop-label'
import { createLoopNode, getRelativeLoopPosition } from './components/workflow-loop/workflow-loop'
const logger = createLogger('Workflow')
// Define custom node and edge types
const nodeTypes: NodeTypes = {
workflowBlock: WorkflowBlock,
@@ -47,7 +47,6 @@ function WorkflowContent() {
const { project } = useReactFlow()
// Store access
const { addNotification } = useNotificationStore()
const { workflows, setActiveWorkflow, createWorkflow } = useWorkflowRegistry()
const { blocks, edges, loops, addBlock, updateBlockPosition, addEdge, removeEdge } =
useWorkflowStore()
@@ -114,13 +113,13 @@ function WorkflowContent() {
// Add block nodes
Object.entries(blocks).forEach(([blockId, block]) => {
if (!block.type || !block.name) {
console.log('Skipping invalid block:', blockId, block)
logger.warn(`Skipping invalid block: ${blockId}`, { block })
return
}
const blockConfig = getBlock(block.type)
if (!blockConfig) {
console.error(`No configuration found for block type: ${block.type}`)
logger.error(`No configuration found for block type: ${block.type}`, { block })
return
}
@@ -241,7 +240,7 @@ function WorkflowContent() {
const blockConfig = getBlock(data.type)
if (!blockConfig) {
console.error('Invalid block type:', data.type)
logger.error('Invalid block type:', { data })
return
}
@@ -268,7 +267,7 @@ function WorkflowContent() {
}
}
} catch (err) {
console.error('Error dropping block:', err)
logger.error('Error dropping block:', { err })
}
},
[project, blocks, addBlock, addEdge, findClosestOutput]
@@ -19,6 +19,9 @@ import {
SelectValue,
} from '@/components/ui/select'
import { Textarea } from '@/components/ui/textarea'
import { createLogger } from '@/lib/logs/console-logger'
const logger = createLogger('HelpForm')
// Define form schema
const formSchema = z.object({
@@ -119,7 +122,7 @@ export function HelpForm({ onClose }: HelpFormProps) {
lastModified: new Date().getTime(),
})
} catch (error) {
console.warn('Image compression failed, using original file:', error)
logger.warn('Image compression failed, using original file:', { error })
return file
}
}
@@ -167,7 +170,7 @@ export function HelpForm({ onClose }: HelpFormProps) {
setImages((prev) => [...prev, ...newImages])
}
} catch (error) {
console.error('Error processing images:', error)
logger.error('Error processing images:', { error })
setImageError('An error occurred while processing images. Please try again.')
} finally {
setIsProcessing(false)
@@ -258,7 +261,7 @@ export function HelpForm({ onClose }: HelpFormProps) {
images.forEach((image) => URL.revokeObjectURL(image.preview))
setImages([])
} catch (error) {
console.error('Error submitting help request:', error)
logger.error('Error submitting help request:', { error })
setSubmitStatus('error')
setErrorMessage(error instanceof Error ? error.message : 'An unknown error occurred')
} finally {
@@ -12,9 +12,12 @@ import {
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { signOut, useSession } from '@/lib/auth-client'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { clearUserData } from '@/stores'
const logger = createLogger('Account')
interface AccountProps {
onOpenChange: (open: boolean) => void
}
@@ -107,7 +110,7 @@ export function Account({ onOpenChange }: AccountProps) {
// Still wait for the promise to resolve/reject to catch errors
await signOutPromise
} catch (error) {
console.error('Error signing out:', error)
logger.error('Error signing out:', { error })
// Still navigate even if there's an error
router.push('/login?fromLogout=true')
} finally {
@@ -7,10 +7,13 @@ import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { Skeleton } from '@/components/ui/skeleton'
import { client, useSession } from '@/lib/auth-client'
import { createLogger } from '@/lib/logs/console-logger'
import { OAUTH_PROVIDERS, OAuthServiceConfig } from '@/lib/oauth'
import { cn } from '@/lib/utils'
import { loadFromStorage, removeFromStorage, saveToStorage } from '@/stores/workflows/persistence'
const logger = createLogger('Credentials')
interface CredentialsProps {
onOpenChange?: (open: boolean) => void
}
@@ -93,7 +96,7 @@ export function Credentials({ onOpenChange }: CredentialsProps) {
setServices(serviceDefinitions)
}
} catch (error) {
console.error('Error fetching services:', error)
logger.error('Error fetching services:', { error })
// Use base definitions on error
setServices(defineServices())
} finally {
@@ -120,7 +123,7 @@ export function Credentials({ onOpenChange }: CredentialsProps) {
// Clear the URL parameters
router.replace('/w')
} else if (error) {
console.error('OAuth error:', error)
logger.error('OAuth error:', { error })
router.replace('/w')
}
}, [searchParams, router, userId])
@@ -188,7 +191,7 @@ export function Credentials({ onOpenChange }: CredentialsProps) {
callbackURL: window.location.href,
})
} catch (error) {
console.error('OAuth login error:', error)
logger.error('OAuth login error:', { error })
setIsConnecting(null)
}
}
@@ -224,10 +227,10 @@ export function Credentials({ onOpenChange }: CredentialsProps) {
})
)
} else {
console.error('Error disconnecting service')
logger.error('Error disconnecting service')
}
} catch (error) {
console.error('Error disconnecting service:', error)
logger.error('Error disconnecting service:', { error })
} finally {
setIsConnecting(null)
}
@@ -5,9 +5,12 @@ import { Loader2, Play, RefreshCw, Search, Square } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { createLogger } from '@/lib/logs/console-logger'
import { useDebounce } from '../../hooks/use-debounce'
import { useFilterStore } from '../../stores/store'
import { LogsResponse, WorkflowLog } from '../../stores/types'
import { LogsResponse } from '../../stores/types'
const logger = createLogger('ControlBar')
/**
* Control bar for logs page - includes search functionality and refresh/live controls
@@ -43,7 +46,7 @@ export function ControlBar() {
const data: LogsResponse = await response.json()
return data
} catch (err) {
console.error('Failed to fetch logs:', err)
logger.error('Failed to fetch logs:', { err })
throw err
}
}
+5 -3
View File
@@ -1,8 +1,8 @@
'use client'
import { useEffect, useMemo, useState } from 'react'
import { format } from 'date-fns'
import { AlertCircle, Info, Loader2 } from 'lucide-react'
import { createLogger } from '@/lib/logs/console-logger'
import { ControlBar } from './components/control-bar/control-bar'
import { Filters } from './components/filters/filters'
import { Sidebar } from './components/sidebar/sidebar'
@@ -10,6 +10,8 @@ import { useFilterStore } from './stores/store'
import { LogsResponse, WorkflowLog } from './stores/types'
import { formatDate } from './utils/format-date'
const logger = createLogger('Logs')
// Helper function to get level badge styling
const getLevelBadgeStyles = (level: string) => {
switch (level.toLowerCase()) {
@@ -84,12 +86,12 @@ export default function Logs() {
const data: LogsResponse = await response.json()
// Log the response to console
console.log('Workflow logs response:', data)
logger.info('Workflow logs response:', data)
setLogs(data.data)
setError(null)
} catch (err) {
console.error('Failed to fetch logs:', err)
logger.error('Failed to fetch logs:', { err })
setError(err instanceof Error ? err.message : 'An unknown error occurred')
} finally {
setLoading(false)
+5 -2
View File
@@ -1,9 +1,12 @@
import { ChartBarIcon } from '@/components/icons'
import { createLogger } from '@/lib/logs/console-logger'
import { ProviderId } from '@/providers/types'
import { MODEL_PROVIDERS } from '@/providers/utils'
import { ToolResponse } from '@/tools/types'
import { BlockConfig, ParamType } from '../types'
const logger = createLogger('EvaluatorBlock')
interface Metric {
name: string
description: string
@@ -52,7 +55,7 @@ export const generateEvaluatorPrompt = (metrics: Metric[], content: string): str
formattedContent = JSON.stringify(content, null, 2)
}
} catch (e) {
console.warn('Warning: Content may not be valid JSON, using as-is', e)
logger.warn('Warning: Content may not be valid JSON, using as-is', { e })
formattedContent = content
}
@@ -184,7 +187,7 @@ export const EvaluatorBlock: BlockConfig<EvaluatorResponse> = {
return JSON.stringify(result)
} catch (e) {
console.error('Error in systemPrompt value function:', e)
logger.error('Error in systemPrompt value function:', { e })
// Return a minimal valid JSON as fallback
return JSON.stringify({
systemPrompt: 'Evaluate the content and return a JSON with metric scores.',
+8 -5
View File
@@ -14,6 +14,7 @@ import {
} from '@/components/ui/command'
import { OAuthRequiredModal } from '@/components/ui/oauth-required-modal'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { createLogger } from '@/lib/logs/console-logger'
import {
Credential,
OAUTH_PROVIDERS,
@@ -25,6 +26,8 @@ import {
} from '@/lib/oauth'
import { saveToStorage } from '@/stores/workflows/persistence'
const logger = createLogger('FileSelector')
export interface FileInfo {
id: string
name: string
@@ -117,7 +120,7 @@ export function FileSelector({
}
}
} catch (error) {
console.error('Error fetching credentials:', error)
logger.error('Error fetching credentials:', { error })
} finally {
setIsLoading(false)
}
@@ -146,11 +149,11 @@ export function FileSelector({
return data.file
}
} else {
console.error('Error fetching file by ID:', await response.text())
logger.error('Error fetching file by ID:', { error: await response.text() })
}
return null
} catch (error) {
console.error('Error fetching file by ID:', error)
logger.error('Error fetching file by ID:', { error })
return null
} finally {
setIsLoadingSelectedFile(false)
@@ -198,11 +201,11 @@ export function FileSelector({
}
}
} else {
console.error('Error fetching files:', await response.text())
logger.error('Error fetching files:', { error: await response.text() })
setFiles([])
}
} catch (error) {
console.error('Error fetching files:', error)
logger.error('Error fetching files:', { error })
setFiles([])
} finally {
setIsLoading(false)
+5 -2
View File
@@ -11,6 +11,7 @@ import {
DialogTitle,
} from '@/components/ui/dialog'
import { client } from '@/lib/auth-client'
import { createLogger } from '@/lib/logs/console-logger'
import {
OAUTH_PROVIDERS,
OAuthProvider,
@@ -20,6 +21,8 @@ import {
} from '@/lib/oauth'
import { saveToStorage } from '@/stores/workflows/persistence'
const logger = createLogger('OAuthRequiredModal')
export interface OAuthRequiredModalProps {
isOpen: boolean
onClose: () => void
@@ -107,7 +110,7 @@ export function OAuthRequiredModal({
})
window.dispatchEvent(event)
} catch (error) {
console.error('Error redirecting to settings:', error)
logger.error('Error redirecting to settings:', { error })
}
}
@@ -131,7 +134,7 @@ export function OAuthRequiredModal({
callbackURL: window.location.href,
})
} catch (error) {
console.error('Error initiating OAuth flow:', error)
logger.error('Error initiating OAuth flow:', { error })
}
}
+7 -4
View File
@@ -1,8 +1,11 @@
import React, { useEffect, useMemo, useState } from 'react'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
const logger = createLogger('TagDropdown')
interface Field {
name: string
type: string
@@ -127,7 +130,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
}
}
} catch (e) {
console.error('Error parsing metrics:', e)
logger.error('Error parsing metrics:', { e })
}
}
@@ -152,7 +155,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
}
}
} catch (e) {
console.error('Error parsing response format:', e)
logger.error('Error parsing response format:', { e })
}
// Fall back to default outputs if no response format
@@ -190,7 +193,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
}
}
} catch (e) {
console.error('Error parsing response format:', e)
logger.error('Error parsing response format:', { e })
}
if (sourceBlock.type === 'evaluator') {
@@ -204,7 +207,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
)
}
} catch (e) {
console.error('Error parsing metrics:', e)
logger.error('Error parsing metrics:', { e })
return []
}
}
+6 -6
View File
@@ -23,12 +23,13 @@ import {
} from '@/components/ui/dialog'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { createLogger } from '@/lib/logs/console-logger'
import {
ProviderConfig,
WEBHOOK_PROVIDERS,
WebhookProvider,
} from '@/app/w/[id]/components/workflow-block/components/sub-block/components/webhook-config'
const logger = createLogger('WebhookModal')
interface WebhookModalProps {
isOpen: boolean
onClose: () => void
@@ -101,7 +102,7 @@ export function WebhookModal({
}
}
} catch (error) {
console.error('Error fetching webhook config:', error)
logger.error('Error fetching webhook config:', { error })
} finally {
setIsLoadingToken(false)
}
@@ -156,11 +157,10 @@ export function WebhookModal({
? formattedPath.substring(1)
: formattedPath
console.log('Saving webhook with path:', pathToSave)
await onSave(pathToSave, providerConfig)
}
} catch (error) {
console.error('Error saving webhook:', error)
logger.error('Error saving webhook:', { error })
} finally {
setIsSaving(false)
}
@@ -174,7 +174,7 @@ export function WebhookModal({
setShowDeleteConfirm(false)
}
} catch (error) {
console.error('Error deleting webhook:', error)
logger.error('Error deleting webhook:', { error })
} finally {
setIsDeleting(false)
}
@@ -211,7 +211,7 @@ export function WebhookModal({
})
}
} catch (error: any) {
console.error('Error testing webhook:', error)
logger.error('Error testing webhook:', { error })
setTestResult({
success: false,
message: error.message || 'An error occurred while testing the webhook',
-5
View File
@@ -11,18 +11,13 @@ type DrizzleClient = ReturnType<typeof drizzle>
const createMockDb = (): DrizzleClient => {
const mockHandler = {
get: (target: any, prop: string) => {
// Return a function that logs and returns empty results
if (typeof prop === 'string') {
return (...args: any[]) => {
console.log(`[localStorage Mode] DB operation "${prop}" called with:`, args)
// Create a chainable mock that always returns itself
const chainableMock = new Proxy(
{},
{
get: (target, chainProp) => {
if (chainProp === 'then') {
// Make it thenable to work with await
return (resolve: Function) => resolve([])
}
return chainableMock
+22 -82
View File
@@ -1,3 +1,4 @@
import { createLogger } from '@/lib/logs/console-logger'
import { getAllBlocks } from '@/blocks'
import { generateRouterPrompt } from '@/blocks/blocks/router'
import { BlockOutput } from '@/blocks/types'
@@ -9,6 +10,8 @@ import { executeTool, getTool } from '@/tools'
import { PathTracker } from './path'
import { ExecutionContext } from './types'
const logger = createLogger('Handlers')
/**
* Interface for block handlers that execute specific block types.
* Each handler is responsible for executing a particular type of block.
@@ -60,14 +63,14 @@ async function executeCodeWithFallback(
const result = await executeCode(code, params, timeout)
if (!result.success) {
console.warn(`WebContainer API execution failed: ${result.error}`)
logger.warn(`WebContainer API execution failed: ${result.error}`)
throw new Error(result.error || `WebContainer execution failed with no error message`)
}
return { success: true, output: result.output }
} catch (error: any) {
console.warn('WebContainer execution failed, falling back to VM:', error)
console.error('WebContainer error details:', {
logger.warn('WebContainer execution failed, falling back to VM:', error)
logger.error('WebContainer error details:', {
name: error.name,
message: error.message,
stack: error.stack,
@@ -106,95 +109,40 @@ export class AgentBlockHandler implements BlockHandler {
inputs: Record<string, any>,
context: ExecutionContext
): Promise<BlockOutput> {
console.log(`[AgentBlockHandler Debug] Executing agent block: ${block.id}`)
console.log(`[AgentBlockHandler Debug] Block inputs:`, JSON.stringify(inputs, null, 2))
logger.info(`Executing agent block: ${block.id}`)
// Check for null values and try to resolve from environment variables
const nullInputs = Object.entries(inputs)
.filter(([_, value]) => value === null)
.map(([key]) => key)
if (nullInputs.length > 0) {
console.warn(`[AgentBlockHandler Debug] Null inputs detected:`, nullInputs)
// Check if we can resolve API key from environment variables
if (nullInputs.includes('apiKey') && context.environmentVariables) {
console.log(
`[AgentBlockHandler Debug] Attempting to resolve API key from environment variables`
)
console.log(
`[AgentBlockHandler Debug] Available env vars:`,
Object.keys(context.environmentVariables)
)
// Try different possible environment variable names for OpenAI API key
const possibleEnvVarNames = ['OPENAI_API_KEY', 'openai_api_key', 'OPENAI_KEY', 'openai_key']
for (const envVar of possibleEnvVarNames) {
if (context.environmentVariables[envVar]) {
console.log(
`[AgentBlockHandler Debug] Found API key in environment variable: ${envVar}`
)
inputs.apiKey = context.environmentVariables[envVar]
break
}
}
// Check if we successfully resolved the API key
if (inputs.apiKey) {
console.log(
`[AgentBlockHandler Debug] Successfully resolved API key from environment variables`
)
} else {
console.error(
`[AgentBlockHandler Debug] Failed to resolve API key from environment variables`
)
}
}
}
// Parse response format if provided
let responseFormat: any = undefined
if (inputs.responseFormat) {
// Handle empty string case - treat it as no response format
if (inputs.responseFormat === '') {
console.log(
`[AgentBlockHandler Debug] Response format is an empty string, treating as undefined`
)
responseFormat = undefined
} else {
try {
console.log(
`[AgentBlockHandler Debug] Response format before parsing:`,
typeof inputs.responseFormat,
inputs.responseFormat
)
responseFormat =
typeof inputs.responseFormat === 'string'
? JSON.parse(inputs.responseFormat)
: inputs.responseFormat
console.log(`[AgentBlockHandler Debug] Response format after parsing:`, responseFormat)
// Ensure the responseFormat is properly structured
if (responseFormat && typeof responseFormat === 'object') {
// If it's just a raw schema without the expected wrapper properties,
// wrap it properly for the provider
if (!responseFormat.schema && !responseFormat.name) {
console.log(`[AgentBlockHandler Debug] Wrapping raw schema in proper format`)
responseFormat = {
name: 'response_schema',
schema: responseFormat,
strict: true,
}
}
console.log(
`[AgentBlockHandler Debug] Final response format structure:`,
responseFormat
)
}
} catch (error: any) {
console.error(`[AgentBlockHandler Error] Failed to parse response format:`, error)
logger.error(`Failed to parse response format:`, { error })
throw new Error(`Invalid response format: ${error.message}`)
}
}
@@ -202,7 +150,7 @@ export class AgentBlockHandler implements BlockHandler {
const model = inputs.model || 'gpt-4o'
const providerId = getProviderFromModel(model)
console.log(`[AgentBlockHandler Debug] Using provider: ${providerId}, model: ${model}`)
logger.info(`Using provider: ${providerId}, model: ${model}`)
// Format tools for provider API
const formattedTools = Array.isArray(inputs.tools)
@@ -243,7 +191,7 @@ export class AgentBlockHandler implements BlockHandler {
return result.output
} catch (error: any) {
console.error(`Error executing custom tool ${toolName}:`, error)
logger.error(`Error executing custom tool ${toolName}:`, error)
throw new Error(`Error in ${toolName}: ${error.message}`)
}
},
@@ -290,36 +238,29 @@ export class AgentBlockHandler implements BlockHandler {
responseFormat,
}
console.log(`[AgentBlockHandler Debug] Provider request details:`, {
logger.info(`Provider request prepared`, {
model: providerRequest.model,
hasSystemPrompt: !!providerRequest.systemPrompt,
hasContext: !!providerRequest.context,
hasTools: !!providerRequest.tools,
hasApiKey: !!providerRequest.apiKey,
apiKeyFirstChars: providerRequest.apiKey ? providerRequest.apiKey.substring(0, 4) : 'NONE',
})
// Ensure context is properly formatted for the provider
const response = await executeProviderRequest(providerId, providerRequest)
console.log(`[AgentBlockHandler Debug] Provider response:`, {
content: response.content,
contentType: typeof response.content,
logger.info(`Provider response received`, {
contentLength: response.content ? response.content.length : 0,
model: response.model,
hasTokens: !!response.tokens,
hasToolCalls: !!response.toolCalls,
toolCallsCount: response.toolCalls?.length || 0,
})
// For structured responses, try to parse the content
if (responseFormat) {
try {
console.log(
`[AgentBlockHandler Debug] Attempting to parse response content as JSON:`,
response.content
)
const parsedContent = JSON.parse(response.content)
console.log(`[AgentBlockHandler Debug] Successfully parsed content:`, parsedContent)
const result = {
response: {
@@ -338,11 +279,10 @@ export class AgentBlockHandler implements BlockHandler {
},
}
console.log(`[AgentBlockHandler Debug] Result:`, result)
return result
} catch (error) {
console.error(`[AgentBlockHandler Error] Failed to parse response content:`, error)
console.log(`[AgentBlockHandler Debug] Falling back to standard response format`)
logger.error(`Failed to parse response content:`, { error })
logger.info(`Falling back to standard response format`)
// Fall back to standard response if parsing fails
return {
@@ -561,7 +501,7 @@ export class ConditionBlockHandler implements BlockHandler {
}
}
} catch (error: any) {
console.error(`Failed to evaluate condition: ${error.message}`, {
logger.error(`Failed to evaluate condition: ${error.message}`, {
condition,
error,
})
@@ -641,7 +581,7 @@ export class EvaluatorBlockHandler implements BlockHandler {
processedContent = String(inputs.content || '')
}
} catch (e) {
console.error('Error processing content:', e)
logger.error('Error processing content:', e)
processedContent = String(inputs.content || '')
}
@@ -732,12 +672,12 @@ export class EvaluatorBlockHandler implements BlockHandler {
try {
parsedContent = JSON.parse(jsonStr)
} catch (parseError) {
console.error('Failed to parse extracted JSON:', parseError)
logger.error('Failed to parse extracted JSON:', parseError)
throw new Error('Invalid JSON in response')
}
} catch (error) {
console.error('Error parsing evaluator response:', error)
console.error('Raw response content:', response.content)
logger.error('Error parsing evaluator response:', error)
logger.error('Raw response content:', response.content)
// Fallback to empty object
parsedContent = {}
@@ -770,7 +710,7 @@ export class EvaluatorBlockHandler implements BlockHandler {
if (matchingKey) {
metricScores[metricName] = Number(parsedContent[matchingKey])
} else {
console.warn(`Metric "${metricName}" not found in LLM response`)
logger.warn(`Metric "${metricName}" not found in LLM response`)
metricScores[metricName] = 0
}
}
@@ -782,7 +722,7 @@ export class EvaluatorBlockHandler implements BlockHandler {
})
}
} catch (e) {
console.error('Error extracting metric scores:', e)
logger.error('Error extracting metric scores:', e)
}
// Create result with metrics as direct fields for easy access
+4 -1
View File
@@ -1,3 +1,4 @@
import { createLogger } from '@/lib/logs/console-logger'
import { useConsoleStore } from '@/stores/console/store'
import { useExecutionStore } from '@/stores/execution/store'
import { BlockOutput } from '@/blocks/types'
@@ -17,6 +18,8 @@ import { PathTracker } from './path'
import { InputResolver } from './resolver'
import { BlockLog, ExecutionContext, ExecutionResult, NormalizedBlockOutput } from './types'
const logger = createLogger('Executor')
/**
* Core execution engine that runs workflow blocks in topological order.
*
@@ -111,7 +114,7 @@ export class Executor {
logs: context.blockLogs,
}
} catch (error: any) {
console.error('Workflow execution failed:', error)
logger.error('Workflow execution failed:', { error })
return {
success: false,
+5 -2
View File
@@ -4,14 +4,17 @@ import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { nextCookies } from 'better-auth/next-js'
import { emailOTP, genericOAuth } from 'better-auth/plugins'
import { Resend } from 'resend'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import * as schema from '@/db/schema'
const logger = createLogger('Auth')
// If there is no resend key, it might be a local dev environment
// In that case, we don't want to send emails and just log them
const resend = process.env.RESEND_API_KEY
? new Resend(process.env.RESEND_API_KEY)
: { emails: { send: async (...args: any[]) => console.log(args) } }
: { emails: { send: async (...args: any[]) => logger.info('Email sent:', args) } }
export const auth = betterAuth({
database: drizzleAdapter(db, {
@@ -93,7 +96,7 @@ export const auth = betterAuth({
throw new Error('Failed to send verification code')
}
} catch (error) {
console.error('Error sending verification code:', {
logger.error('Error sending verification code:', {
error,
email: data.email,
otp: data.otp,
+5 -2
View File
@@ -1,8 +1,11 @@
import { v4 as uuidv4 } from 'uuid'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { workflowLogs } from '@/db/schema'
import { ExecutionResult as ExecutorResult } from '@/executor/types'
const logger = createLogger('ExecutionLogger')
export interface LogEntry {
id: string
workflowId: string
@@ -69,7 +72,7 @@ export async function persistExecutionLogs(
createdAt: new Date(),
})
} catch (error: any) {
console.error(`Error persisting execution logs: ${error.message}`, error)
logger.error(`Error persisting execution logs: ${error.message}`, { error })
}
}
@@ -100,7 +103,7 @@ export async function persistExecutionError(
createdAt: new Date(),
})
} catch (logError: any) {
console.error(`Error persisting execution error log: ${logError.message}`, logError)
logger.error(`Error persisting execution error log: ${logError.message}`, { logError })
}
}
+5 -2
View File
@@ -10,6 +10,9 @@ import {
SupabaseIcon,
xIcon,
} from '@/components/icons'
import { createLogger } from '@/lib/logs/console-logger'
const logger = createLogger('OAuth')
// Define the base OAuth provider type
export type OAuthProvider = 'google' | 'github' | 'x' | 'supabase' | string
@@ -329,14 +332,14 @@ export async function refreshOAuthToken(
if (!response.ok) {
const errorText = await response.text()
console.error('Token refresh failed:', response.status, errorText)
logger.error('Token refresh failed:', { status: response.status, error: errorText })
throw new Error(`Failed to refresh token: ${response.status} ${errorText}`)
}
const data = await response.json()
return data.access_token || null
} catch (error) {
console.error('Error refreshing token:', error)
logger.error('Error refreshing token:', { error })
return null
}
}
+10 -9
View File
@@ -1,4 +1,7 @@
import Redis from 'ioredis'
import { createLogger } from '@/lib/logs/console-logger'
const logger = createLogger('Redis')
// Default to localhost if REDIS_URL is not provided
const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379'
@@ -34,7 +37,7 @@ export function getRedisClient(): Redis | null {
// Retry strategy with exponential backoff
retryStrategy: (times) => {
if (times > 5) {
console.warn('Redis connection failed after 5 attempts, using fallback')
logger.warn('Redis connection failed after 5 attempts, using fallback')
return null // Stop retrying
}
return Math.min(times * 200, 2000) // Exponential backoff
@@ -43,19 +46,17 @@ export function getRedisClient(): Redis | null {
// Handle connection events
globalRedisClient.on('error', (err: any) => {
console.error('Redis connection error:', err)
logger.error('Redis connection error:', { err })
if (err.code === 'ECONNREFUSED' || err.code === 'ETIMEDOUT') {
globalRedisClient = null
}
})
globalRedisClient.on('connect', () => {
console.log('Connected to Redis')
})
globalRedisClient.on('connect', () => {})
return globalRedisClient
} catch (error) {
console.error('Failed to initialize Redis client:', error)
logger.error('Failed to initialize Redis client:', { error })
return null
}
}
@@ -92,7 +93,7 @@ export async function hasProcessedMessage(messageId: string): Promise<boolean> {
return true
}
} catch (error) {
console.error('Error checking message ID:', error)
logger.error('Error checking message ID:', { error })
// Fallback to in-memory cache on error
const cacheEntry = inMemoryCache.get(messageId)
return !!cacheEntry && (!cacheEntry.expiry || cacheEntry.expiry > Date.now())
@@ -145,7 +146,7 @@ export async function markMessageAsProcessed(
}
}
} catch (error) {
console.error('Error marking message as processed:', error)
logger.error('Error marking message as processed:', { error })
// Fallback to in-memory cache on error
const expiry = expirySeconds ? Date.now() + expirySeconds * 1000 : null
inMemoryCache.set(messageId, { value: '1', expiry })
@@ -161,7 +162,7 @@ export async function closeRedisConnection(): Promise<void> {
try {
await globalRedisClient.quit()
} catch (error) {
console.error('Error closing Redis connection:', error)
logger.error('Error closing Redis connection:', { error })
} finally {
globalRedisClient = null
}
+4 -1
View File
@@ -1,6 +1,9 @@
import { type ClassValue, clsx } from 'clsx'
import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto'
import { twMerge } from 'tailwind-merge'
import { createLogger } from '@/lib/logs/console-logger'
const logger = createLogger('Utils')
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
@@ -64,7 +67,7 @@ export async function decryptSecret(encryptedValue: string): Promise<{ decrypted
return { decrypted }
} catch (error: any) {
console.error('Decryption error:', error.message)
logger.error('Decryption error:', { error: error.message })
throw error
}
}
+11 -8
View File
@@ -1,5 +1,8 @@
import { WebContainer } from '@webcontainer/api'
import { auth } from '@webcontainer/api'
import { createLogger } from '@/lib/logs/console-logger'
const logger = createLogger('WebContainer')
// Singleton instance of WebContainer
let webcontainerInstance: WebContainer | null = null
@@ -33,7 +36,7 @@ async function initializeAuth() {
scope: '',
})
} catch (error) {
console.error('Failed to initialize WebContainer auth:', error)
logger.error('Failed to initialize WebContainer auth:', { error })
throw error
}
}
@@ -60,7 +63,7 @@ export async function getWebContainer(): Promise<WebContainer> {
// Check if cross-origin isolation is enabled
if (!isCrossOriginIsolated()) {
console.warn('Cross-Origin Isolation is not enabled. WebContainers require COOP/COEP headers.')
logger.warn('Cross-Origin Isolation is not enabled. WebContainers require COOP/COEP headers.')
throw new Error(
'WebContainers require cross-origin isolation. Please restart the server for changes to take effect.'
)
@@ -86,7 +89,7 @@ export async function getWebContainer(): Promise<WebContainer> {
return webcontainerInstance
} catch (error) {
console.error('WebContainer boot error:', error)
logger.error('WebContainer boot error:', { error })
isBooting = false
bootPromise = null
throw error
@@ -262,7 +265,7 @@ export async function executeCode(
// Don't resolve yet - wait for process to exit
} catch (error) {
console.error('Failed to parse result', error)
logger.error('Failed to parse result', { error })
reject(error)
}
}
@@ -286,7 +289,7 @@ export async function executeCode(
process.stderr.pipeTo(
new WritableStream({
write(data) {
console.error('WebContainer executeCode - Process error:', data)
logger.error('WebContainer executeCode - Process error:', { data })
stdout += `ERROR: ${data}\n`
},
})
@@ -297,7 +300,7 @@ export async function executeCode(
const timeoutPromise = new Promise<void>((_, reject) => {
setTimeout(() => {
if (!processCompleted) {
console.error('WebContainer executeCode - Process timed out after', timeout, 'ms')
logger.error('WebContainer executeCode - Process timed out after', timeout, 'ms')
reject(new Error(`Execution timed out after ${timeout}ms`))
}
}, timeout)
@@ -322,7 +325,7 @@ export async function executeCode(
},
}
} catch (error: any) {
console.error('WebContainer executeCode - Execution failed:', {
logger.error('WebContainer executeCode - Execution failed:', {
error: error.message,
name: error.name,
stack: error.stack,
@@ -334,7 +337,7 @@ export async function executeCode(
try {
await process.kill()
} catch (killError) {
console.error('WebContainer executeCode - Failed to kill process:', killError)
logger.error('WebContainer executeCode - Failed to kill process:', { killError })
}
}
+6 -3
View File
@@ -1,7 +1,10 @@
import Anthropic from '@anthropic-ai/sdk'
import { createLogger } from '@/lib/logs/console-logger'
import { executeTool } from '@/tools'
import { ProviderConfig, ProviderRequest, ProviderResponse } from '../types'
const logger = createLogger('Anthropic Provider')
export const anthropicProvider: ProviderConfig = {
id: 'anthropic',
name: 'Anthropic',
@@ -264,7 +267,7 @@ ${fieldDescriptions}
],
})
} catch (error) {
console.error('Error processing tool call:', error)
logger.error('Error processing tool call:', { error })
}
}
@@ -298,7 +301,7 @@ ${fieldDescriptions}
iterationCount++
}
} catch (error) {
console.error('Error in Anthropic request:', error)
logger.error('Error in Anthropic request:', { error })
throw error
}
@@ -310,7 +313,7 @@ ${fieldDescriptions}
content = jsonMatch[0]
}
} catch (e) {
console.error('Error extracting JSON from response:', e)
logger.error('Error extracting JSON from response:', { error: e })
}
}
+6 -4
View File
@@ -1,7 +1,10 @@
import { Cerebras } from '@cerebras/cerebras_cloud_sdk'
import { createLogger } from '@/lib/logs/console-logger'
import { executeTool } from '@/tools'
import { ProviderConfig, ProviderRequest, ProviderResponse } from '../types'
const logger = createLogger('Cerebras Provider')
export const cerebrasProvider: ProviderConfig = {
id: 'cerebras',
name: 'Cerebras',
@@ -175,7 +178,7 @@ export const cerebrasProvider: ProviderConfig = {
content: JSON.stringify(result.output),
})
} catch (error) {
console.error('Error processing tool call:', error)
logger.error('Error processing tool call:', { error })
}
}
@@ -230,8 +233,7 @@ export const cerebrasProvider: ProviderConfig = {
}
}
} catch (error) {
console.error('Error in Cerebras tool processing:', error)
// Don't throw here, return what we have so far
logger.error('Error in Cerebras tool processing:', { error })
}
return {
@@ -242,7 +244,7 @@ export const cerebrasProvider: ProviderConfig = {
toolResults: toolResults.length > 0 ? toolResults : undefined,
}
} catch (error) {
console.error('Error in Cerebras request:', error)
logger.error('Error in Cerebras request:', { error })
throw error
}
},
+5 -2
View File
@@ -1,7 +1,10 @@
import OpenAI from 'openai'
import { createLogger } from '@/lib/logs/console-logger'
import { executeTool } from '@/tools'
import { ProviderConfig, ProviderRequest, ProviderResponse } from '../types'
const logger = createLogger('Deepseek Provider')
export const deepseekProvider: ProviderConfig = {
id: 'deepseek',
name: 'Deepseek',
@@ -148,7 +151,7 @@ export const deepseekProvider: ProviderConfig = {
content: JSON.stringify(result.output),
})
} catch (error) {
console.error('Error processing tool call:', error)
logger.error('Error processing tool call:', { error })
}
}
@@ -179,7 +182,7 @@ export const deepseekProvider: ProviderConfig = {
iterationCount++
}
} catch (error) {
console.error('Error in Deepseek request:', error)
logger.error('Error in Deepseek request:', { error })
throw error
}
+5 -2
View File
@@ -1,7 +1,10 @@
import OpenAI from 'openai'
import { createLogger } from '@/lib/logs/console-logger'
import { executeTool } from '@/tools'
import { ProviderConfig, ProviderRequest, ProviderResponse } from '../types'
const logger = createLogger('Google Provider')
export const googleProvider: ProviderConfig = {
id: 'google',
name: 'Google',
@@ -149,7 +152,7 @@ export const googleProvider: ProviderConfig = {
content: toolResultContent,
})
} catch (error) {
console.error('Error processing tool call:', error)
logger.error('Error processing tool call:', { error })
}
}
@@ -177,7 +180,7 @@ export const googleProvider: ProviderConfig = {
iterationCount++
}
} catch (error) {
console.error('Error in Google Gemini request:', error)
logger.error('Error in Google Gemini request:', { error })
throw error
}
+5 -2
View File
@@ -1,7 +1,10 @@
import { Groq } from 'groq-sdk'
import { createLogger } from '@/lib/logs/console-logger'
import { executeTool } from '@/tools'
import { ProviderConfig, ProviderRequest, ProviderResponse } from '../types'
const logger = createLogger('Groq Provider')
export const groqProvider: ProviderConfig = {
id: 'groq',
name: 'Groq',
@@ -146,7 +149,7 @@ export const groqProvider: ProviderConfig = {
content: JSON.stringify(result.output),
})
} catch (error) {
console.error('Error processing tool call:', error)
logger.error('Error processing tool call:', { error })
}
}
@@ -174,7 +177,7 @@ export const groqProvider: ProviderConfig = {
iterationCount++
}
} catch (error) {
console.error('Error in Groq request:', error)
logger.error('Error in Groq request:', { error })
throw error
}
+13 -11
View File
@@ -1,6 +1,9 @@
import { createLogger } from '@/lib/logs/console-logger'
import { supportsTemperature } from './model-capabilities'
import { ProviderRequest, ProviderResponse } from './types'
import { generateStructuredOutputInstructions, getProvider, getProviderFromModel } from './utils'
import { generateStructuredOutputInstructions, getProvider } from './utils'
const logger = createLogger('Providers')
// Sanitize the request by removing parameters that aren't supported by the model
function sanitizeRequest(request: ProviderRequest): ProviderRequest {
@@ -19,8 +22,10 @@ export async function executeProviderRequest(
providerId: string,
request: ProviderRequest
): Promise<ProviderResponse> {
console.log(`[Provider Debug] Executing request with provider: ${providerId}`)
console.log(`[Provider Debug] Request has responseFormat:`, !!request.responseFormat)
logger.info(`Executing request with provider: ${providerId}`, {
hasResponseFormat: !!request.responseFormat,
model: request.model,
})
const provider = getProvider(providerId)
if (!provider) {
@@ -39,24 +44,21 @@ export async function executeProviderRequest(
typeof sanitizedRequest.responseFormat === 'string' &&
sanitizedRequest.responseFormat === ''
) {
console.log(`[Provider Debug] Response format is an empty string, ignoring it`)
logger.info(`Empty response format provided, ignoring it`)
sanitizedRequest.responseFormat = undefined
} else {
console.log(`[Provider Debug] Response format:`, sanitizedRequest.responseFormat)
// Generate structured output instructions
const structuredOutputInstructions = generateStructuredOutputInstructions(
sanitizedRequest.responseFormat
)
console.log(`[Provider Debug] Generated instructions:`, structuredOutputInstructions)
// Only add additional instructions if they're not empty
if (structuredOutputInstructions.trim()) {
const originalPrompt = sanitizedRequest.systemPrompt || ''
sanitizedRequest.systemPrompt =
`${originalPrompt}\n\n${structuredOutputInstructions}`.trim()
console.log(`[Provider Debug] Updated system prompt with instructions`)
logger.info(`Added structured output instructions to system prompt`)
}
}
}
@@ -64,12 +66,12 @@ export async function executeProviderRequest(
// Execute the request using the provider's implementation
const response = await provider.executeRequest(sanitizedRequest)
console.log(`[Provider Debug] Provider response:`, {
contentType: typeof response.content,
logger.info(`Provider response received`, {
contentLength: response.content ? response.content.length : 0,
model: response.model,
hasTokens: !!response.tokens,
hasToolCalls: !!response.toolCalls,
toolCallsCount: response.toolCalls?.length || 0,
})
return response
+24 -21
View File
@@ -1,7 +1,10 @@
import OpenAI from 'openai'
import { createLogger } from '@/lib/logs/console-logger'
import { executeTool } from '@/tools'
import { ProviderConfig, ProviderRequest, ProviderResponse } from '../types'
const logger = createLogger('OpenAI Provider')
export const openaiProvider: ProviderConfig = {
id: 'openai',
name: 'OpenAI',
@@ -11,20 +14,25 @@ export const openaiProvider: ProviderConfig = {
defaultModel: 'gpt-4o',
executeRequest: async (request: ProviderRequest): Promise<ProviderResponse> => {
console.log('Full request:', request)
logger.info('Preparing OpenAI request', {
model: request.model || 'gpt-4o',
hasSystemPrompt: !!request.systemPrompt,
hasMessages: !!request.messages?.length,
hasTools: !!request.tools?.length,
toolCount: request.tools?.length || 0,
hasResponseFormat: !!request.responseFormat,
})
if (!request.apiKey) {
console.error('OpenAI API key missing in request. Request details:', {
logger.error('OpenAI API key missing in request', {
hasModel: !!request.model,
hasSystemPrompt: !!request.systemPrompt,
hasMessages: !!request.messages,
hasTools: !!request.tools,
requestKeys: Object.keys(request),
})
throw new Error('API key is required for OpenAI')
}
console.log('OpenAI API key found in request (first 4 chars):', request.apiKey.substring(0, 4))
const openai = new OpenAI({
apiKey: request.apiKey,
dangerouslyAllowBrowser: true,
@@ -78,15 +86,6 @@ export const openaiProvider: ProviderConfig = {
// Add response format for structured output if specified
if (request.responseFormat) {
// Log detailed information about the responseFormat
console.log(`[OpenAI Provider Debug] Response format details:`, {
type: typeof request.responseFormat,
isString: typeof request.responseFormat === 'string',
hasSchema: request.responseFormat.schema !== undefined,
hasName: request.responseFormat.name !== undefined,
value: JSON.stringify(request.responseFormat),
})
// Use OpenAI's JSON schema format
payload.response_format = {
type: 'json_schema',
@@ -97,17 +96,14 @@ export const openaiProvider: ProviderConfig = {
},
}
// Log the final response_format being sent to OpenAI
console.log(
`[OpenAI Provider Debug] Final response_format:`,
JSON.stringify(payload.response_format)
)
logger.info('Added JSON schema response format to request')
}
// Add tools if provided
if (tools?.length) {
payload.tools = tools
payload.tool_choice = 'auto'
logger.info(`Configured ${tools.length} tools for OpenAI request`)
}
// Make the initial API request
@@ -132,6 +128,10 @@ export const openaiProvider: ProviderConfig = {
break
}
logger.info(
`Processing ${toolCallsInResponse.length} tool calls (iteration ${iterationCount + 1}/${MAX_ITERATIONS})`
)
// Process each tool call
for (const toolCall of toolCallsInResponse) {
try {
@@ -176,7 +176,10 @@ export const openaiProvider: ProviderConfig = {
content: JSON.stringify(result.output),
})
} catch (error) {
console.error('Error processing tool call:', error)
logger.error('Error processing tool call:', {
error,
toolName: toolCall?.function?.name,
})
}
}
@@ -204,7 +207,7 @@ export const openaiProvider: ProviderConfig = {
iterationCount++
}
} catch (error) {
console.error('Error in OpenAI request:', error)
logger.error('Error in OpenAI request:', { error })
throw error
}
+34 -7
View File
@@ -1,3 +1,4 @@
import { createLogger } from '@/lib/logs/console-logger'
import { useCustomToolsStore } from '@/stores/custom-tools/store'
import { anthropicProvider } from './anthropic'
import { cerebrasProvider } from './cerebras'
@@ -8,6 +9,8 @@ import { openaiProvider } from './openai'
import { ProviderConfig, ProviderId, ProviderToolConfig } from './types'
import { xAIProvider } from './xai'
const logger = createLogger('ProviderUtils')
/**
* Provider configurations with associated model names/patterns
*/
@@ -89,6 +92,7 @@ export function getProviderFromModel(model: string): ProviderId {
}
}
logger.warn(`No provider found for model: ${model}, defaulting to deepseek`)
return 'deepseek'
}
@@ -161,6 +165,8 @@ export function generateStructuredOutputInstructions(responseFormat: any): strin
})
.join('\n')
logger.info(`Generated structured output instructions for ${responseFormat.fields.length} fields`)
return `
Please provide your response in the following JSON format:
{
@@ -201,9 +207,13 @@ export function extractAndParseJSON(content: string): any {
try {
return JSON.parse(cleaned)
} catch (innerError) {
console.error('Original content:', content)
console.error('Extracted JSON:', jsonStr)
console.error('Cleaned JSON:', cleaned)
logger.error('Failed to parse JSON response', {
contentLength: content.length,
extractedLength: jsonStr.length,
cleanedLength: cleaned.length,
error: innerError instanceof Error ? innerError.message : 'Unknown error',
})
throw new Error(
`Failed to parse JSON after cleanup: ${innerError instanceof Error ? innerError.message : 'Unknown error'}`
)
@@ -241,6 +251,10 @@ export function getCustomTools(): ProviderToolConfig[] {
// Get custom tools from the store
const customTools = useCustomToolsStore.getState().getAllTools()
if (customTools.length > 0) {
logger.info(`Found ${customTools.length} custom tools`)
}
// Transform each custom tool into a provider tool config
return customTools.map(transformCustomTool)
}
@@ -264,7 +278,10 @@ export function transformBlockTool(
// Get the block definition
const blockDef = getAllBlocks().find((b: any) => b.type === block.type)
if (!blockDef) return null
if (!blockDef) {
logger.warn(`Block definition not found for type: ${block.type}`)
return null
}
// If the block has multiple operations, use the selected one or the first one
let toolId: string | null = null
@@ -279,7 +296,11 @@ export function transformBlockTool(
operation: selectedOperation,
})
} catch (error) {
console.error('Error selecting tool:', error)
logger.error('Error selecting tool for block', {
blockType: block.type,
operation: selectedOperation,
error,
})
return null
}
} else {
@@ -291,11 +312,17 @@ export function transformBlockTool(
toolId = blockDef.tools?.access?.[0] || null
}
if (!toolId) return null
if (!toolId) {
logger.warn(`No tool ID found for block: ${block.type}`)
return null
}
// Get the tool config
const toolConfig = getTool(toolId)
if (!toolConfig) return null
if (!toolConfig) {
logger.warn(`Tool config not found for ID: ${toolId}`)
return null
}
// Return formatted tool config
return {
+5 -2
View File
@@ -1,7 +1,10 @@
import OpenAI from 'openai'
import { createLogger } from '@/lib/logs/console-logger'
import { executeTool } from '@/tools'
import { ProviderConfig, ProviderRequest, ProviderResponse } from '../types'
const logger = createLogger('XAI Provider')
export const xAIProvider: ProviderConfig = {
id: 'xai',
name: 'xAI',
@@ -145,7 +148,7 @@ export const xAIProvider: ProviderConfig = {
content: JSON.stringify(result.output),
})
} catch (error) {
console.error('Error processing tool call:', error)
logger.error('Error processing tool call:', { error })
}
}
@@ -169,7 +172,7 @@ export const xAIProvider: ProviderConfig = {
iterationCount++
}
} catch (error) {
console.error('Error in xAI request:', error)
logger.error('Error in xAI request:', { error })
throw error
}
+6 -3
View File
@@ -1,7 +1,10 @@
import { Edge } from 'reactflow'
import { BlockState, Loop, SubBlockState } from '@/stores/workflows/workflow/types'
import { createLogger } from '@/lib/logs/console-logger'
import { BlockState, Loop } from '@/stores/workflows/workflow/types'
import { getBlock } from '@/blocks'
import { SerializedBlock, SerializedConnection, SerializedWorkflow } from './types'
import { SerializedBlock, SerializedWorkflow } from './types'
const logger = createLogger('Serializer')
export class Serializer {
serializeWorkflow(
@@ -48,7 +51,7 @@ export class Serializer {
: blockConfig.tools.access[0]
}
} catch (error) {
console.error('Error processing tools in agent block:', error)
logger.error('Error processing tools in agent block:', { error })
// Default to the first tool if we can't process tools
toolId = blockConfig.tools.access[0]
}
+4 -3
View File
@@ -1,10 +1,13 @@
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'
import { createLogger } from '@/lib/logs/console-logger'
import { useEnvironmentStore } from '../settings/environment/store'
import { useWorkflowStore } from '../workflows/workflow/store'
import { ChatMessage, ChatStore } from './types'
import { calculateBlockPosition, getNextBlockNumber } from './utils'
const logger = createLogger('Chat Store')
export const useChatStore = create<ChatStore>()(
devtools(
(set, get) => ({
@@ -71,8 +74,6 @@ export const useChatStore = create<ChatStore>()(
const data = await response.json()
console.log('OPENAI RESPONSE', data)
// Handle any actions returned from the API
if (data.actions) {
// Process all block additions first to properly calculate positions
@@ -135,7 +136,7 @@ export const useChatStore = create<ChatStore>()(
}))
}
} catch (error) {
console.error('Chat error:', error)
logger.error('Chat error:', { error })
set({ error: error instanceof Error ? error.message : 'Unknown error' })
} finally {
set({ isProcessing: false })
+12 -17
View File
@@ -1,4 +1,5 @@
import { useEffect } from 'react'
import { createLogger } from '@/lib/logs/console-logger'
import { useChatStore } from './chat/store'
import { useConsoleStore } from './console/store'
import { useCustomToolsStore } from './custom-tools/store'
@@ -17,6 +18,8 @@ import { useWorkflowRegistry } from './workflows/registry/store'
import { useSubBlockStore } from './workflows/subblock/store'
import { useWorkflowStore } from './workflows/workflow/store'
const logger = createLogger('Stores')
// Track initialization state
let isInitializing = false
@@ -47,7 +50,7 @@ async function initializeApplication(): Promise<void> {
// No workflows loaded from DB, try localStorage as fallback
const workflows = loadRegistry()
if (workflows && Object.keys(workflows).length > 0) {
console.log('Loading workflows from localStorage as fallback')
logger.info('Loading workflows from localStorage as fallback')
useWorkflowRegistry.setState({ workflows })
const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
@@ -56,13 +59,13 @@ async function initializeApplication(): Promise<void> {
}
}
} else {
console.log('Using workflows loaded from DB, ignoring localStorage')
logger.info('Using workflows loaded from DB, ignoring localStorage')
}
// 2. Register cleanup
window.addEventListener('beforeunload', handleBeforeUnload)
} catch (error) {
console.error('Error during application initialization:', error)
logger.error('Error during application initialization:', { error })
} finally {
isInitializing = false
}
@@ -72,7 +75,7 @@ function initializeWorkflowState(workflowId: string): void {
// Load the specific workflow state from localStorage
const workflowState = loadWorkflowState(workflowId)
if (!workflowState) {
console.warn(`No saved state found for workflow ${workflowId}`)
logger.warn(`No saved state found for workflow ${workflowId}`)
return
}
@@ -94,7 +97,7 @@ function initializeWorkflowState(workflowId: string): void {
useSubBlockStore.getState().initializeFromWorkflow(workflowId, workflowState.blocks)
}
console.log(`Initialized workflow state for ${workflowId}`)
logger.info(`Initialized workflow state for ${workflowId}`)
}
/**
@@ -167,9 +170,9 @@ export async function clearUserData(): Promise<void> {
const keysToRemove = Object.keys(localStorage).filter((key) => !keysToKeep.includes(key))
keysToRemove.forEach((key) => localStorage.removeItem(key))
console.log('User data cleared successfully')
logger.info('User data cleared successfully')
} catch (error) {
console.error('Error clearing user data:', error)
logger.error('Error clearing user data:', { error })
}
}
@@ -247,14 +250,6 @@ export const logAllStores = () => {
subBlock: useSubBlockStore.getState(),
}
console.group('Application State')
Object.entries(state).forEach(([storeName, storeState]) => {
console.group(storeName)
console.log(storeState)
console.groupEnd()
})
console.groupEnd()
return state
}
@@ -275,8 +270,8 @@ export async function reinitializeAfterLogin(): Promise<void> {
// Reinitialize the application
await initializeApplication()
console.log('Application reinitialized after login')
logger.info('Application reinitialized after login')
} catch (error) {
console.error('Error reinitializing application:', error)
logger.error('Error reinitializing application:', { error })
}
}
+5 -2
View File
@@ -1,7 +1,10 @@
import { create } from 'zustand'
import { createLogger } from '@/lib/logs/console-logger'
import { API_ENDPOINTS } from '../../constants'
import { EnvironmentStore, EnvironmentVariable } from './types'
const logger = createLogger('Environment Store')
export const useEnvironmentStore = create<EnvironmentStore>()((set, get) => ({
variables: {},
isLoading: false,
@@ -32,7 +35,7 @@ export const useEnvironmentStore = create<EnvironmentStore>()((set, get) => ({
})
}
} catch (error) {
console.error('Error loading environment variables:', error)
logger.error('Error loading environment variables:', { error })
set({
error: error instanceof Error ? error.message : 'Unknown error',
isLoading: false,
@@ -80,7 +83,7 @@ export const useEnvironmentStore = create<EnvironmentStore>()((set, get) => ({
set({ isLoading: false })
} catch (error) {
console.error('Error saving environment variables:', error)
logger.error('Error saving environment variables:', { error })
set({
error: error instanceof Error ? error.message : 'Unknown error',
isLoading: false,
+5 -1
View File
@@ -1,3 +1,7 @@
import { createLogger } from '@/lib/logs/console-logger'
const logger = createLogger('Sync Core')
/**
* Core sync types and utilities for optimistic state synchronization
*/
@@ -73,7 +77,7 @@ export async function performSync(config: SyncConfig): Promise<boolean> {
if (config.onSyncError) {
config.onSyncError(error)
}
console.error(`Sync error: ${error}`)
logger.error(`Sync error: ${error}`)
return false
}
}
+5 -2
View File
@@ -1,9 +1,12 @@
'use client'
import { createLogger } from '@/lib/logs/console-logger'
import { SyncManager } from './sync'
import { isLocalStorageMode } from './sync-core'
import { fetchWorkflowsFromDB, workflowSync } from './workflows/sync'
const logger = createLogger('Sync Registry')
// Initialize managers lazily
let initialized = false
let initializing = false
@@ -42,13 +45,13 @@ export async function initializeSyncManagers(): Promise<boolean> {
// Remove environment variables fetch
await fetchWorkflowsFromDB()
} catch (error) {
console.error('Error fetching data from DB:', error)
logger.error('Error fetching data from DB:', { error })
}
initialized = true
return true
} catch (error) {
console.error('Error initializing sync managers:', error)
logger.error('Error initializing sync managers:', { error })
return false
} finally {
initializing = false
+6 -3
View File
@@ -1,6 +1,7 @@
'use client'
import { useEffect } from 'react'
import { createLogger } from '@/lib/logs/console-logger'
import { SYNC_INTERVALS } from './constants'
import {
DEFAULT_SYNC_CONFIG,
@@ -10,6 +11,8 @@ import {
performSync,
} from './sync-core'
const logger = createLogger('Sync')
// Client-side sync manager with lifecycle and registry management
export interface SyncManager extends SyncOperations {
id: string
@@ -33,7 +36,7 @@ export function createSyncManager(config: SyncConfig): SyncManager {
// Optimistic sync - fire and forget
const sync = (): void => {
performSync(fullConfig).catch((err) => {
console.error('Sync failed:', err)
logger.error('Sync failed:', { err })
})
}
@@ -146,7 +149,7 @@ export function createSingletonSyncManager(
return {
id: key,
config: configFactory(),
sync: () => console.log(`[LocalStorage Mode] Skipping sync for ${key}`),
sync: () => logger.info(`[LocalStorage Mode] Skipping sync for ${key}`),
startIntervalSync: () => {},
stopIntervalSync: () => {},
dispose: () => {},
@@ -168,7 +171,7 @@ export function createSingletonSyncManager(
config,
sync: () => {
performSync(config).catch((err) => {
console.error(`Sync failed for ${key}:`, err)
logger.error(`Sync failed for ${key}:`, { err })
})
},
startIntervalSync: () => {
+4 -1
View File
@@ -1,3 +1,4 @@
import { createLogger } from '@/lib/logs/console-logger'
import { loadWorkflowState } from './persistence'
import { useWorkflowRegistry } from './registry/store'
import { useSubBlockStore } from './subblock/store'
@@ -5,6 +6,8 @@ import { mergeSubblockState } from './utils'
import { useWorkflowStore } from './workflow/store'
import { BlockState, WorkflowState } from './workflow/types'
const logger = createLogger('Workflows')
// Get a specific block with its subblock values merged in
export function getBlockWithValues(blockId: string): BlockState | null {
const workflowState = useWorkflowStore.getState()
@@ -42,7 +45,7 @@ export function getAllWorkflowsWithValues() {
const savedState = loadWorkflowState(id)
if (!savedState) {
// Skip workflows with no saved state
console.warn(`No saved state found for workflow ${id}`)
logger.warn(`No saved state found for workflow ${id}`)
continue
}
workflowState = savedState
+6 -3
View File
@@ -2,11 +2,14 @@
* Centralized persistence layer for workflow stores
* Handles localStorage interactions and synchronization
*/
import { createLogger } from '@/lib/logs/console-logger'
import { STORAGE_KEYS } from '../constants'
import { useWorkflowRegistry } from './registry/store'
import { useSubBlockStore } from './subblock/store'
import { useWorkflowStore } from './workflow/store'
const logger = createLogger('Workflows Persistence')
/**
* Save data to localStorage with error handling
*/
@@ -15,7 +18,7 @@ export function saveToStorage<T>(key: string, data: T): boolean {
localStorage.setItem(key, JSON.stringify(data))
return true
} catch (error) {
console.error(`Failed to save data to ${key}:`, error)
logger.error(`Failed to save data to ${key}:`, { error })
return false
}
}
@@ -28,7 +31,7 @@ export function loadFromStorage<T>(key: string): T | null {
const data = localStorage.getItem(key)
return data ? JSON.parse(data) : null
} catch (error) {
console.error(`Failed to load data from ${key}:`, error)
logger.error(`Failed to load data from ${key}:`, { error })
return null
}
}
@@ -41,7 +44,7 @@ export function removeFromStorage(key: string): boolean {
localStorage.removeItem(key)
return true
} catch (error) {
console.error(`Failed to remove data from ${key}:`, error)
logger.error(`Failed to remove data from ${key}:`, { error })
return false
}
}
+6 -4
View File
@@ -1,8 +1,8 @@
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'
import { createLogger } from '@/lib/logs/console-logger'
import { API_ENDPOINTS, STORAGE_KEYS } from '../../constants'
import {
loadRegistry,
loadWorkflowState,
removeFromStorage,
saveRegistry,
@@ -15,6 +15,8 @@ import { useWorkflowStore } from '../workflow/store'
import { WorkflowMetadata, WorkflowRegistry } from './types'
import { generateUniqueName, getNextWorkflowColor } from './utils'
const logger = createLogger('Workflow Registry')
export const useWorkflowRegistry = create<WorkflowRegistry>()(
devtools(
(set, get) => ({
@@ -89,7 +91,7 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
lastSaved: parsedState.lastSaved || Date.now(),
})
console.log(`Switched to workflow ${id}`)
logger.info(`Switched to workflow ${id}`)
} else {
// If no saved state, initialize with empty state
useWorkflowStore.setState({
@@ -117,7 +119,7 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
lastSaved: Date.now(),
})
console.warn(`No saved state found for workflow ${id}, initialized with empty state`)
logger.warn(`No saved state found for workflow ${id}, initialized with empty state`)
}
// Update the active workflow ID
@@ -312,7 +314,7 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
state: { blocks: {} }, // Empty blocks will signal to cancel the schedule
}),
}).catch((error) => {
console.error(`Error cancelling schedule for deleted workflow ${id}:`, error)
logger.error(`Error cancelling schedule for deleted workflow ${id}:`, { error })
})
// Sync deletion with database
+17 -14
View File
@@ -1,5 +1,6 @@
'use client'
import { createLogger } from '@/lib/logs/console-logger'
import { getAllWorkflowsWithValues } from '.'
import { API_ENDPOINTS } from '../constants'
import { createSingletonSyncManager } from '../sync'
@@ -7,7 +8,9 @@ import { useWorkflowRegistry } from './registry/store'
import { WorkflowMetadata } from './registry/types'
import { useSubBlockStore } from './subblock/store'
import { useWorkflowStore } from './workflow/store'
import { BlockState, WorkflowState } from './workflow/types'
import { BlockState } from './workflow/types'
const logger = createLogger('Workflows Sync')
// Flag to prevent immediate sync back to DB after loading from DB
let isLoadingFromDB = false
@@ -52,7 +55,7 @@ async function updateWorkflowSchedule(workflowId: string, state: any): Promise<v
})
if (!response.ok) {
console.error(
logger.error(
`Failed to ${isScheduleEnabled ? 'update' : 'cancel'} schedule for workflow ${workflowId}:`,
response.statusText
)
@@ -64,13 +67,13 @@ async function updateWorkflowSchedule(workflowId: string, state: any): Promise<v
// Update our tracking of scheduled workflows
if (isScheduleEnabled) {
scheduledWorkflows.add(workflowId)
console.log(`Schedule updated for workflow ${workflowId}:`, result)
logger.info(`Schedule updated for workflow ${workflowId}:`, result)
} else {
scheduledWorkflows.delete(workflowId)
console.log(`Schedule cancelled for workflow ${workflowId}:`, result)
logger.info(`Schedule cancelled for workflow ${workflowId}:`, result)
}
} catch (error) {
console.error(`Error managing schedule for workflow ${workflowId}:`, error)
logger.error(`Error managing schedule for workflow ${workflowId}:`, { error })
}
}
@@ -92,18 +95,18 @@ export async function fetchWorkflowsFromDB(): Promise<void> {
if (!response.ok) {
if (response.status === 401) {
console.warn('User not authenticated for workflow fetch')
logger.warn('User not authenticated for workflow fetch')
return
}
console.error('Failed to fetch workflows:', response.statusText)
logger.error('Failed to fetch workflows:', response.statusText)
return
}
const { data } = await response.json()
if (!data || !Array.isArray(data) || data.length === 0) {
console.log('No workflows found in database')
logger.info('No workflows found in database')
return
}
@@ -204,9 +207,9 @@ export async function fetchWorkflowsFromDB(): Promise<void> {
}
}
console.log('Workflows loaded from DB:', Object.keys(registryWorkflows).length)
logger.info('Workflows loaded from DB:', Object.keys(registryWorkflows).length)
} catch (error) {
console.error('Error fetching workflows from DB:', error)
logger.error('Error fetching workflows from DB:', { error })
} finally {
// Reset the flag after a short delay to allow state to settle
setTimeout(() => {
@@ -223,7 +226,7 @@ export const workflowSync = createSingletonSyncManager('workflow-sync', () => ({
// Skip sync if we're currently loading from DB to prevent overwriting DB data
if (isLoadingFromDB) {
console.log('Skipping workflow sync while loading from DB')
logger.info('Skipping workflow sync while loading from DB')
return { skipSync: true }
}
@@ -232,7 +235,7 @@ export const workflowSync = createSingletonSyncManager('workflow-sync', () => ({
// Skip sync if there are no workflows to sync
if (Object.keys(workflowsData).length === 0) {
console.log('Skipping workflow sync - no workflows to sync')
logger.info('Skipping workflow sync - no workflows to sync')
return { skipSync: true }
}
@@ -244,7 +247,7 @@ export const workflowSync = createSingletonSyncManager('workflow-sync', () => ({
syncOnInterval: true,
syncOnExit: true,
onSyncSuccess: async (data) => {
console.log('Workflows synced to DB successfully')
logger.info('Workflows synced to DB successfully')
// After successful sync to DB, update schedules for all workflows
try {
@@ -273,7 +276,7 @@ export const workflowSync = createSingletonSyncManager('workflow-sync', () => ({
}
}
} catch (error) {
console.error('Error updating workflow schedules:', error)
logger.error('Error updating workflow schedules:', { error })
}
},
}))
+6 -7
View File
@@ -1,6 +1,9 @@
import { createLogger } from '@/lib/logs/console-logger'
import { ToolConfig } from '../types'
import { GoogleDocsCreateResponse, GoogleDocsToolParams } from './types'
const logger = createLogger('Google Docs Create Tool')
export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateResponse> = {
id: 'google_docs_create',
name: 'Create Google Docs Document',
@@ -55,7 +58,6 @@ export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateRespon
// The Google Docs API doesn't directly support content in the create request,
// so we need to add it separately via the write tool
if (result.success && params.content) {
console.log('Google Docs create - Post-processing: Adding content to document')
const documentId = result.output.metadata.documentId
if (documentId) {
@@ -65,21 +67,18 @@ export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateRespon
documentId: documentId,
content: params.content,
}
console.log('Content to add:', params.content)
// Use the write tool to add content
const writeResult = await executeTool('google_docs_write', writeParams)
if (!writeResult.success) {
console.warn(
logger.warn(
'Failed to add content to document, but document was created:',
writeResult.error
)
} else {
console.log('Google Docs create - Content added successfully')
}
} catch (error) {
console.warn('Error adding content to document:', error)
logger.warn('Error adding content to document:', { error })
// Don't fail the overall operation if adding content fails
}
}
@@ -126,7 +125,7 @@ export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateRespon
},
}
} catch (error) {
console.error('Google Docs create - Error processing response:', error)
logger.error('Google Docs create - Error processing response:', { error })
throw error
}
},
+7 -4
View File
@@ -1,7 +1,10 @@
import { createLogger } from '@/lib/logs/console-logger'
import { ToolConfig } from '../types'
import { GoogleDriveDownloadResponse } from './types'
import { GoogleDriveToolParams } from './types'
const logger = createLogger('Google Drive Export Tool')
export const exportTool: ToolConfig<
GoogleDriveToolParams & { mimeType?: string },
GoogleDriveDownloadResponse
@@ -33,7 +36,7 @@ export const exportTool: ToolConfig<
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json()
console.error('Google Drive export error:', {
logger.error('Google Drive export error:', {
status: response.status,
statusText: response.statusText,
error,
@@ -54,7 +57,7 @@ export const exportTool: ToolConfig<
if (!metadataResponse.ok) {
const metadataError = await metadataResponse.json()
console.error('Google Drive metadata error:', {
logger.error('Google Drive metadata error:', {
status: metadataResponse.status,
statusText: metadataResponse.statusText,
error: metadataError,
@@ -69,7 +72,7 @@ export const exportTool: ToolConfig<
try {
content = await response.text()
} catch (error: any) {
console.error('Error reading response content:', {
logger.error('Error reading response content:', {
message: error.message,
stack: error.stack,
error: JSON.stringify(error),
@@ -96,7 +99,7 @@ export const exportTool: ToolConfig<
}
},
transformError: (error: any) => {
console.error('Export tool error:', {
logger.error('Export tool error:', {
message: error.message,
stack: error.stack,
error: JSON.stringify(error, null, 2),
+14 -11
View File
@@ -1,3 +1,4 @@
import { createLogger } from '@/lib/logs/console-logger'
import { useCustomToolsStore } from '@/stores/custom-tools/store'
import { useEnvironmentStore } from '@/stores/settings/environment/store'
import { docsCreateTool, docsReadTool, docsWriteTool } from './docs'
@@ -34,6 +35,8 @@ import { whatsappSendMessageTool } from './whatsapp'
import { xReadTool, xSearchTool, xUserTool, xWriteTool } from './x'
import { youtubeSearchTool } from './youtube/search'
const logger = createLogger('Tools')
// Registry of all available tools
export const tools: Record<string, ToolConfig> = {
openai_embeddings: openAIEmbeddings,
@@ -130,7 +133,7 @@ function getCustomTool(customToolId: string): ToolConfig | undefined {
}
if (!customTool) {
console.error(`Custom tool not found: ${identifier}`)
logger.error(`Custom tool not found: ${identifier}`)
return undefined
}
@@ -255,7 +258,7 @@ function getCustomTool(customToolId: string): ToolConfig | undefined {
error: undefined,
}
} catch (error: any) {
console.warn('WebContainer execution failed, falling back to API:', error.message)
logger.warn('WebContainer execution failed, falling back to API:', error.message)
// Fall back to API route if WebContainer fails
return undefined
}
@@ -320,7 +323,7 @@ export async function executeTool(
try {
return await tool.postProcess(result, params, executeTool)
} catch (error) {
console.error(`Error in post-processing for tool ${toolId}:`, error)
logger.error(`Error in post-processing for tool ${toolId}:`, { error })
// Return original result if post-processing fails
return result
}
@@ -337,7 +340,7 @@ export async function executeTool(
try {
return await tool.postProcess(result, params, executeTool)
} catch (error) {
console.error(`Error in post-processing for tool ${toolId}:`, error)
logger.error(`Error in post-processing for tool ${toolId}:`, { error })
// Return original result if post-processing fails
return result
}
@@ -345,7 +348,7 @@ export async function executeTool(
return result
} catch (error: any) {
console.error(`Error executing tool ${toolId}:`, error)
logger.error(`Error executing tool ${toolId}:`, { error })
// For custom tools, provide more helpful error information
if (toolId.startsWith('custom_')) {
@@ -353,8 +356,8 @@ export async function executeTool(
const allTools = useCustomToolsStore.getState().getAllTools()
const availableTools = allTools.map((t) => ({ id: t.id, title: t.title }))
console.error('Available custom tools:', availableTools)
console.error(`Looking for custom tool with identifier: ${identifier}`)
logger.error('Available custom tools:', availableTools)
logger.error(`Looking for custom tool with identifier: ${identifier}`)
}
return {
@@ -428,7 +431,7 @@ async function handleInternalRequest(
error: undefined,
}
} catch (error: any) {
console.error(`Error executing internal tool ${toolId}:`, error)
logger.error(`Error executing internal tool ${toolId}:`, { error })
// Use the tool's error transformer if available
if (tool.transformError) {
@@ -474,7 +477,7 @@ async function handleInternalRequest(
}
}
} catch (transformError) {
console.error(`Error transforming error for tool ${toolId}:`, transformError)
logger.error(`Error transforming error for tool ${toolId}:`, { transformError })
return {
success: false,
output: {},
@@ -573,7 +576,7 @@ async function handleProxyRequest(
if (!response.ok) {
const errorText = await response.text()
console.error('Token fetch failed:', response.status, errorText)
logger.error('Token fetch failed:', response.status, errorText)
throw new Error(`Failed to fetch access token: ${response.status} ${errorText}`)
}
@@ -584,7 +587,7 @@ async function handleProxyRequest(
delete params.credential
if (params.workflowId) delete params.workflowId
} catch (error) {
console.error('Error fetching access token:', error)
logger.error('Error fetching access token:', { error })
throw error
}
}
-7
View File
@@ -31,12 +31,6 @@ export const insertTool: ToolConfig<SupabaseInsertParams, SupabaseInsertResponse
},
directExecution: async (params: SupabaseInsertParams) => {
try {
// This is a mock implementation
console.log(
`Inserting data into Supabase table ${params.table} in project ${params.projectId}`
)
console.log('Data to insert:', params.data)
// Mock response
const mockData = [{ ...params.data, id: Math.floor(Math.random() * 1000) }]
@@ -50,7 +44,6 @@ export const insertTool: ToolConfig<SupabaseInsertParams, SupabaseInsertResponse
error: null,
}
} catch (error) {
console.error('Error inserting into Supabase:', error)
return {
success: false,
output: {
-4
View File
@@ -33,9 +33,6 @@ export const queryTool: ToolConfig<SupabaseQueryParams, SupabaseQueryResponse> =
},
directExecution: async (params: SupabaseQueryParams) => {
try {
// This is a mock implementation
console.log(`Querying Supabase table ${params.table} in project ${params.projectId}`)
// Mock response
const mockData = [
{ id: 1, name: 'Item 1', description: 'Description 1' },
@@ -52,7 +49,6 @@ export const queryTool: ToolConfig<SupabaseQueryParams, SupabaseQueryResponse> =
error: null,
}
} catch (error) {
console.error('Error querying Supabase:', error)
return {
success: false,
output: {
-6
View File
@@ -33,11 +33,6 @@ export const updateTool: ToolConfig<SupabaseUpdateParams, SupabaseUpdateResponse
},
directExecution: async (params: SupabaseUpdateParams) => {
try {
// This is a mock implementation
console.log(`Updating data in Supabase table ${params.table} in project ${params.projectId}`)
console.log('Filter:', params.filter)
console.log('Data to update:', params.data)
// Mock response
const mockData = [{ ...params.data, id: params.filter.value }]
@@ -51,7 +46,6 @@ export const updateTool: ToolConfig<SupabaseUpdateParams, SupabaseUpdateResponse
error: null,
}
} catch (error) {
console.error('Error updating Supabase data:', error)
return {
success: false,
output: {
+4 -1
View File
@@ -1,6 +1,9 @@
import { createLogger } from '@/lib/logs/console-logger'
import { TableRow } from './types'
import { ToolConfig, ToolResponse } from './types'
const logger = createLogger('Tools Utils')
/**
* Transforms a table from the store format to a key-value object
* @param table Array of table rows from the store
@@ -108,7 +111,7 @@ export async function executeRequest(
}
} else {
const error = errorContent.message || `${toolId} API error: ${externalResponse.statusText}`
console.error(`${toolId} error:`, error)
logger.error(`${toolId} error:`, { error })
throw new Error(error)
}
}
+5 -2
View File
@@ -1,6 +1,9 @@
import { createLogger } from '@/lib/logs/console-logger'
import { ToolConfig } from '../types'
import { WhatsAppToolResponse } from './types'
const logger = createLogger('WhatsApp Send Message Tool')
export const sendMessageTool: ToolConfig<any, WhatsAppToolResponse> = {
id: 'whatsapp',
name: 'WhatsApp',
@@ -81,7 +84,7 @@ export const sendMessageTool: ToolConfig<any, WhatsAppToolResponse> = {
if (!response.ok) {
const errorMessage =
data.error?.message || `Failed to send WhatsApp message (HTTP ${response.status})`
console.error('WhatsApp API error:', data)
logger.error('WhatsApp API error:', data)
throw new Error(errorMessage)
}
@@ -96,7 +99,7 @@ export const sendMessageTool: ToolConfig<any, WhatsAppToolResponse> = {
},
transformError: (error) => {
console.error('WhatsApp tool error:', error)
logger.error('WhatsApp tool error:', { error })
return `WhatsApp message failed: ${error.message || 'Unknown error occurred'}`
},
}