|
|
import { AgentStep, AgentTrace, AgentTraceMetadata, FinalStep } from '@/types/agent'; |
|
|
import { create } from 'zustand'; |
|
|
import { devtools } from 'zustand/middleware'; |
|
|
|
|
|
interface AgentState { |
|
|
|
|
|
trace?: AgentTrace; |
|
|
traceId: string | null; |
|
|
isAgentProcessing: boolean; |
|
|
isConnectingToE2B: boolean; |
|
|
vncUrl: string; |
|
|
selectedModelId: string; |
|
|
availableModels: string[]; |
|
|
isLoadingModels: boolean; |
|
|
isConnected: boolean; |
|
|
error?: string; |
|
|
isDarkMode: boolean; |
|
|
selectedStepIndex: number | null; |
|
|
finalStep?: FinalStep; |
|
|
|
|
|
|
|
|
setTrace: (trace: AgentTrace | undefined) => void; |
|
|
setTraceId: (traceId: string | null) => void; |
|
|
updateTraceWithStep: (step: AgentStep, metadata: AgentTraceMetadata) => void; |
|
|
updateStepEvaluation: (stepId: string, evaluation: 'like' | 'dislike' | 'neutral') => void; |
|
|
updateTraceEvaluation: (evaluation: 'success' | 'failed' | 'not_evaluated') => void; |
|
|
completeTrace: (metadata: AgentTraceMetadata, finalState?: 'success' | 'stopped' | 'max_steps_reached' | 'error' | 'sandbox_timeout') => void; |
|
|
setIsAgentProcessing: (processing: boolean) => void; |
|
|
setIsConnectingToE2B: (connecting: boolean) => void; |
|
|
setVncUrl: (url: string) => void; |
|
|
setSelectedModelId: (modelId: string) => void; |
|
|
setAvailableModels: (models: string[]) => void; |
|
|
setIsLoadingModels: (loading: boolean) => void; |
|
|
setIsConnected: (connected: boolean) => void; |
|
|
setError: (error: string | undefined) => void; |
|
|
setSelectedStepIndex: (index: number | null) => void; |
|
|
toggleDarkMode: () => void; |
|
|
resetAgent: () => void; |
|
|
} |
|
|
|
|
|
const initialState = { |
|
|
trace: undefined, |
|
|
traceId: null, |
|
|
isAgentProcessing: false, |
|
|
isConnectingToE2B: false, |
|
|
vncUrl: '', |
|
|
selectedModelId: 'Qwen/Qwen3-VL-30B-A3B-Instruct', |
|
|
availableModels: [], |
|
|
isLoadingModels: false, |
|
|
isConnected: false, |
|
|
error: undefined, |
|
|
isDarkMode: false, |
|
|
selectedStepIndex: null, |
|
|
finalStep: undefined, |
|
|
}; |
|
|
|
|
|
export const useAgentStore = create<AgentState>()( |
|
|
devtools( |
|
|
(set) => ({ |
|
|
...initialState, |
|
|
|
|
|
|
|
|
setTrace: (trace) => |
|
|
set({ trace }, false, 'setTrace'), |
|
|
|
|
|
|
|
|
setTraceId: (traceId) => |
|
|
set({ traceId }, false, 'setTraceId'), |
|
|
|
|
|
|
|
|
updateTraceWithStep: (step, metadata) => |
|
|
set( |
|
|
(state) => { |
|
|
if (!state.trace) return state; |
|
|
|
|
|
const existingSteps = state.trace.steps || []; |
|
|
const stepExists = existingSteps.some((s) => s.stepId === step.stepId); |
|
|
|
|
|
if (stepExists) return state; |
|
|
|
|
|
|
|
|
const updatedMetadata = { |
|
|
...metadata, |
|
|
maxSteps: metadata.maxSteps > 0 |
|
|
? metadata.maxSteps |
|
|
: (state.trace.traceMetadata?.maxSteps || 200), |
|
|
}; |
|
|
|
|
|
return { |
|
|
trace: { |
|
|
...state.trace, |
|
|
steps: [...existingSteps, step], |
|
|
traceMetadata: updatedMetadata, |
|
|
isRunning: true, |
|
|
}, |
|
|
}; |
|
|
}, |
|
|
false, |
|
|
'updateTraceWithStep' |
|
|
), |
|
|
|
|
|
|
|
|
updateStepEvaluation: (stepId, evaluation) => |
|
|
set( |
|
|
(state) => { |
|
|
if (!state.trace || !state.trace.steps) return state; |
|
|
|
|
|
const updatedSteps = state.trace.steps.map((step) => |
|
|
step.stepId === stepId |
|
|
? { ...step, step_evaluation: evaluation } |
|
|
: step |
|
|
); |
|
|
|
|
|
return { |
|
|
trace: { |
|
|
...state.trace, |
|
|
steps: updatedSteps, |
|
|
}, |
|
|
}; |
|
|
}, |
|
|
false, |
|
|
'updateStepEvaluation' |
|
|
), |
|
|
|
|
|
|
|
|
updateTraceEvaluation: (evaluation) => |
|
|
set( |
|
|
(state) => { |
|
|
if (!state.trace || !state.trace.traceMetadata) return state; |
|
|
|
|
|
const updatedMetadata = { |
|
|
...state.trace.traceMetadata, |
|
|
user_evaluation: evaluation, |
|
|
}; |
|
|
|
|
|
return { |
|
|
trace: { |
|
|
...state.trace, |
|
|
traceMetadata: updatedMetadata, |
|
|
}, |
|
|
|
|
|
finalStep: state.finalStep ? { |
|
|
...state.finalStep, |
|
|
metadata: { |
|
|
...state.finalStep.metadata, |
|
|
user_evaluation: evaluation, |
|
|
}, |
|
|
} : state.finalStep, |
|
|
}; |
|
|
}, |
|
|
false, |
|
|
'updateTraceEvaluation' |
|
|
), |
|
|
|
|
|
|
|
|
completeTrace: (metadata, finalState?: 'success' | 'stopped' | 'max_steps_reached' | 'error' | 'sandbox_timeout') => |
|
|
set( |
|
|
(state) => { |
|
|
if (!state.trace) return state; |
|
|
|
|
|
|
|
|
const updatedMetadata = { |
|
|
...metadata, |
|
|
maxSteps: metadata.maxSteps > 0 |
|
|
? metadata.maxSteps |
|
|
: (state.trace.traceMetadata?.maxSteps || 200), |
|
|
completed: true, |
|
|
}; |
|
|
|
|
|
|
|
|
let stepType: 'success' | 'failure' | 'stopped' | 'max_steps_reached' | 'sandbox_timeout'; |
|
|
let stepMessage: string | undefined; |
|
|
|
|
|
if (finalState === 'stopped') { |
|
|
stepType = 'stopped'; |
|
|
stepMessage = 'Task stopped by user'; |
|
|
} else if (finalState === 'max_steps_reached') { |
|
|
stepType = 'max_steps_reached'; |
|
|
stepMessage = 'Maximum steps reached'; |
|
|
} else if (finalState === 'sandbox_timeout') { |
|
|
stepType = 'sandbox_timeout'; |
|
|
stepMessage = 'Sandbox timeout'; |
|
|
} else if (finalState === 'error' || state.error) { |
|
|
stepType = 'failure'; |
|
|
stepMessage = state.error || 'Task failed'; |
|
|
} else { |
|
|
stepType = 'success'; |
|
|
stepMessage = undefined; |
|
|
} |
|
|
|
|
|
const finalStep: FinalStep = { |
|
|
type: stepType, |
|
|
message: stepMessage, |
|
|
metadata: updatedMetadata, |
|
|
}; |
|
|
|
|
|
return { |
|
|
trace: { |
|
|
...state.trace, |
|
|
isRunning: false, |
|
|
traceMetadata: updatedMetadata, |
|
|
}, |
|
|
finalStep, |
|
|
|
|
|
selectedStepIndex: null, |
|
|
}; |
|
|
}, |
|
|
false, |
|
|
'completeTrace' |
|
|
), |
|
|
|
|
|
|
|
|
setIsAgentProcessing: (isAgentProcessing) => |
|
|
set({ isAgentProcessing }, false, 'setIsAgentProcessing'), |
|
|
|
|
|
|
|
|
setIsConnectingToE2B: (isConnectingToE2B) => |
|
|
set({ isConnectingToE2B }, false, 'setIsConnectingToE2B'), |
|
|
|
|
|
|
|
|
setVncUrl: (vncUrl) => |
|
|
set({ vncUrl }, false, 'setVncUrl'), |
|
|
|
|
|
|
|
|
setSelectedModelId: (selectedModelId) => |
|
|
set({ selectedModelId }, false, 'setSelectedModelId'), |
|
|
|
|
|
|
|
|
setAvailableModels: (availableModels) => |
|
|
set({ availableModels }, false, 'setAvailableModels'), |
|
|
|
|
|
|
|
|
setIsLoadingModels: (isLoadingModels) => |
|
|
set({ isLoadingModels }, false, 'setIsLoadingModels'), |
|
|
|
|
|
|
|
|
setIsConnected: (isConnected) => |
|
|
set({ isConnected }, false, 'setIsConnected'), |
|
|
|
|
|
|
|
|
setError: (error) => |
|
|
set( |
|
|
(state) => { |
|
|
|
|
|
if (error && state.trace) { |
|
|
const metadata = state.trace.traceMetadata || { |
|
|
traceId: state.trace.id, |
|
|
inputTokensUsed: 0, |
|
|
outputTokensUsed: 0, |
|
|
duration: 0, |
|
|
numberOfSteps: state.trace.steps?.length || 0, |
|
|
maxSteps: 200, |
|
|
completed: false, |
|
|
final_state: null, |
|
|
user_evaluation: 'not_evaluated' as const, |
|
|
}; |
|
|
|
|
|
|
|
|
const finalMetadata: AgentTraceMetadata = { |
|
|
...metadata, |
|
|
maxSteps: metadata.maxSteps > 0 ? metadata.maxSteps : 200, |
|
|
final_state: metadata.final_state || null, |
|
|
user_evaluation: metadata.user_evaluation || 'not_evaluated', |
|
|
}; |
|
|
|
|
|
const finalStep: FinalStep = { |
|
|
type: 'failure', |
|
|
message: error, |
|
|
metadata: finalMetadata, |
|
|
}; |
|
|
|
|
|
return { |
|
|
error, |
|
|
finalStep, |
|
|
trace: { |
|
|
...state.trace, |
|
|
isRunning: false, |
|
|
}, |
|
|
selectedStepIndex: null, |
|
|
}; |
|
|
} |
|
|
return { error }; |
|
|
}, |
|
|
false, |
|
|
'setError' |
|
|
), |
|
|
|
|
|
|
|
|
setSelectedStepIndex: (selectedStepIndex) => |
|
|
set({ selectedStepIndex }, false, 'setSelectedStepIndex'), |
|
|
|
|
|
|
|
|
toggleDarkMode: () => |
|
|
set((state) => ({ isDarkMode: !state.isDarkMode }), false, 'toggleDarkMode'), |
|
|
|
|
|
|
|
|
resetAgent: () => |
|
|
set((state) => ({ |
|
|
...initialState, |
|
|
traceId: state.traceId, |
|
|
isDarkMode: state.isDarkMode, |
|
|
isConnected: state.isConnected, |
|
|
selectedModelId: state.selectedModelId, |
|
|
availableModels: state.availableModels, |
|
|
isLoadingModels: state.isLoadingModels |
|
|
}), false, 'resetAgent'), |
|
|
}), |
|
|
{ name: 'AgentStore' } |
|
|
) |
|
|
); |
|
|
|
|
|
|
|
|
export const selectTrace = (state: AgentState) => state.trace; |
|
|
export const selectTraceId = (state: AgentState) => state.traceId; |
|
|
export const selectIsAgentProcessing = (state: AgentState) => state.isAgentProcessing; |
|
|
export const selectIsConnectingToE2B = (state: AgentState) => state.isConnectingToE2B; |
|
|
export const selectVncUrl = (state: AgentState) => state.vncUrl; |
|
|
export const selectSelectedModelId = (state: AgentState) => state.selectedModelId; |
|
|
export const selectAvailableModels = (state: AgentState) => state.availableModels; |
|
|
export const selectIsLoadingModels = (state: AgentState) => state.isLoadingModels; |
|
|
export const selectIsConnected = (state: AgentState) => state.isConnected; |
|
|
export const selectSteps = (state: AgentState) => state.trace?.steps; |
|
|
export const selectMetadata = (state: AgentState) => state.trace?.traceMetadata; |
|
|
export const selectError = (state: AgentState) => state.error; |
|
|
export const selectIsDarkMode = (state: AgentState) => state.isDarkMode; |
|
|
export const selectSelectedStepIndex = (state: AgentState) => state.selectedStepIndex; |
|
|
export const selectFinalStep = (state: AgentState) => state.finalStep; |
|
|
|
|
|
|
|
|
export const selectSelectedStep = (state: AgentState) => { |
|
|
const steps = state.trace?.steps; |
|
|
const selectedIndex = state.selectedStepIndex; |
|
|
|
|
|
if (selectedIndex === null || !steps || selectedIndex >= steps.length) { |
|
|
return null; |
|
|
} |
|
|
|
|
|
return steps[selectedIndex]; |
|
|
}; |
|
|
|