| | 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: true,
|
| | 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];
|
| | };
|
| |
|