Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/sim/app/(landing)/components/nav/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface NavProps {
}

export default function Nav({ hideAuthButtons = false, variant = 'landing' }: NavProps = {}) {
const [githubStars, setGithubStars] = useState('18.6k')
const [githubStars, setGithubStars] = useState('24k')
const [isHovered, setIsHovered] = useState(false)
const [isLoginHovered, setIsLoginHovered] = useState(false)
const router = useRouter()
Expand Down
54 changes: 35 additions & 19 deletions apps/sim/app/_shell/providers/query-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
'use client'

import { type ReactNode, useState } from 'react'
import type { ReactNode } from 'react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

export function QueryProvider({ children }: { children: ReactNode }) {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 30 * 1000,
gcTime: 5 * 60 * 1000,
refetchOnWindowFocus: false,
retry: 1,
retryOnMount: false,
},
mutations: {
retry: 1,
},
},
})
)
/**
* Singleton QueryClient instance for client-side use.
* Can be imported directly for cache operations outside React components.
*/
function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 30 * 1000,
gcTime: 5 * 60 * 1000,
refetchOnWindowFocus: false,
retry: 1,
retryOnMount: false,
},
mutations: {
retry: 1,
},
},
})
}

let browserQueryClient: QueryClient | undefined

export function getQueryClient() {
if (typeof window === 'undefined') {
return makeQueryClient()
}
if (!browserQueryClient) {
browserQueryClient = makeQueryClient()
}
return browserQueryClient
}

