mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-25 19:40:47 -08:00
fix: errors
This commit is contained in:
parent
5f4a236927
commit
b74553c914
20 changed files with 255 additions and 290 deletions
|
|
@ -192,7 +192,6 @@
|
|||
"ExitFullScreen": "Exit Fullscreen",
|
||||
"Flat": "Flat View",
|
||||
"FormEditor": "Form Editor",
|
||||
"GeneratingPreview": "Generating preview...",
|
||||
"LastUpdated": "Last updated",
|
||||
"Loading": "Loading preview...",
|
||||
"NoConfigFound": "No configuration found",
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@
|
|||
"ExitFullScreen": "退出全屏",
|
||||
"Flat": "平铺视图",
|
||||
"FormEditor": "表单编辑器",
|
||||
"GeneratingPreview": "正在生成预览...",
|
||||
"LastUpdated": "上次更新时间",
|
||||
"Loading": "加载预览中...",
|
||||
"NoConfigFound": "未找到配置",
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ Object.defineProperty(window, 'observables', {
|
|||
},
|
||||
workspace: {
|
||||
workspaces$: new BehaviorSubject([]).asObservable(),
|
||||
get$: vi.fn().mockReturnValue(new BehaviorSubject(null).asObservable()),
|
||||
},
|
||||
updater: {
|
||||
updaterMetaData$: new BehaviorSubject(undefined).asObservable(),
|
||||
|
|
@ -54,21 +53,6 @@ Object.defineProperty(window, 'observables', {
|
|||
auth: {
|
||||
userInfo$: new BehaviorSubject(undefined).asObservable(),
|
||||
},
|
||||
agentInstance: {
|
||||
subscribeToAgentUpdates: vi.fn().mockReturnValue(new BehaviorSubject(null).asObservable()),
|
||||
},
|
||||
agentBrowser: {
|
||||
tabs$: new BehaviorSubject([]).asObservable(),
|
||||
},
|
||||
notification: {
|
||||
pauseNotificationsInfo$: new BehaviorSubject(null).asObservable(),
|
||||
},
|
||||
systemPreference: {
|
||||
systemPreference$: new BehaviorSubject(null).asObservable(),
|
||||
},
|
||||
theme: {
|
||||
theme$: new BehaviorSubject(null).asObservable(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -101,8 +85,6 @@ const mockServiceInstances = {
|
|||
workspace: {
|
||||
countWorkspaces: vi.fn().mockResolvedValue(5),
|
||||
openWorkspaceTiddler: vi.fn().mockResolvedValue(undefined),
|
||||
},
|
||||
agentInstance: {
|
||||
concatPrompt: vi.fn().mockReturnValue(
|
||||
new BehaviorSubject({
|
||||
processedPrompts: [],
|
||||
|
|
@ -115,7 +97,6 @@ const mockServiceInstances = {
|
|||
isComplete: true,
|
||||
}),
|
||||
),
|
||||
subscribeToAgentUpdates: vi.fn().mockReturnValue(new BehaviorSubject(null)),
|
||||
},
|
||||
workspaceView: {
|
||||
setActiveWorkspaceView: vi.fn().mockResolvedValue(undefined),
|
||||
|
|
@ -173,7 +154,7 @@ vi.mock('@services/container', () => {
|
|||
'Symbol(Context)': 'context',
|
||||
'Symbol(Preference)': 'preference',
|
||||
'Symbol(ExternalAPI)': 'externalAPI',
|
||||
'Symbol(AgentInstance)': 'agentInstance',
|
||||
'Symbol(AgentInstance)': 'workspace',
|
||||
'Symbol(AgentDefinition)': 'agentDefinition',
|
||||
};
|
||||
const serviceKey = identifierMap[identifier.toString()];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
import React from 'react';
|
||||
import { LinearProgress, Box, Typography, Chip } from '@mui/material';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useAgentChatStore } from '../../store/agentChatStore';
|
||||
|
||||
interface PreviewProgressBarProps {
|
||||
/**
|
||||
* Whether to show the progress bar
|
||||
*/
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress bar component for preview generation
|
||||
* Shows real-time progress and current processing step
|
||||
*/
|
||||
export const PreviewProgressBar: React.FC<PreviewProgressBarProps> = ({ show }) => {
|
||||
const {
|
||||
previewProgress,
|
||||
previewCurrentStep,
|
||||
previewCurrentPlugin,
|
||||
previewLoading,
|
||||
} = useAgentChatStore(
|
||||
useShallow((state) => ({
|
||||
previewProgress: state.previewProgress,
|
||||
previewCurrentStep: state.previewCurrentStep,
|
||||
previewCurrentPlugin: state.previewCurrentPlugin,
|
||||
previewLoading: state.previewLoading,
|
||||
})),
|
||||
);
|
||||
|
||||
if (!show || !previewLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const progressPercentage = Math.round(previewProgress * 100);
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%', mb: 2, p: 2, bgcolor: 'background.paper', borderRadius: 1 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{previewCurrentStep}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{previewCurrentPlugin && (
|
||||
<Chip
|
||||
label={previewCurrentPlugin}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
/>
|
||||
)}
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{progressPercentage}%
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={progressPercentage}
|
||||
sx={{
|
||||
height: 6,
|
||||
borderRadius: 3,
|
||||
'& .MuiLinearProgress-bar': {
|
||||
borderRadius: 3,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: 'block' }}>
|
||||
⚡ Live preview - this is not the final version and is still loading
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
|
@ -188,7 +188,7 @@ export const agentActions = (
|
|||
|
||||
// Subscribe to overall agent updates (primarily for new messages)
|
||||
const agentSubscription = window.observables.agentInstance.subscribeToAgentUpdates(agentId).subscribe({
|
||||
next: async (fullAgent: AgentInstance) => {
|
||||
next: async (fullAgent) => {
|
||||
// Ensure fullAgent exists before processing
|
||||
if (!fullAgent) return;
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ export const agentActions = (
|
|||
const newMessageIds: string[] = [];
|
||||
|
||||
// Process new messages - backend already sorts messages by modified time
|
||||
fullAgent.messages.forEach((message: AgentInstanceMessage) => {
|
||||
fullAgent.messages.forEach(message => {
|
||||
const existingMessage = currentMessages.get(message.id);
|
||||
|
||||
// If this is a new message
|
||||
|
|
@ -214,7 +214,7 @@ export const agentActions = (
|
|||
messageSubscriptions.set(
|
||||
message.id,
|
||||
window.observables.agentInstance.subscribeToAgentUpdates(agentId, message.id).subscribe({
|
||||
next: (status: any) => {
|
||||
next: (status) => {
|
||||
if (status?.message) {
|
||||
// Update the message in our map
|
||||
get().messages.set(status.message.id, status.message);
|
||||
|
|
@ -224,7 +224,7 @@ export const agentActions = (
|
|||
}
|
||||
}
|
||||
},
|
||||
error: (error: any) => {
|
||||
error: (error) => {
|
||||
console.error(`Error in message subscription for ${message.id}:`, error);
|
||||
},
|
||||
complete: () => {
|
||||
|
|
@ -252,7 +252,7 @@ export const agentActions = (
|
|||
set({ agent: agentWithoutMessages });
|
||||
}
|
||||
},
|
||||
error: (error: any) => {
|
||||
error: (error) => {
|
||||
console.error('Error in agent subscription:', error);
|
||||
set({ error: error instanceof Error ? error : new Error(String(error)) });
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import type { AgentPromptDescription } from '@services/agentInstance/promptConcat/promptConcatSchema';
|
||||
import { timeout } from 'rxjs/operators';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { timeout, tap } from 'rxjs/operators';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { StateCreator } from 'zustand';
|
||||
import { AgentChatStoreType, PreviewActions } from '../types';
|
||||
|
||||
/**
|
||||
* Preview dialog related actions
|
||||
* Handles dialog state and preview generation with real-time updates
|
||||
* Handles dialog state and preview generation
|
||||
*/
|
||||
export const previewActionsMiddleware: StateCreator<AgentChatStoreType, [], [], PreviewActions> = (
|
||||
set,
|
||||
|
|
@ -22,8 +22,6 @@ export const previewActionsMiddleware: StateCreator<AgentChatStoreType, [], [],
|
|||
lastUpdated: null,
|
||||
expandedArrayItems: new Map(),
|
||||
formFieldsToScrollTo: [],
|
||||
previewProgress: undefined,
|
||||
previewStep: undefined,
|
||||
});
|
||||
},
|
||||
|
||||
|
|
@ -31,14 +29,12 @@ export const previewActionsMiddleware: StateCreator<AgentChatStoreType, [], [],
|
|||
set({ previewDialogTab: tab });
|
||||
},
|
||||
|
||||
setFormFieldsToScrollTo: (fieldIds: string[]) => {
|
||||
set({ formFieldsToScrollTo: fieldIds });
|
||||
setFormFieldsToScrollTo: (fieldPaths: string[]) => {
|
||||
set({ formFieldsToScrollTo: fieldPaths });
|
||||
},
|
||||
|
||||
setArrayItemExpanded: (itemId: string, expanded: boolean) => {
|
||||
const { expandedArrayItems } = get();
|
||||
const newMap = new Map(expandedArrayItems);
|
||||
|
||||
if (expanded) {
|
||||
newMap.set(itemId, true);
|
||||
} else {
|
||||
|
|
@ -46,33 +42,10 @@ export const previewActionsMiddleware: StateCreator<AgentChatStoreType, [], [],
|
|||
}
|
||||
set({ expandedArrayItems: newMap });
|
||||
},
|
||||
|
||||
toggleArrayItemExpansion: (itemId: string) => {
|
||||
const { expandedArrayItems } = get();
|
||||
const newMap = new Map(expandedArrayItems);
|
||||
|
||||
if (newMap.has(itemId)) {
|
||||
newMap.delete(itemId);
|
||||
} else {
|
||||
newMap.set(itemId, true);
|
||||
}
|
||||
set({ expandedArrayItems: newMap });
|
||||
},
|
||||
|
||||
collapseArrayItem: (itemId: string) => {
|
||||
const { expandedArrayItems } = get();
|
||||
const newMap = new Map(expandedArrayItems);
|
||||
if (newMap.has(itemId)) {
|
||||
newMap.delete(itemId);
|
||||
}
|
||||
set({ expandedArrayItems: newMap });
|
||||
},
|
||||
|
||||
isArrayItemExpanded: (itemId: string) => {
|
||||
const { expandedArrayItems } = get();
|
||||
return expandedArrayItems.get(itemId) ?? false;
|
||||
},
|
||||
|
||||
expandPathToTarget: (targetPath: string[]) => {
|
||||
const { expandedArrayItems } = get();
|
||||
const newMap = new Map(expandedArrayItems);
|
||||
|
|
@ -88,37 +61,28 @@ export const previewActionsMiddleware: StateCreator<AgentChatStoreType, [], [],
|
|||
set({ expandedArrayItems: newMap });
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate preview result with real-time progress updates
|
||||
* Shows processing status and intermediate results to the user
|
||||
*/
|
||||
updatePreviewProgress: (progress: number, step: string, currentPlugin?: string) => {
|
||||
set({
|
||||
previewProgress: progress,
|
||||
previewCurrentStep: step,
|
||||
previewCurrentPlugin: currentPlugin || null,
|
||||
});
|
||||
},
|
||||
|
||||
getPreviewPromptResult: async (
|
||||
inputText: string,
|
||||
promptConfig: AgentPromptDescription['promptConfig'],
|
||||
) => {
|
||||
try {
|
||||
// Initialize loading state
|
||||
set({
|
||||
previewLoading: true,
|
||||
previewProgress: 0,
|
||||
previewStep: 'Starting...',
|
||||
previewResult: null
|
||||
});
|
||||
|
||||
set({ previewLoading: true });
|
||||
const messages = Array.from(get().messages.values());
|
||||
|
||||
// Safety check - if promptConfig is empty, fail early
|
||||
if (Object.keys(promptConfig).length === 0) {
|
||||
set({
|
||||
previewLoading: false,
|
||||
previewResult: null,
|
||||
previewProgress: undefined,
|
||||
previewStep: undefined,
|
||||
});
|
||||
set({ previewLoading: false, previewResult: null });
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add input text as a preview message
|
||||
if (inputText.trim()) {
|
||||
messages.push({
|
||||
id: 'preview-input',
|
||||
|
|
@ -129,72 +93,99 @@ export const previewActionsMiddleware: StateCreator<AgentChatStoreType, [], [],
|
|||
});
|
||||
}
|
||||
|
||||
// Use the streaming API for real-time progress
|
||||
const concatStream = window.service.agentInstance.concatPrompt({ promptConfig }, messages);
|
||||
// Use the streaming API with progress updates
|
||||
const concatStream = window.observables.agentInstance.concatPrompt({ promptConfig }, messages);
|
||||
|
||||
// Create promise to track completion and provide real-time updates
|
||||
return new Promise((resolve, reject) => {
|
||||
let finalResult: any = null;
|
||||
// Initialize progress
|
||||
set({
|
||||
previewProgress: 0,
|
||||
previewCurrentStep: 'Starting...',
|
||||
previewCurrentPlugin: null,
|
||||
});
|
||||
|
||||
const subscription = concatStream.pipe(
|
||||
timeout(15000) // 15 second timeout
|
||||
).subscribe({
|
||||
let finalResult: any = null;
|
||||
let completed = false;
|
||||
|
||||
// Create a promise that resolves when the stream completes
|
||||
const streamPromise = new Promise<any>((resolve, reject) => {
|
||||
// Subscribe to the stream and update progress in real-time
|
||||
const subscription = concatStream.subscribe({
|
||||
next: (state) => {
|
||||
// Update UI with real-time progress
|
||||
// Update progress and current step
|
||||
const stepDescription = state.step === 'plugin'
|
||||
? `Processing plugin: ${state.currentPlugin?.pluginId || 'unknown'}`
|
||||
: state.step === 'finalize'
|
||||
? 'Finalizing prompts...'
|
||||
: state.step === 'flatten'
|
||||
? 'Flattening prompt tree...'
|
||||
: 'Completing...';
|
||||
|
||||
set({
|
||||
previewProgress: state.progress,
|
||||
previewStep: state.step,
|
||||
previewCurrentStep: stepDescription,
|
||||
previewCurrentPlugin: state.currentPlugin?.pluginId || null,
|
||||
// Update intermediate results
|
||||
previewResult: {
|
||||
flatPrompts: state.flatPrompts,
|
||||
processedPrompts: state.processedPrompts,
|
||||
},
|
||||
});
|
||||
|
||||
// Store final result when processing is complete
|
||||
// Store final result
|
||||
if (state.isComplete) {
|
||||
finalResult = {
|
||||
flatPrompts: state.flatPrompts,
|
||||
processedPrompts: state.processedPrompts,
|
||||
};
|
||||
|
||||
set({
|
||||
previewResult: finalResult,
|
||||
previewLoading: false,
|
||||
lastUpdated: new Date(),
|
||||
});
|
||||
}
|
||||
|
||||
// Log progress for development debugging
|
||||
console.log(`🔄 Preview progress: ${Math.round(state.progress * 100)}% - ${state.step}`, {
|
||||
currentPlugin: state.currentPlugin?.pluginId,
|
||||
flatPromptsCount: state.flatPrompts.length,
|
||||
processedPromptsCount: state.processedPrompts.length,
|
||||
});
|
||||
},
|
||||
error: (error: any) => {
|
||||
console.error('❌ Error generating preview prompt result:', error);
|
||||
error: (error) => {
|
||||
console.error('Error generating preview prompt result:', error);
|
||||
set({
|
||||
previewResult: null,
|
||||
previewLoading: false,
|
||||
previewProgress: undefined,
|
||||
previewStep: undefined,
|
||||
previewProgress: 0,
|
||||
previewCurrentStep: 'Error occurred',
|
||||
previewCurrentPlugin: null,
|
||||
});
|
||||
reject(error);
|
||||
},
|
||||
complete: () => {
|
||||
console.log('✅ Preview prompt generation completed');
|
||||
completed = true;
|
||||
set({
|
||||
previewResult: finalResult,
|
||||
previewLoading: false,
|
||||
previewProgress: undefined,
|
||||
previewStep: undefined,
|
||||
previewProgress: 1,
|
||||
previewCurrentStep: 'Complete',
|
||||
previewCurrentPlugin: null,
|
||||
lastUpdated: new Date(),
|
||||
});
|
||||
resolve(finalResult);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// Set up timeout
|
||||
setTimeout(() => {
|
||||
if (!completed) {
|
||||
subscription.unsubscribe();
|
||||
set({
|
||||
previewResult: null,
|
||||
previewLoading: false,
|
||||
previewProgress: 0,
|
||||
previewCurrentStep: 'Timeout',
|
||||
previewCurrentPlugin: null,
|
||||
});
|
||||
reject(new Error('Preview generation timed out'));
|
||||
}
|
||||
}, 15000);
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error in preview generation:', error);
|
||||
|
||||
return streamPromise;
|
||||
} catch (error) {
|
||||
console.error('Error generating preview prompt result:', error);
|
||||
set({
|
||||
previewResult: null,
|
||||
previewLoading: false,
|
||||
previewProgress: undefined,
|
||||
previewStep: undefined,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ export const useAgentChatStore = create<AgentChatStoreType>()((set, get, api) =>
|
|||
previewDialogOpen: false,
|
||||
previewDialogTab: 'tree',
|
||||
previewLoading: false,
|
||||
previewProgress: 0,
|
||||
previewCurrentStep: '',
|
||||
previewCurrentPlugin: null,
|
||||
previewResult: null,
|
||||
lastUpdated: null,
|
||||
formFieldsToScrollTo: [],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { AgentDefinition } from '@services/agentDefinition/interface';
|
||||
import type { AgentInstance, AgentInstanceMessage } from '@services/agentInstance/interface';
|
||||
import type { AgentPromptDescription, IPrompt } from '@services/agentInstance/promptConcat/promptConcatSchema';
|
||||
import { PromptConcatStreamState } from '@services/agentInstance/promptConcat/promptConcat';
|
||||
import { CoreMessage } from 'ai';
|
||||
|
||||
// Type for agent data without messages - exported for use in other components
|
||||
|
|
@ -29,8 +30,9 @@ export interface PreviewDialogState {
|
|||
previewDialogOpen: boolean;
|
||||
previewDialogTab: 'flat' | 'tree';
|
||||
previewLoading: boolean;
|
||||
previewProgress?: number; // 0-1 progress value
|
||||
previewStep?: string; // Current processing step
|
||||
previewProgress: number; // 0-1, processing progress
|
||||
previewCurrentStep: string; // current processing step description
|
||||
previewCurrentPlugin: string | null; // current plugin being processed
|
||||
previewResult: {
|
||||
flatPrompts: CoreMessage[];
|
||||
processedPrompts: IPrompt[];
|
||||
|
|
@ -176,17 +178,29 @@ export interface PreviewActions {
|
|||
*/
|
||||
expandPathToTarget: (targetPath: string[]) => void;
|
||||
|
||||
/**
|
||||
* Updates preview progress state
|
||||
* @param progress Progress value from 0 to 1
|
||||
* @param step Current processing step description
|
||||
* @param currentPlugin Current plugin being processed
|
||||
*/
|
||||
updatePreviewProgress: (progress: number, step: string, currentPlugin?: string) => void;
|
||||
|
||||
/**
|
||||
* Generates a preview of prompts for the current agent state
|
||||
* Now uses streaming API for real-time progress updates
|
||||
* @param inputText Input text to include in the preview
|
||||
* @param promptConfig Prompt configuration to use for preview
|
||||
* @returns Promise that resolves to a cleanup function to cancel the subscription
|
||||
* @returns Promise that resolves when preview is generated and state is updated
|
||||
*/
|
||||
getPreviewPromptResult: (
|
||||
inputText: string,
|
||||
promptConfig: AgentPromptDescription['promptConfig'],
|
||||
) => Promise<(() => void) | null>;
|
||||
) => Promise<
|
||||
{
|
||||
flatPrompts: CoreMessage[];
|
||||
processedPrompts: IPrompt[];
|
||||
} | null
|
||||
>;
|
||||
|
||||
/**
|
||||
* Resets the lastUpdated timestamp, typically called when dialog is closed
|
||||
|
|
|
|||
|
|
@ -1,22 +1,17 @@
|
|||
import { Box, CircularProgress, LinearProgress, Typography } from '@mui/material';
|
||||
import { Box, CircularProgress, Typography } from '@mui/material';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface LoadingViewProps {
|
||||
message?: string;
|
||||
progress?: number; // 0-1 progress value
|
||||
step?: string; // Current processing step
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhanced loading state component with progress indicator and step information
|
||||
* Loading state component with spinner and messages
|
||||
*/
|
||||
export const LoadingView: React.FC<LoadingViewProps> = ({ message, progress, step }) => {
|
||||
export const LoadingView: React.FC<LoadingViewProps> = ({ message }) => {
|
||||
const { t } = useTranslation('agent');
|
||||
|
||||
const showProgress = typeof progress === 'number';
|
||||
const progressPercentage = showProgress ? Math.round(progress * 100) : 0;
|
||||
|
||||
return (
|
||||
<Box
|
||||
display='flex'
|
||||
|
|
@ -25,52 +20,11 @@ export const LoadingView: React.FC<LoadingViewProps> = ({ message, progress, ste
|
|||
alignItems='center'
|
||||
minHeight={300}
|
||||
gap={2}
|
||||
sx={{ px: 3 }}
|
||||
>
|
||||
{/* Main spinner */}
|
||||
<CircularProgress
|
||||
variant={showProgress ? 'determinate' : 'indeterminate'}
|
||||
value={progressPercentage}
|
||||
size={60}
|
||||
/>
|
||||
|
||||
{/* Progress percentage */}
|
||||
{showProgress && (
|
||||
<Typography variant='h6' color='primary' fontWeight='bold'>
|
||||
{progressPercentage}%
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{/* Current step information */}
|
||||
{step && (
|
||||
<Typography variant='body1' color='text.primary' textAlign='center'>
|
||||
{step}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{/* Main loading message */}
|
||||
<Typography variant='body2' color='text.secondary' textAlign='center'>
|
||||
<CircularProgress />
|
||||
<Typography variant='body2' color='text.secondary'>
|
||||
{message || t('Prompt.Loading')}
|
||||
</Typography>
|
||||
|
||||
{/* Linear progress bar for better visual feedback */}
|
||||
{showProgress && (
|
||||
<Box sx={{ width: '100%', maxWidth: 400, mt: 2 }}>
|
||||
<LinearProgress
|
||||
variant='determinate'
|
||||
value={progressPercentage}
|
||||
sx={{
|
||||
height: 8,
|
||||
borderRadius: 5,
|
||||
'& .MuiLinearProgress-bar': {
|
||||
borderRadius: 5,
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Auto-refresh hint */}
|
||||
<Typography variant='caption' color='text.secondary' sx={{ mt: 1, maxWidth: '80%', textAlign: 'center' }}>
|
||||
{t('Prompt.AutoRefresh')}
|
||||
</Typography>
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@ export const PreviewTabsView: React.FC<PreviewTabsViewProps> = ({
|
|||
previewDialogTab: tab,
|
||||
previewLoading,
|
||||
previewResult,
|
||||
previewProgress,
|
||||
previewStep,
|
||||
lastUpdated,
|
||||
setPreviewDialogTab,
|
||||
} = useAgentChatStore(
|
||||
|
|
@ -60,8 +58,6 @@ export const PreviewTabsView: React.FC<PreviewTabsViewProps> = ({
|
|||
previewDialogTab: state.previewDialogTab,
|
||||
previewLoading: state.previewLoading,
|
||||
previewResult: state.previewResult,
|
||||
previewProgress: state.previewProgress,
|
||||
previewStep: state.previewStep,
|
||||
lastUpdated: state.lastUpdated,
|
||||
setPreviewDialogTab: state.setPreviewDialogTab,
|
||||
})),
|
||||
|
|
@ -89,13 +85,7 @@ export const PreviewTabsView: React.FC<PreviewTabsViewProps> = ({
|
|||
}, [setPreviewDialogTab]);
|
||||
|
||||
if (previewLoading) {
|
||||
return (
|
||||
<LoadingView
|
||||
progress={previewProgress}
|
||||
step={previewStep}
|
||||
message={t('Prompt.GeneratingPreview')}
|
||||
/>
|
||||
);
|
||||
return <LoadingView />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useAgentChatStore } from '../../../Agent/store/agentChatStore/index';
|
||||
import { PreviewProgressBar } from '../../../Agent/components/PreviewDialog/PreviewProgressBar';
|
||||
import { EditView } from './EditView';
|
||||
import { PreviewTabsView } from './PreviewTabsView';
|
||||
|
||||
|
|
@ -42,9 +43,13 @@ export const PromptPreviewDialog: React.FC<PromptPreviewDialogProps> = ({
|
|||
agentId: agent?.id,
|
||||
});
|
||||
|
||||
const { getPreviewPromptResult } = useAgentChatStore(
|
||||
const {
|
||||
getPreviewPromptResult,
|
||||
previewLoading,
|
||||
} = useAgentChatStore(
|
||||
useShallow((state) => ({
|
||||
getPreviewPromptResult: state.getPreviewPromptResult,
|
||||
previewLoading: state.previewLoading,
|
||||
})),
|
||||
);
|
||||
useEffect(() => {
|
||||
|
|
@ -59,7 +64,7 @@ export const PromptPreviewDialog: React.FC<PromptPreviewDialogProps> = ({
|
|||
}
|
||||
};
|
||||
void fetchInitialPreview();
|
||||
}, [agent?.agentDefId, handlerConfig, handlerConfigLoading, getPreviewPromptResult, inputText, open]);
|
||||
}, [agent?.agentDefId, handlerConfig, handlerConfigLoading, inputText, open]); // 移除 getPreviewPromptResult
|
||||
|
||||
const handleToggleFullScreen = useCallback((): void => {
|
||||
setIsFullScreen(previous => !previous);
|
||||
|
|
@ -143,6 +148,7 @@ export const PromptPreviewDialog: React.FC<PromptPreviewDialogProps> = ({
|
|||
}),
|
||||
}}
|
||||
>
|
||||
<PreviewProgressBar show={previewLoading} />
|
||||
{isEditMode
|
||||
? (
|
||||
<Box sx={{ display: 'flex', gap: 2, height: isFullScreen ? '100%' : '70vh' }}>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import { ExternalAPIServiceIPCDescriptor, IExternalAPIService } from '../../serv
|
|||
|
||||
export const agentBrowser = createProxy<AsyncifyProxy<IAgentBrowserService>>(AgentBrowserServiceIPCDescriptor);
|
||||
export const agentDefinition = createProxy<AsyncifyProxy<IAgentDefinitionService>>(AgentDefinitionServiceIPCDescriptor);
|
||||
export const agentInstance = createProxy<IAgentInstanceService>(AgentInstanceServiceIPCDescriptor);
|
||||
export const agentInstance = createProxy<AsyncifyProxy<IAgentInstanceService>>(AgentInstanceServiceIPCDescriptor);
|
||||
export const auth = createProxy<IAuthenticationService>(AuthenticationServiceIPCDescriptor);
|
||||
export const context = createProxy<IContextService>(ContextServiceIPCDescriptor);
|
||||
export const deepLink = createProxy<IDeepLinkService>(DeepLinkServiceIPCDescriptor);
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ describe('basicPromptConcatHandler', () => {
|
|||
describe('error handling', () => {
|
||||
it('should handle unexpected errors', async () => {
|
||||
// Mock service to return error observable
|
||||
mockServiceInstances.agentInstance.concatPrompt = vi.fn().mockReturnValue(
|
||||
mockServiceInstances.workspace.concatPrompt = vi.fn().mockReturnValue(
|
||||
new BehaviorSubject({
|
||||
processedPrompts: [],
|
||||
flatPrompts: [],
|
||||
|
|
|
|||
|
|
@ -1,51 +1,9 @@
|
|||
import { AsyncSeriesWaterfallHook } from 'tapable';
|
||||
import { logger } from '@services/libs/log';
|
||||
import { IPrompt } from '../promptConcatSchema';
|
||||
import { Plugin } from '../promptConcatSchema/plugin';
|
||||
import { fullReplacementPlugin, dynamicPositionPlugin, modelContextProtocolPlugin, retrievalAugmentedGenerationPlugin } from './promptPlugins';
|
||||
import { toolCallingPlugin, autoReplyPlugin } from './responsePlugins';
|
||||
import { AgentInstanceMessage } from '@services/agentInstance/interface';
|
||||
import { PromptConcatHooks, PromptConcatHookContext, PromptConcatPlugin, AgentResponse, ResponseHookContext } from './types';
|
||||
|
||||
/**
|
||||
* Context passed to plugin hooks
|
||||
*/
|
||||
export interface PromptConcatHookContext {
|
||||
/** Array of agent instance messages for context */
|
||||
messages: AgentInstanceMessage[];
|
||||
/** Current prompt tree */
|
||||
prompts: IPrompt[];
|
||||
/** Plugin configuration */
|
||||
plugin: Plugin;
|
||||
/** Additional context data */
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin function type - receives hooks object and registers handlers
|
||||
*/
|
||||
export type PromptConcatPlugin = (hooks: PromptConcatHooks) => void;
|
||||
|
||||
/**
|
||||
* Hooks system for prompt concatenation
|
||||
*/
|
||||
export class PromptConcatHooks {
|
||||
/** Hook for processing prompt modifications */
|
||||
public readonly processPrompts = new AsyncSeriesWaterfallHook<[PromptConcatHookContext]>(['context']);
|
||||
|
||||
/** Hook for finalizing prompts before LLM call */
|
||||
public readonly finalizePrompts = new AsyncSeriesWaterfallHook<[PromptConcatHookContext]>(['context']);
|
||||
|
||||
/** Hook for post-processing after LLM response */
|
||||
public readonly postProcess = new AsyncSeriesWaterfallHook<[PromptConcatHookContext & { llmResponse: string }]>(['context']);
|
||||
|
||||
/**
|
||||
* Register a plugin
|
||||
*/
|
||||
public registerPlugin(plugin: PromptConcatPlugin): void {
|
||||
logger.debug('Registering prompt concat plugin');
|
||||
plugin(this);
|
||||
}
|
||||
}
|
||||
// Re-export types for convenience
|
||||
export type { PromptConcatHookContext, PromptConcatPlugin, AgentResponse, ResponseHookContext };
|
||||
export { PromptConcatHooks };
|
||||
|
||||
/**
|
||||
* Registry for built-in plugins
|
||||
|
|
@ -60,23 +18,29 @@ export function registerBuiltInPlugin(pluginId: string, plugin: PromptConcatPlug
|
|||
logger.debug(`Registered built-in plugin: ${pluginId}`);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register all built-in plugins
|
||||
*/
|
||||
export function registerAllBuiltInPlugins(): void {
|
||||
// Prompt processing plugins
|
||||
registerBuiltInPlugin('fullReplacement', fullReplacementPlugin);
|
||||
registerBuiltInPlugin('dynamicPosition', dynamicPositionPlugin);
|
||||
registerBuiltInPlugin('modelContextProtocol', modelContextProtocolPlugin);
|
||||
registerBuiltInPlugin('retrievalAugmentedGeneration', retrievalAugmentedGenerationPlugin);
|
||||
// Use dynamic imports to avoid circular dependency issues
|
||||
Promise.all([
|
||||
import('./promptPlugins'),
|
||||
import('./responsePlugins')
|
||||
]).then(([promptPluginsModule, responsePluginsModule]) => {
|
||||
// Prompt processing plugins
|
||||
registerBuiltInPlugin('fullReplacement', promptPluginsModule.fullReplacementPlugin);
|
||||
registerBuiltInPlugin('dynamicPosition', promptPluginsModule.dynamicPositionPlugin);
|
||||
registerBuiltInPlugin('modelContextProtocol', promptPluginsModule.modelContextProtocolPlugin);
|
||||
registerBuiltInPlugin('retrievalAugmentedGeneration', promptPluginsModule.retrievalAugmentedGenerationPlugin);
|
||||
|
||||
// Response processing plugins
|
||||
registerBuiltInPlugin('toolCalling', toolCallingPlugin);
|
||||
registerBuiltInPlugin('autoReply', autoReplyPlugin);
|
||||
// Response processing plugins
|
||||
registerBuiltInPlugin('toolCalling', responsePluginsModule.toolCallingPlugin);
|
||||
registerBuiltInPlugin('autoReply', responsePluginsModule.autoReplyPlugin);
|
||||
|
||||
// Note: fullReplacementResponsePlugin is separate from fullReplacementPlugin
|
||||
// They handle different phases of processing
|
||||
logger.debug('All built-in plugins registered successfully');
|
||||
}).catch(error => {
|
||||
logger.error('Failed to register built-in plugins:', error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
*/
|
||||
import { logger } from '@services/libs/log';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { PromptConcatPlugin, PromptConcatHookContext } from './index';
|
||||
import { PromptConcatPlugin, PromptConcatHookContext, AgentResponse, ResponseHookContext } from './types';
|
||||
import { findPromptById } from '../promptConcat';
|
||||
import { IPrompt } from '../promptConcatSchema';
|
||||
import { AgentResponse, ResponseHookContext } from './responsePlugins';
|
||||
|
||||
/**
|
||||
* Full replacement plugin
|
||||
|
|
|
|||
|
|
@ -2,18 +2,10 @@
|
|||
* Response processing plugins
|
||||
*/
|
||||
import { logger } from '@services/libs/log';
|
||||
import { PromptConcatPlugin, PromptConcatHookContext } from './index';
|
||||
|
||||
/**
|
||||
* Agent response interface
|
||||
* Represents a structured response from an agent
|
||||
*/
|
||||
export interface AgentResponse {
|
||||
id: string;
|
||||
text?: string;
|
||||
enabled?: boolean;
|
||||
children?: AgentResponse[];
|
||||
}
|
||||
import { AgentInstanceMessage } from '../../interface';
|
||||
import { IPrompt } from '../promptConcatSchema';
|
||||
import { Plugin } from '../promptConcatSchema/plugin';
|
||||
import { PromptConcatPlugin, PromptConcatHookContext, AgentResponse, ResponseHookContext } from './types';
|
||||
|
||||
/**
|
||||
* Find response by ID in response array
|
||||
|
|
@ -52,14 +44,6 @@ function parseRegexString(regexString: string): RegExp | null {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Context for response processing hooks
|
||||
*/
|
||||
export interface ResponseHookContext extends PromptConcatHookContext {
|
||||
llmResponse: string;
|
||||
responses: AgentResponse[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool calling plugin
|
||||
* Processes function calls in AI responses
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { AsyncSeriesWaterfallHook } from 'tapable';
|
||||
import { logger } from '@services/libs/log';
|
||||
import { AgentInstanceMessage } from '../interface';
|
||||
import { IPrompt } from './promptConcatSchema';
|
||||
import { Plugin } from './promptConcatSchema/plugin';
|
||||
import { IPrompt } from '../promptConcatSchema';
|
||||
import { Plugin } from '../promptConcatSchema/plugin';
|
||||
import { AgentInstanceMessage } from '@services/agentInstance/interface';
|
||||
|
||||
/**
|
||||
* Context passed to plugin hooks
|
||||
|
|
@ -18,6 +18,25 @@ export interface PromptConcatHookContext {
|
|||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Agent response interface
|
||||
* Represents a structured response from an agent
|
||||
*/
|
||||
export interface AgentResponse {
|
||||
id: string;
|
||||
text?: string;
|
||||
enabled?: boolean;
|
||||
children?: AgentResponse[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Context for response processing hooks
|
||||
*/
|
||||
export interface ResponseHookContext extends PromptConcatHookContext {
|
||||
llmResponse: string;
|
||||
responses: AgentResponse[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin function type - receives hooks object and registers handlers
|
||||
*/
|
||||
|
|
@ -44,16 +63,3 @@ export class PromptConcatHooks {
|
|||
plugin(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registry for built-in plugins
|
||||
*/
|
||||
export const builtInPlugins = new Map<string, PromptConcatPlugin>();
|
||||
|
||||
/**
|
||||
* Register a built-in plugin
|
||||
*/
|
||||
export function registerBuiltInPlugin(pluginId: string, plugin: PromptConcatPlugin): void {
|
||||
builtInPlugins.set(pluginId, plugin);
|
||||
logger.debug(`Registered built-in plugin: ${pluginId}`);
|
||||
}
|
||||
|
|
@ -19,8 +19,7 @@ import { cloneDeep } from 'lodash';
|
|||
import { AgentInstanceMessage } from '../interface';
|
||||
import { AgentPromptDescription, IPrompt } from './promptConcatSchema';
|
||||
import { Plugin } from './promptConcatSchema/plugin';
|
||||
import { PromptConcatHooks, PromptConcatHookContext, builtInPlugins } from './hooks';
|
||||
import { initializePluginSystem } from './plugins';
|
||||
import { PromptConcatHooks, PromptConcatHookContext, builtInPlugins, initializePluginSystem } from './plugins';
|
||||
|
||||
// Initialize plugin system on module load
|
||||
initializePluginSystem();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { AgentInstanceMessage } from '../interface';
|
|||
import { AgentPromptDescription } from './promptConcatSchema';
|
||||
import { Plugin } from './promptConcatSchema/plugin';
|
||||
import { PromptConcatHooks, PromptConcatHookContext, builtInPlugins } from './plugins';
|
||||
import { ResponseHookContext, AgentResponse } from './plugins/responsePlugins';
|
||||
import { ResponseHookContext, AgentResponse } from './plugins/types';
|
||||
|
||||
/**
|
||||
* Process response configuration, apply plugins, and return final response
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* Utility functions for prompt concatenation
|
||||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { Observable, lastValueFrom } from 'rxjs';
|
||||
import { last } from 'rxjs/operators';
|
||||
import { PromptConcatStreamState } from './promptConcat';
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ export async function getFinalPromptResult(
|
|||
flatPrompts: PromptConcatStreamState['flatPrompts'];
|
||||
processedPrompts: PromptConcatStreamState['processedPrompts'];
|
||||
}> {
|
||||
const finalState = await last<PromptConcatStreamState>()(stream).toPromise();
|
||||
const finalState = await lastValueFrom(stream.pipe(last()));
|
||||
|
||||
if (!finalState) {
|
||||
throw new Error('Prompt concatenation stream ended without final result');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue