mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-11 07:58:06 -05:00
Remove context usage code
This commit is contained in:
committed by
Emir Karabeg
parent
4fd5656c01
commit
d86e43945f
@@ -1,134 +0,0 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { getCopilotModel } from '@/lib/copilot/config'
|
||||
import { SIM_AGENT_API_URL_DEFAULT } from '@/lib/copilot/constants'
|
||||
import type { CopilotProviderConfig } from '@/lib/copilot/types'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
|
||||
const logger = createLogger('ContextUsageAPI')
|
||||
|
||||
const SIM_AGENT_API_URL = env.SIM_AGENT_API_URL || SIM_AGENT_API_URL_DEFAULT
|
||||
|
||||
const ContextUsageRequestSchema = z.object({
|
||||
chatId: z.string(),
|
||||
model: z.string(),
|
||||
workflowId: z.string(),
|
||||
provider: z.any().optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* POST /api/copilot/context-usage
|
||||
* Fetch context usage from sim-agent API
|
||||
*/
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
logger.info('[Context Usage API] Request received')
|
||||
|
||||
const session = await getSession()
|
||||
if (!session?.user?.id) {
|
||||
logger.warn('[Context Usage API] No session/user ID')
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const body = await req.json()
|
||||
logger.info('[Context Usage API] Request body', body)
|
||||
|
||||
const parsed = ContextUsageRequestSchema.safeParse(body)
|
||||
|
||||
if (!parsed.success) {
|
||||
logger.warn('[Context Usage API] Invalid request body', parsed.error.errors)
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid request body', details: parsed.error.errors },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
const { chatId, model, workflowId, provider } = parsed.data
|
||||
const userId = session.user.id // Get userId from session, not from request
|
||||
|
||||
logger.info('[Context Usage API] Request validated', { chatId, model, userId, workflowId })
|
||||
|
||||
// Build provider config similar to chat route
|
||||
let providerConfig: CopilotProviderConfig | undefined = provider
|
||||
if (!providerConfig) {
|
||||
const defaults = getCopilotModel('chat')
|
||||
const modelToUse = env.COPILOT_MODEL || defaults.model
|
||||
const providerEnv = env.COPILOT_PROVIDER as any
|
||||
|
||||
if (providerEnv) {
|
||||
if (providerEnv === 'azure-openai') {
|
||||
providerConfig = {
|
||||
provider: 'azure-openai',
|
||||
model: modelToUse,
|
||||
apiKey: env.AZURE_OPENAI_API_KEY,
|
||||
apiVersion: env.AZURE_OPENAI_API_VERSION,
|
||||
endpoint: env.AZURE_OPENAI_ENDPOINT,
|
||||
}
|
||||
} else if (providerEnv === 'vertex') {
|
||||
providerConfig = {
|
||||
provider: 'vertex',
|
||||
model: modelToUse,
|
||||
apiKey: env.COPILOT_API_KEY,
|
||||
vertexProject: env.VERTEX_PROJECT,
|
||||
vertexLocation: env.VERTEX_LOCATION,
|
||||
}
|
||||
} else {
|
||||
providerConfig = {
|
||||
provider: providerEnv,
|
||||
model: modelToUse,
|
||||
apiKey: env.COPILOT_API_KEY,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call sim-agent API
|
||||
const requestPayload = {
|
||||
chatId,
|
||||
model,
|
||||
userId,
|
||||
workflowId,
|
||||
...(providerConfig ? { provider: providerConfig } : {}),
|
||||
}
|
||||
|
||||
logger.info('[Context Usage API] Calling sim-agent', {
|
||||
url: `${SIM_AGENT_API_URL}/api/get-context-usage`,
|
||||
payload: requestPayload,
|
||||
})
|
||||
|
||||
const simAgentResponse = await fetch(`${SIM_AGENT_API_URL}/api/get-context-usage`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(env.COPILOT_API_KEY ? { 'x-api-key': env.COPILOT_API_KEY } : {}),
|
||||
},
|
||||
body: JSON.stringify(requestPayload),
|
||||
})
|
||||
|
||||
logger.info('[Context Usage API] Sim-agent response', {
|
||||
status: simAgentResponse.status,
|
||||
ok: simAgentResponse.ok,
|
||||
})
|
||||
|
||||
if (!simAgentResponse.ok) {
|
||||
const errorText = await simAgentResponse.text().catch(() => '')
|
||||
logger.warn('[Context Usage API] Sim agent request failed', {
|
||||
status: simAgentResponse.status,
|
||||
error: errorText,
|
||||
})
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch context usage from sim-agent' },
|
||||
{ status: simAgentResponse.status }
|
||||
)
|
||||
}
|
||||
|
||||
const data = await simAgentResponse.json()
|
||||
logger.info('[Context Usage API] Sim-agent data received', data)
|
||||
return NextResponse.json(data)
|
||||
} catch (error) {
|
||||
logger.error('Error fetching context usage:', error)
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { useMemo } from 'react'
|
||||
import { Tooltip } from '@/components/emcn'
|
||||
|
||||
interface ContextUsageIndicatorProps {
|
||||
/** Usage percentage (0-100) */
|
||||
percentage: number
|
||||
/** Size of the indicator in pixels */
|
||||
size?: number
|
||||
/** Stroke width in pixels */
|
||||
strokeWidth?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Circular context usage indicator showing percentage of context window used.
|
||||
* Displays a progress ring that changes color based on usage level.
|
||||
*
|
||||
* @param props - Component props
|
||||
* @returns Rendered context usage indicator
|
||||
*/
|
||||
export function ContextUsageIndicator({
|
||||
percentage,
|
||||
size = 20,
|
||||
strokeWidth = 2,
|
||||
}: ContextUsageIndicatorProps) {
|
||||
const radius = (size - strokeWidth) / 2
|
||||
const circumference = radius * 2 * Math.PI
|
||||
const offset = circumference - (percentage / 100) * circumference
|
||||
|
||||
const color = useMemo(() => {
|
||||
if (percentage >= 90) return 'var(--text-error)'
|
||||
if (percentage >= 75) return 'var(--warning)'
|
||||
return 'var(--text-muted)'
|
||||
}, [percentage])
|
||||
|
||||
const displayPercentage = useMemo(() => {
|
||||
return Math.round(percentage)
|
||||
}, [percentage])
|
||||
|
||||
return (
|
||||
<Tooltip.Root delayDuration={100}>
|
||||
<Tooltip.Trigger asChild>
|
||||
<div
|
||||
className='flex cursor-pointer items-center justify-center transition-opacity hover:opacity-80'
|
||||
style={{ width: size, height: size }}
|
||||
>
|
||||
<svg width={size} height={size} className='rotate-[-90deg]'>
|
||||
<circle
|
||||
cx={size / 2}
|
||||
cy={size / 2}
|
||||
r={radius}
|
||||
stroke='currentColor'
|
||||
strokeWidth={strokeWidth}
|
||||
fill='none'
|
||||
className='text-muted-foreground/20'
|
||||
/>
|
||||
<circle
|
||||
cx={size / 2}
|
||||
cy={size / 2}
|
||||
r={radius}
|
||||
stroke={color}
|
||||
strokeWidth={strokeWidth}
|
||||
fill='none'
|
||||
strokeDasharray={circumference}
|
||||
strokeDashoffset={offset}
|
||||
className='transition-all duration-300 ease-in-out'
|
||||
strokeLinecap='round'
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content side='top'>{displayPercentage}% context used</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
export { AttachedFilesDisplay } from './attached-files-display/attached-files-display'
|
||||
export { ContextPills } from './context-pills/context-pills'
|
||||
export { ContextUsageIndicator } from './context-usage-indicator/context-usage-indicator'
|
||||
export { MentionMenu } from './mention-menu/mention-menu'
|
||||
export { ModeSelector } from './mode-selector/mode-selector'
|
||||
export { ModelSelector } from './model-selector/model-selector'
|
||||
|
||||
@@ -117,7 +117,6 @@ const UserInput = forwardRef<UserInputRef, UserInputProps>(
|
||||
const selectedModel =
|
||||
selectedModelOverride !== undefined ? selectedModelOverride : copilotStore.selectedModel
|
||||
const setSelectedModel = onModelChangeOverride || copilotStore.setSelectedModel
|
||||
const contextUsage = copilotStore.contextUsage
|
||||
|
||||
// Internal state
|
||||
const [internalMessage, setInternalMessage] = useState('')
|
||||
|
||||
@@ -100,7 +100,6 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(({ panelWidth }, ref
|
||||
loadChats,
|
||||
messageCheckpoints,
|
||||
currentChat,
|
||||
fetchContextUsage,
|
||||
selectChat,
|
||||
deleteChat,
|
||||
areChatsFresh,
|
||||
@@ -119,7 +118,6 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(({ panelWidth }, ref
|
||||
chatsLoadedForWorkflow,
|
||||
setCopilotWorkflowId,
|
||||
loadChats,
|
||||
fetchContextUsage,
|
||||
loadAutoAllowedTools,
|
||||
currentChat,
|
||||
isSendingMessage,
|
||||
|
||||
@@ -11,7 +11,6 @@ interface UseCopilotInitializationProps {
|
||||
chatsLoadedForWorkflow: string | null
|
||||
setCopilotWorkflowId: (workflowId: string | null) => Promise<void>
|
||||
loadChats: (forceRefresh?: boolean) => Promise<void>
|
||||
fetchContextUsage: () => Promise<void>
|
||||
loadAutoAllowedTools: () => Promise<void>
|
||||
currentChat: any
|
||||
isSendingMessage: boolean
|
||||
@@ -30,7 +29,6 @@ export function useCopilotInitialization(props: UseCopilotInitializationProps) {
|
||||
chatsLoadedForWorkflow,
|
||||
setCopilotWorkflowId,
|
||||
loadChats,
|
||||
fetchContextUsage,
|
||||
loadAutoAllowedTools,
|
||||
currentChat,
|
||||
isSendingMessage,
|
||||
@@ -102,18 +100,6 @@ export function useCopilotInitialization(props: UseCopilotInitializationProps) {
|
||||
isSendingMessage,
|
||||
])
|
||||
|
||||
/**
|
||||
* Fetch context usage when component is initialized and has a current chat
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (isInitialized && currentChat?.id && activeWorkflowId) {
|
||||
logger.info('[Copilot] Component initialized, fetching context usage')
|
||||
fetchContextUsage().catch((err) => {
|
||||
logger.warn('[Copilot] Failed to fetch context usage on mount', err)
|
||||
})
|
||||
}
|
||||
}, [isInitialized, currentChat?.id, activeWorkflowId, fetchContextUsage])
|
||||
|
||||
/**
|
||||
* Load auto-allowed tools once on mount
|
||||
*/
|
||||
|
||||
@@ -1969,7 +1969,6 @@ const initialState = {
|
||||
streamingPlanContent: '',
|
||||
toolCallsById: {} as Record<string, CopilotToolCall>,
|
||||
suppressAutoSelect: false,
|
||||
contextUsage: null,
|
||||
autoAllowedTools: [] as string[],
|
||||
messageQueue: [] as import('./types').QueuedMessage[],
|
||||
}
|
||||
@@ -1982,7 +1981,7 @@ export const useCopilotStore = create<CopilotStore>()(
|
||||
setMode: (mode) => set({ mode }),
|
||||
|
||||
// Clear messages (don't clear streamingPlanContent - let it persist)
|
||||
clearMessages: () => set({ messages: [], contextUsage: null }),
|
||||
clearMessages: () => set({ messages: [] }),
|
||||
|
||||
// Workflow selection
|
||||
setWorkflowId: async (workflowId: string | null) => {
|
||||
@@ -2060,7 +2059,6 @@ export const useCopilotStore = create<CopilotStore>()(
|
||||
mode: chatMode,
|
||||
selectedModel: chatModel as CopilotStore['selectedModel'],
|
||||
suppressAutoSelect: false,
|
||||
contextUsage: null,
|
||||
})
|
||||
|
||||
// Background-save the previous chat's latest messages, plan artifact, and config before switching (optimistic)
|
||||
@@ -2112,15 +2110,11 @@ export const useCopilotStore = create<CopilotStore>()(
|
||||
chats: (get().chats || []).map((c: CopilotChat) =>
|
||||
c.id === chat.id ? latestChat : c
|
||||
),
|
||||
contextUsage: null,
|
||||
toolCallsById,
|
||||
})
|
||||
try {
|
||||
await get().loadMessageCheckpoints(latestChat.id)
|
||||
} catch {}
|
||||
// Fetch context usage for the selected chat
|
||||
logger.info('[Context Usage] Chat selected, fetching usage')
|
||||
await get().fetchContextUsage()
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
@@ -2158,7 +2152,6 @@ export const useCopilotStore = create<CopilotStore>()(
|
||||
}
|
||||
} catch {}
|
||||
|
||||
logger.info('[Context Usage] New chat created, clearing context usage')
|
||||
set({
|
||||
currentChat: null,
|
||||
messages: [],
|
||||
@@ -2167,7 +2160,6 @@ export const useCopilotStore = create<CopilotStore>()(
|
||||
showPlanTodos: false,
|
||||
streamingPlanContent: '',
|
||||
suppressAutoSelect: true,
|
||||
contextUsage: null,
|
||||
})
|
||||
},
|
||||
|
||||
@@ -2560,13 +2552,6 @@ export const useCopilotStore = create<CopilotStore>()(
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// Fetch context usage after abort
|
||||
logger.info('[Context Usage] Message aborted, fetching usage')
|
||||
get()
|
||||
.fetchContextUsage()
|
||||
.catch((err) => {
|
||||
logger.warn('[Context Usage] Failed to fetch after abort', err)
|
||||
})
|
||||
} catch {
|
||||
set({ isSendingMessage: false, isAborting: false, abortController: null })
|
||||
}
|
||||
@@ -3132,10 +3117,6 @@ export const useCopilotStore = create<CopilotStore>()(
|
||||
// Removed: stats sending now occurs only on accept/reject with minimal payload
|
||||
} catch {}
|
||||
|
||||
// Fetch context usage after response completes
|
||||
logger.info('[Context Usage] Stream completed, fetching usage')
|
||||
await get().fetchContextUsage()
|
||||
|
||||
// Invalidate subscription queries to update usage
|
||||
setTimeout(() => {
|
||||
const queryClient = getQueryClient()
|
||||
@@ -3313,86 +3294,11 @@ export const useCopilotStore = create<CopilotStore>()(
|
||||
},
|
||||
|
||||
setSelectedModel: async (model) => {
|
||||
logger.info('[Context Usage] Model changed', { from: get().selectedModel, to: model })
|
||||
set({ selectedModel: model })
|
||||
// Fetch context usage after model switch
|
||||
await get().fetchContextUsage()
|
||||
},
|
||||
setAgentPrefetch: (prefetch) => set({ agentPrefetch: prefetch }),
|
||||
setEnabledModels: (models) => set({ enabledModels: models }),
|
||||
|
||||
// Fetch context usage from sim-agent API
|
||||
fetchContextUsage: async () => {
|
||||
try {
|
||||
const { currentChat, selectedModel, workflowId } = get()
|
||||
logger.info('[Context Usage] Starting fetch', {
|
||||
hasChatId: !!currentChat?.id,
|
||||
hasWorkflowId: !!workflowId,
|
||||
chatId: currentChat?.id,
|
||||
workflowId,
|
||||
model: selectedModel,
|
||||
})
|
||||
|
||||
if (!currentChat?.id || !workflowId) {
|
||||
logger.info('[Context Usage] Skipping: missing chat or workflow', {
|
||||
hasChatId: !!currentChat?.id,
|
||||
hasWorkflowId: !!workflowId,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const requestPayload = {
|
||||
chatId: currentChat.id,
|
||||
model: selectedModel,
|
||||
workflowId,
|
||||
}
|
||||
|
||||
logger.info('[Context Usage] Calling API', requestPayload)
|
||||
|
||||
// Call the backend API route which proxies to sim-agent
|
||||
const response = await fetch('/api/copilot/context-usage', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(requestPayload),
|
||||
})
|
||||
|
||||
logger.info('[Context Usage] API response', { status: response.status, ok: response.ok })
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
logger.info('[Context Usage] Received data', data)
|
||||
|
||||
// Check for either tokensUsed or usage field
|
||||
if (
|
||||
data.tokensUsed !== undefined ||
|
||||
data.usage !== undefined ||
|
||||
data.percentage !== undefined
|
||||
) {
|
||||
const contextUsage = {
|
||||
usage: data.tokensUsed || data.usage || 0,
|
||||
percentage: data.percentage || 0,
|
||||
model: data.model || selectedModel,
|
||||
contextWindow: data.contextWindow || data.context_window || 0,
|
||||
when: data.when || 'end',
|
||||
estimatedTokens: data.tokensUsed || data.estimated_tokens || data.estimatedTokens,
|
||||
}
|
||||
set({ contextUsage })
|
||||
logger.info('[Context Usage] Updated store', contextUsage)
|
||||
} else {
|
||||
logger.warn('[Context Usage] No usage data in response', data)
|
||||
}
|
||||
} else {
|
||||
const errorText = await response.text().catch(() => 'Unable to read error')
|
||||
logger.warn('[Context Usage] API call failed', {
|
||||
status: response.status,
|
||||
error: errorText,
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('[Context Usage] Error fetching:', err)
|
||||
}
|
||||
},
|
||||
|
||||
executeIntegrationTool: async (toolCallId: string) => {
|
||||
const { toolCallsById, workflowId } = get()
|
||||
const toolCall = toolCallsById[toolCallId]
|
||||
|
||||
@@ -161,16 +161,6 @@ export interface CopilotState {
|
||||
|
||||
// Per-message metadata captured at send-time for reliable stats
|
||||
|
||||
// Context usage tracking for percentage pill
|
||||
contextUsage: {
|
||||
usage: number
|
||||
percentage: number
|
||||
model: string
|
||||
contextWindow: number
|
||||
when: 'start' | 'end'
|
||||
estimatedTokens?: number
|
||||
} | null
|
||||
|
||||
// Auto-allowed integration tools (tools that can run without confirmation)
|
||||
autoAllowedTools: string[]
|
||||
|
||||
@@ -183,7 +173,6 @@ export interface CopilotActions {
|
||||
setSelectedModel: (model: CopilotStore['selectedModel']) => Promise<void>
|
||||
setAgentPrefetch: (prefetch: boolean) => void
|
||||
setEnabledModels: (models: string[] | null) => void
|
||||
fetchContextUsage: () => Promise<void>
|
||||
|
||||
setWorkflowId: (workflowId: string | null) => Promise<void>
|
||||
validateCurrentChat: () => boolean
|
||||
|
||||
Reference in New Issue
Block a user