export function QueryProvider({ children }: { children: ReactNode }) {
const queryClient = getQueryClient()
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}
7 changes: 4 additions & 3 deletions apps/sim/app/api/logs/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,15 +259,16 @@ export async function GET(request: NextRequest) {
input: 0,
output: 0,
total: 0,
tokens: { prompt: 0, completion: 0, total: 0 },
tokens: { input: 0, output: 0, total: 0 },
})
}
const modelCost = models.get(block.cost.model)
modelCost.input += Number(block.cost.input) || 0
modelCost.output += Number(block.cost.output) || 0
modelCost.total += Number(block.cost.total) || 0
modelCost.tokens.prompt += block.cost.tokens?.prompt || 0
modelCost.tokens.completion += block.cost.tokens?.completion || 0
modelCost.tokens.input += block.cost.tokens?.input || block.cost.tokens?.prompt || 0
modelCost.tokens.output +=
block.cost.tokens?.output || block.cost.tokens?.completion || 0
modelCost.tokens.total += block.cost.tokens?.total || 0
}
}
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/app/api/providers/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ export async function POST(request: NextRequest) {
: '',
model: executionData.output?.model,
tokens: executionData.output?.tokens || {
prompt: 0,
completion: 0,
input: 0,
output: 0,
total: 0,
},
// Sanitize any potential Unicode characters in tool calls
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/app/chat/[identifier]/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export default function ChatClient({ identifier }: { identifier: string }) {
const [error, setError] = useState<string | null>(null)
const messagesEndRef = useRef<HTMLDivElement>(null)
const messagesContainerRef = useRef<HTMLDivElement>(null)
const [starCount, setStarCount] = useState('19.4k')
const [starCount, setStarCount] = useState('24k')
const [conversationId, setConversationId] = useState('')

const [showScrollButton, setShowScrollButton] = useState(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ function formatExecutionData(executionData: any) {
: null,
tokens: tokens
? {
prompt: tokens.prompt || 0,
completion: tokens.completion || 0,
input: tokens.input || tokens.prompt || 0,
output: tokens.output || tokens.completion || 0,
total: tokens.total || 0,
}
: null,
Expand Down Expand Up @@ -347,12 +347,12 @@ function PinnedLogs({
</h4>
<div className='space-y-[4px] rounded-[4px] border border-[var(--border)] bg-[var(--surface-3)] p-[12px] text-[13px]'>
<div className='flex justify-between text-[var(--text-primary)]'>
<span>Prompt:</span>
<span>{formatted.tokens.prompt}</span>
<span>Input:</span>
<span>{formatted.tokens.input}</span>
</div>
<div className='flex justify-between text-[var(--text-primary)]'>
<span>Completion:</span>
<span>{formatted.tokens.completion}</span>
<span>Output:</span>
<span>{formatted.tokens.output}</span>
</div>
<div className='flex justify-between border-[var(--border)] border-t pt-[4px] font-medium text-[var(--text-primary)]'>
<span>Total:</span>
Expand Down Expand Up @@ -498,8 +498,8 @@ export function FrozenCanvas({
total: null,
},
tokens: span.tokens || {
prompt: null,
completion: null,
input: null,
output: null,
total: null,
},
modelUsed: span.model || null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function CredentialSelector({
setStoreValue('')
}, [invalidSelection, selectedId, effectiveProviderId, setStoreValue])

useCredentialRefreshTriggers(refetchCredentials, effectiveProviderId, provider)
useCredentialRefreshTriggers(refetchCredentials)

const handleOpenChange = useCallback(
(isOpen: boolean) => {
Expand Down Expand Up @@ -268,11 +268,7 @@ export function CredentialSelector({
)
}

function useCredentialRefreshTriggers(
refetchCredentials: () => Promise<unknown>,
effectiveProviderId?: string,
provider?: OAuthProvider
) {
function useCredentialRefreshTriggers(refetchCredentials: () => Promise<unknown>) {
useEffect(() => {
const refresh = () => {
void refetchCredentials()
Expand All @@ -290,26 +286,12 @@ function useCredentialRefreshTriggers(
}
}

const handleCredentialDisconnected = (event: Event) => {
const customEvent = event as CustomEvent<{ providerId?: string }>
const providerId = customEvent.detail?.providerId

if (
providerId &&
(providerId === effectiveProviderId || (provider && providerId.startsWith(provider)))
) {
refresh()
}
}

document.addEventListener('visibilitychange', handleVisibilityChange)
window.addEventListener('pageshow', handlePageShow)
window.addEventListener('credential-disconnected', handleCredentialDisconnected)

return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange)
window.removeEventListener('pageshow', handlePageShow)
window.removeEventListener('credential-disconnected', handleCredentialDisconnected)
}
}, [refetchCredentials, effectiveProviderId, provider])
}, [refetchCredentials])
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function ToolCredentialSelector({
onChange('')
}, [invalidSelection, onChange])

useCredentialRefreshTriggers(refetchCredentials, effectiveProviderId, provider)
useCredentialRefreshTriggers(refetchCredentials)

const handleOpenChange = useCallback(
(isOpen: boolean) => {
Expand Down Expand Up @@ -238,11 +238,7 @@ export function ToolCredentialSelector({
)
}

function useCredentialRefreshTriggers(
refetchCredentials: () => Promise<unknown>,
effectiveProviderId?: string,
provider?: OAuthProvider
) {
function useCredentialRefreshTriggers(refetchCredentials: () => Promise<unknown>) {
useEffect(() => {
const refresh = () => {
void refetchCredentials()
Expand All @@ -260,26 +256,12 @@ function useCredentialRefreshTriggers(
}
}

const handleCredentialDisconnected = (event: Event) => {
const customEvent = event as CustomEvent<{ providerId?: string }>
const providerId = customEvent.detail?.providerId

if (
providerId &&
(providerId === effectiveProviderId || (provider && providerId.startsWith(provider)))
) {
refresh()
}
}

document.addEventListener('visibilitychange', handleVisibilityChange)
window.addEventListener('pageshow', handlePageShow)
window.addEventListener('credential-disconnected', handleCredentialDisconnected)

return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange)
window.removeEventListener('pageshow', handlePageShow)
window.removeEventListener('credential-disconnected', handleCredentialDisconnected)
}
}, [refetchCredentials, effectiveProviderId, provider])
}, [refetchCredentials])
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,22 +143,10 @@ export function useScheduleInfo(
setIsLoading(false)
}

const handleScheduleUpdate = (event: CustomEvent) => {
if (event.detail?.workflowId === workflowId && event.detail?.blockId === blockId) {
logger.debug('Schedule update event received, refetching schedule info')
if (blockType === 'schedule') {
fetchScheduleInfo(workflowId)
}
}
}

window.addEventListener('schedule-updated', handleScheduleUpdate as EventListener)

return () => {
setIsLoading(false)
window.removeEventListener('schedule-updated', handleScheduleUpdate as EventListener)
}
}, [blockType, workflowId, blockId, fetchScheduleInfo])
}, [blockType, workflowId, fetchScheduleInfo])

return {
scheduleInfo,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useCallback, useRef, useState } from 'react'
import { createLogger } from '@/lib/logs/console/logger'
import { getQueryClient } from '@/app/_shell/providers/query-provider'
import type { GenerationType } from '@/blocks/types'
import { subscriptionKeys } from '@/hooks/queries/subscription'

const logger = createLogger('useWand')

Expand All @@ -17,12 +19,10 @@ function buildContextInfo(currentValue?: string, generationType?: string): strin

let contextInfo = `Current content (${contentLength} characters, ${lineCount} lines):\n${currentValue}`

// Add type-specific context analysis
if (generationType) {
switch (generationType) {
case 'javascript-function-body':
case 'typescript-function-body': {
// Analyze code structure
const hasFunction = /function\s+\w+/.test(currentValue)
const hasArrowFunction = /=>\s*{/.test(currentValue)
const hasReturn = /return\s+/.test(currentValue)
Expand All @@ -32,7 +32,6 @@ function buildContextInfo(currentValue?: string, generationType?: string): strin

case 'json-schema':
case 'json-object':
// Analyze JSON structure
try {
const parsed = JSON.parse(currentValue)
const keys = Object.keys(parsed)
Expand Down Expand Up @@ -83,7 +82,6 @@ export function useWand({
const [error, setError] = useState<string | null>(null)
const [isStreaming, setIsStreaming] = useState(false)

// Conversation history state
const [conversationHistory, setConversationHistory] = useState<ChatMessage[]>([])

const abortControllerRef = useRef<AbortController | null>(null)
Expand Down Expand Up @@ -143,25 +141,20 @@ export function useWand({

abortControllerRef.current = new AbortController()

// Signal the start of streaming to clear previous content
if (onStreamStart) {
onStreamStart()
}

try {
// Build context-aware message
const contextInfo = buildContextInfo(currentValue, wandConfig?.generationType)

// Build the system prompt with context information
let systemPrompt = wandConfig?.prompt || ''
if (systemPrompt.includes('{context}')) {
systemPrompt = systemPrompt.replace('{context}', contextInfo)
}

// User message is just the user's specific request
const userMessage = prompt

// Keep track of the current prompt for history
const currentPrompt = prompt

const response = await fetch('/api/wand', {
Expand All @@ -172,9 +165,9 @@ export function useWand({
},
body: JSON.stringify({
prompt: userMessage,
systemPrompt: systemPrompt, // Send the processed system prompt with context
systemPrompt: systemPrompt,
stream: true,
history: wandConfig?.maintainHistory ? conversationHistory : [], // Include history if enabled
history: wandConfig?.maintainHistory ? conversationHistory : [],
}),
signal: abortControllerRef.current.signal,
cache: 'no-store',
Expand Down Expand Up @@ -256,6 +249,11 @@ export function useWand({
prompt,
contentLength: accumulatedContent.length,
})

setTimeout(() => {
const queryClient = getQueryClient()
queryClient.invalidateQueries({ queryKey: subscriptionKeys.user() })
}, 1000)
} catch (error: any) {
if (error.name === 'AbortError') {
logger.debug('Wand generation cancelled')
Expand Down
Loading
Loading