agent-Specialization/static/src/app/state.ts
JOJO 4c3d8cedc7 feat(ui): 计划批准弹窗支持最小化关闭,状态栏可恢复处理
- PlanApprovalDialog windowbar 新增关闭(X)按钮,点击后弹窗收起不打扰
- InputComposer 底部状态栏新增「有待批准的计划」按钮(对齐等待回答问题交互),点击恢复弹窗
- floatingStatusVisible 可见性判断纳入计划批准最小化状态,修复弹窗收起后浮栏不渲染的问题
- 批准解决后自动复位最小化状态,避免按钮残留
2026-08-30 00:33:34 +08:00

377 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// @ts-nocheck
import { t } from '@/locales';
import { ICONS, TOOL_CATEGORY_ICON_MAP } from '../utils/icons';
/* host/docker 模式缓存:模式是部署级属性几乎不变,首屏用缓存值渲染
工作区入口按钮(按钮显隐依赖这两个 flagsocket 连接后校正并回写,
避免按钮在初始化完成前「延迟零点几秒才出现」。 */
const WORKSPACE_MODE_STORAGE_KEY = 'agents_workspace_mode';
const loadCachedWorkspaceMode = (): 'host' | 'docker' | null => {
try {
const v = window.localStorage.getItem(WORKSPACE_MODE_STORAGE_KEY);
return v === 'host' || v === 'docker' ? v : null;
} catch {
return null;
}
};
export const persistWorkspaceMode = (isHostMode: boolean): void => {
try {
window.localStorage.setItem(WORKSPACE_MODE_STORAGE_KEY, isHostMode ? 'host' : 'docker');
} catch {
/* ignore */
}
};
/* 待创建对话类型缓存:/new 页输入栏「智能体/多智能体」选择器的上次选择,
刷新后恢复,避免每次新建都要重新选。 */
const NEW_CONVERSATION_TYPE_STORAGE_KEY = 'agents_new_conversation_type';
const loadNewConversationType = (): 'agent' | 'multi_agent' => {
try {
const v = window.localStorage.getItem(NEW_CONVERSATION_TYPE_STORAGE_KEY);
return v === 'multi_agent' ? 'multi_agent' : 'agent';
} catch {
return 'agent';
}
};
export const persistNewConversationType = (type: string): void => {
try {
window.localStorage.setItem(NEW_CONVERSATION_TYPE_STORAGE_KEY, type);
} catch {
/* ignore */
}
};
const cachedWorkspaceMode = loadCachedWorkspaceMode();
const cachedNewConversationType = loadNewConversationType();
export function dataState() {
return {
// 路由相关
initialRouteResolved: false,
dropToolEvents: false,
// 工作流编辑器 demo 路由('workflows' | 'workflow/<name>',空串 = 不在 demo 视图)
workflowDemoRoute: '',
// 当前打开对话的类型('normal' | 'multi_agent',创建时确定、不可变);
// 空对话态为 null。权威来源是对话 metadata.multi_agent_mode。
currentConversationType: null,
// /new 页输入栏选择器的待创建类型('agent' | 'multi_agent'localStorage 持久化)
newConversationType: cachedNewConversationType,
// 输入栏类型选择器菜单开关
agentTypeMenuOpen: false,
// 多智能体索引重建触发去重(每次页面加载最多一次)
multiAgentIndexRebuildTriggered: false,
// 轮询模式标志(禁用 WebSocket 事件处理)
usePollingMode: true,
// 后台子智能体等待状态
waitingForSubAgent: false,
// 后台 run_command 等待状态(用于文案区分)
waitingForBackgroundCommand: false,
// 是否在对话区展示 system 消息
hideSystemMessages: true,
// 工具状态跟踪
preparingTools: new Map(),
activeTools: new Map(),
toolActionIndex: new Map(),
toolStacks: new Map(),
// 当前任务是否仍在进行中(用于保持输入区的"停止"状态)
taskInProgress: false,
// 等待 API 响应:对话运行期间后端已发出 API 请求、尚未收到首个响应事件
// (由后端 api_request_start 事件置位thinking_start/text_start/tool_preparing/
// error/任务终结时清除),用于状态头像显示「等待 API 响应…」
apiRequestPending: false,
// 对话运行状态对账定时器事件为主、2.5s 对账纠偏,冲突以对账为准)
runningStateReconcileTimer: null,
// 对账清理方向的连续空闲确认计数(防 notice/idle dispatch 间隙误清)
_runningStateIdleStreak: 0,
// 宿主机多工作区任务列表后台刷新定时器(用于当前未查看运行对话时同步完成态)
runningWorkspaceTasksRefreshTimer: null,
// 运行期消息堆积(提前发送 / 引导对话)
runtimeQueuedMessages: [],
runtimeGuidanceFallbackQueue: [],
runtimeQueueSuppressedMessageIds: new Set(),
runtimeGuidanceSuppressedTextCounts: {},
runtimeQueueLimit: 5,
runtimeQueueAutoSendInProgress: false,
runtimeQueueSyncLockKey: '',
runtimeQueueSyncLockUntil: 0,
projectGitSummary: null,
projectGitSummaryRefreshTimer: null,
terminalCountRefreshTimer: null,
projectGitSummaryRefreshing: false,
gitChangesPanelOpen: false,
gitChangesLoading: false,
gitChangesError: '',
gitChangesContext: 3,
gitChangesFileContexts: {},
gitChangesFoldContexts: {},
gitChangesDiff: null,
// 实时终端面板
terminalPanelOpen: false,
terminalSessions: {} as Record<string, { working_dir?: string; shell?: string }>,
terminalActiveSession: '',
terminalSessionLogs: {} as Record<string, string>,
terminalHydrated: {} as Record<string, boolean>,
terminalCount: 0,
// 上一次检测到的终端数量,用于判断 0→>0自动开和 >0→0自动关
previousTerminalCount: 0,
// 右侧面板上下分割比例(终端占比 0.15~0.85
rightSplitRatio: 0.5,
// 输入区动态保留高度(用于同步扩大消息区可滚动范围)
composerReservedHeight: 80,
// 记录上一次成功加载历史的对话ID防止初始化阶段重复加载导致动画播放两次
lastHistoryLoadedConversationId: null,
// ==========================================
// 对话管理相关状态
// ==========================================
// 搜索功能
// ==========================================
searchRequestSeq: 0,
searchActiveQuery: '',
// Token统计相关状态修复版
// ==========================================
// 对话压缩状态
compressing: false,
compressionInProgress: false,
// 正在压缩的对话 id压缩锁只作用于该对话本身不影响其他对话与 /new 新建页
// (多对话独立运行后,压缩不再是对话级全局锁)。
compressionConversationId: null,
compressionMode: '',
compressionStage: '',
compressionError: '',
compressionToastId: null,
skipConversationLoadedEvent: false,
skipConversationHistoryReload: false,
_scrollListenerReady: false,
historyLoading: false,
historyLoadingFor: null,
historyLoadSeq: 0,
blankHeroActive: false,
blankHeroExiting: false,
blankWelcomeText: '',
lastBlankConversationId: null,
// 对话标题打字效果
titleTypingText: '',
titleTypingTarget: '',
titleTypingTimer: null,
titleReady: false,
suppressTitleTyping: false,
headerMenuOpen: false,
blankWelcomePool: [
t('appCore.welcomeHelp'),
t('appCore.welcomeHot'),
t('appCore.welcomeHomework'),
t('appCore.welcomeCode'),
t('appCore.welcomeChat'),
t('appCore.welcomeOrganize'),
t('appCore.welcomeTool'),
t('appCore.welcomeContinue'),
t('appCore.welcomeDraw'),
t('appCore.welcomeCat'),
t('appCore.welcomePuzzle'),
t('appCore.welcomeFun'),
t('appCore.welcomeNeed')
],
mobileViewportQuery: null,
modeMenuOpen: false,
modelMenuOpen: false,
permissionMenuOpen: false,
currentPermissionMode: 'unrestricted',
pendingPermissionMode: '',
executionModeEnabled: false,
currentExecutionMode: 'sandbox',
pendingExecutionMode: '',
networkPermissionEnabled: false,
currentNetworkPermission: 'restricted',
pendingNetworkPermission: '',
networkPermissionOptions: [
{
value: 'restricted',
labelKey: 'appUi.networkRestricted',
descriptionKey: 'appCore.networkRestrictedDesc'
},
{
value: 'full',
labelKey: 'appUi.networkFull',
descriptionKey: 'appCore.networkFullDesc'
}
],
workModeMenuOpen: false,
currentWorkMode: 'plan',
workModeOptions: [
{
value: 'plan',
labelKey: 'appUi.workModePlan',
descriptionKey: 'appCore.workModePlanDesc'
},
{
value: 'ask',
labelKey: 'appUi.workModeAsk',
descriptionKey: 'appCore.workModeAskDesc'
},
{
value: 'execute',
labelKey: 'appUi.workModeExecute',
descriptionKey: 'appCore.workModeExecuteDesc'
}
],
pathAuthorizationDialogOpen: false,
pathAuthorizationMode: 'writable',
pathAuthorizationWritableDraft: '',
pathAuthorizationReadableDraft: '',
pathAuthorizationDraft: '',
pathAuthorizationSaving: false,
versioningHostMode: cachedWorkspaceMode === 'host',
dockerProjectMode: cachedWorkspaceMode === 'docker',
hostWorkspaces: [],
currentHostWorkspaceId: '',
defaultHostWorkspaceId: '',
hostWorkspaceSwitching: false,
hostWorkspaceCreatePath: '',
hostWorkspaceCreateLabel: '',
hostWorkspaceCreateSubmitting: false,
hostWorkspaceCreateError: '',
hostWorkspaceManageSubmitting: false,
versioningEnabled: false,
versioningTrackingMode: 'conversation_only',
versioningMode: 'overwrite',
versioningDialogOpen: false,
versioningLoading: false,
versioningCheckpoints: [],
versioningSelectedSeq: null,
versioningSelectedDetail: null,
versioningDetailLoading: false,
versioningRestoring: false,
versioningRestoreMode: 'overwrite',
versioningInitializingBackupToastId: null,
permissionModeOptions: [
{
value: 'readonly',
labelKey: 'personalization.permissionReadonly',
descriptionKey: 'appCore.permissionReadonlyDesc'
},
{
value: 'approval',
labelKey: 'appCore.permissionApproval',
descriptionKey: 'appCore.permissionApprovalDesc'
},
{
value: 'auto_approval',
labelKey: 'appCore.permissionAutoApproval',
descriptionKey: 'appCore.permissionAutoApprovalDesc'
},
{
value: 'unrestricted',
labelKey: 'appCore.permissionUnrestricted',
descriptionKey: 'appCore.permissionUnrestrictedDesc'
}
],
executionModeOptions: [
{
value: 'sandbox',
labelKey: 'input.executionSandbox',
descriptionKey: 'appCore.executionSandboxDesc'
},
{
value: 'direct',
labelKey: 'input.executionFullAccess',
descriptionKey: 'appCore.executionDirectDesc'
}
],
pendingToolApprovals: [],
decidingApprovalIds: [],
pendingUserQuestions: [],
pendingPlanApprovals: [],
answeringPlanApprovalIds: [],
planApprovalMinimized: false,
userQuestionDialogVisible: false,
userQuestionMinimized: false,
userQuestionActiveIndex: 0,
answeringUserQuestionIds: [],
userQuestionOriginalTitle: '',
userQuestionTitleBlinkTimer: null,
userQuestionTitleBlinkRed: true,
autoApprovalFeedLines: [],
autoApprovalFinalMessage: '',
autoApprovalTitle: t('appTasks.autoApprovalRecordTitle'),
approvalAutoCloseTimer: null,
imageEntries: [],
imageLoading: false,
videoEntries: [],
videoLoading: false,
conversationHasImages: false,
conversationHasVideos: false,
conversationListRequestSeq: 0,
conversationListRefreshToken: 0,
connectionHeartbeatTimer: null,
connectionHeartbeatActive: false,
connectionHeartbeatFailCount: 0,
connectionHeartbeatSeq: 0,
connectionHeartbeatLastLatencyMs: 0,
connectionHeartbeatLastError: '',
connectionHeartbeatLastStatusCode: null,
connectionHeartbeatLastChangeAt: 0,
connectionHeartbeatInFlight: false,
connectionHeartbeatFailThreshold: 3,
connectionHeartbeatRequestTimeoutMs: 5000,
connectionHeartbeatIntervalMs: 8000,
connectionHeartbeatDisconnectedIntervalMs: 1000,
composerDraftSaveTimer: null,
composerDraftDirty: false,
composerDraftLastSyncedContent: '',
composerDraftFetchSeq: 0,
// 工具控制菜单
icons: ICONS,
toolCategoryIcons: TOOL_CATEGORY_ICON_MAP,
// 对话回顾
reviewDialogOpen: false,
reviewSelectedConversationId: null,
reviewSubmitting: false,
reviewPreviewLines: [],
reviewPreviewLoading: false,
reviewPreviewError: null,
reviewPreviewLimit: 20,
reviewSendToModel: true,
reviewGeneratedPath: null,
// 回顾弹窗独立的对话列表(只含有内容的对话,不污染侧边栏)
reviewConversations: [],
reviewListLoading: false,
reviewListLoadingMore: false,
reviewListHasMore: false,
reviewListOffset: 0,
reviewListLimit: 20,
// 新手教程首次引导弹窗
tutorialPromptVisible: false,
tutorialPromptLoading: false,
tutorialPromptUsername: '',
// 拖拽上传状态
dragOverActive: false,
// 拖拽事件绑定函数(用于正确移除监听)
_boundDragEnter: null,
_boundDragOver: null,
_boundDragLeave: null,
_boundDrop: null,
_manualScrollSuppressUntil: 0,
_escapedByUserScroll: false,
_autoRelockCooldownUntil: 0,
// stick-to-bottom 状态(用于“回到底部”按钮显隐)
stickIsAtBottom: true,
stickIsNearBottom: true
};
}