diff --git a/src/main/presenter/configPresenter/index.ts b/src/main/presenter/configPresenter/index.ts index 3c123abae..889f2e0ff 100644 --- a/src/main/presenter/configPresenter/index.ts +++ b/src/main/presenter/configPresenter/index.ts @@ -32,7 +32,7 @@ import { DEFAULT_PROVIDERS } from './providers' import path from 'path' import { app, nativeTheme, shell, ipcMain } from 'electron' import fs from 'fs' -import { CONFIG_EVENTS, SYSTEM_EVENTS, FLOATING_BUTTON_EVENTS } from '@/events' +import { CONFIG_EVENTS, SYSTEM_EVENTS, FLOATING_BUTTON_EVENTS, SESSION_EVENTS } from '@/events' import { McpConfHelper } from './mcpConfHelper' import { presenter } from '@/presenter' import { compare } from 'compare-versions' @@ -1329,6 +1329,7 @@ export class ConfigPresenter implements IConfigPresenter { private notifyAcpAgentsChanged() { console.log('[ACP] notifyAcpAgentsChanged: sending MODEL_LIST_CHANGED event for provider "acp"') eventBus.sendToRenderer(CONFIG_EVENTS.MODEL_LIST_CHANGED, SendTarget.ALL_WINDOWS, 'acp') + eventBus.sendToRenderer(SESSION_EVENTS.LIST_UPDATED, SendTarget.ALL_WINDOWS) } // Provide getMcpConfHelper method to get MCP configuration helper diff --git a/src/main/presenter/newAgentPresenter/index.ts b/src/main/presenter/newAgentPresenter/index.ts index 6f290d6dd..b1b1b91f8 100644 --- a/src/main/presenter/newAgentPresenter/index.ts +++ b/src/main/presenter/newAgentPresenter/index.ts @@ -365,14 +365,10 @@ export class NewAgentPresenter { const enriched: SessionWithState[] = [] for (const record of records) { - const agent = await this.resolveAgentImplementation(record.agentId) - const state = await agent.getSessionState(record.id) - enriched.push({ - ...record, - status: state?.status ?? 'idle', - providerId: state?.providerId ?? '', - modelId: state?.modelId ?? '' - }) + const session = await this.tryBuildSessionWithState(record) + if (session) { + enriched.push(session) + } } return enriched @@ -381,14 +377,7 @@ export class NewAgentPresenter { async getSession(sessionId: string): Promise { const record = this.sessionManager.get(sessionId) if (!record) return null - const agent = await this.resolveAgentImplementation(record.agentId) - const state = await agent.getSessionState(sessionId) - return { - ...record, - status: state?.status ?? 'idle', - providerId: state?.providerId ?? '', - modelId: state?.modelId ?? '' - } + return await this.tryBuildSessionWithState(record) } async getMessages(sessionId: string): Promise { @@ -556,7 +545,11 @@ export class NewAgentPresenter { async getActiveSession(webContentsId: number): Promise { const sessionId = this.sessionManager.getActiveSessionId(webContentsId) if (!sessionId) return null - return this.getSession(sessionId) + const session = await this.getSession(sessionId) + if (!session) { + this.sessionManager.unbindWindow(webContentsId) + } + return session } async getAgents(): Promise { @@ -891,6 +884,29 @@ export class NewAgentPresenter { return false } + private async buildSessionWithState(record: SessionRecord): Promise { + const agent = await this.resolveAgentImplementation(record.agentId) + const state = await agent.getSessionState(record.id) + return { + ...record, + status: state?.status ?? 'idle', + providerId: state?.providerId ?? '', + modelId: state?.modelId ?? '' + } + } + + private async tryBuildSessionWithState(record: SessionRecord): Promise { + try { + return await this.buildSessionWithState(record) + } catch (error) { + console.warn( + `[NewAgentPresenter] Skipping unavailable session id=${record.id} agent=${record.agentId}:`, + error + ) + return null + } + } + private async resolveAgentImplementation(agentId: string): Promise { if (this.agentRegistry.has(agentId)) { return this.agentRegistry.resolve(agentId) diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index c44294752..6036ffb1c 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -14,6 +14,10 @@ declare global { toRelativePath?(filePath: string, baseDir?: string): string formatPathForInput?(filePath: string): string } + __deepchatDev?: { + goToWelcome(): boolean + clearWelcomeOverride(): boolean + } floatingButtonAPI: typeof floatingButtonAPI } } diff --git a/src/preload/index.ts b/src/preload/index.ts index b789aba1b..8d0b5c4e5 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -11,6 +11,9 @@ import { import { exposeElectronAPI } from '@electron-toolkit/preload' const ALLOWED_PROTOCOLS = ['http:', 'https:', 'mailto:', 'tel:', 'deepchat:'] +const isDevHiddenApiEnabled = + process.env.NODE_ENV === 'development' || Boolean(process.env.ELECTRON_RENDERER_URL) +const DEV_WELCOME_OVERRIDE_KEY = '__deepchat_dev_force_welcome' const isValidExternalUrl = (url: string): boolean => { try { @@ -101,6 +104,33 @@ const api = { return `'${filePath.replace(/'/g, `'\\''`)}'` } } + +const setDevWelcomeOverride = (enabled: boolean) => { + try { + if (enabled) { + window.sessionStorage.setItem(DEV_WELCOME_OVERRIDE_KEY, '1') + } else { + window.sessionStorage.removeItem(DEV_WELCOME_OVERRIDE_KEY) + } + } catch (error) { + console.warn('Preload: Failed to update dev welcome override:', error) + } +} + +const deepchatDevApi = isDevHiddenApiEnabled + ? { + goToWelcome: () => { + setDevWelcomeOverride(true) + window.location.hash = '/welcome' + return true + }, + clearWelcomeOverride: () => { + setDevWelcomeOverride(false) + return true + } + } + : undefined + exposeElectronAPI() // Use `contextBridge` APIs to expose Electron APIs to @@ -109,12 +139,19 @@ exposeElectronAPI() if (process.contextIsolated) { try { contextBridge.exposeInMainWorld('api', api) + if (deepchatDevApi) { + contextBridge.exposeInMainWorld('__deepchatDev', deepchatDevApi) + } } catch (error) { console.error('Preload: Failed to expose API via contextBridge:', error) } } else { // @ts-ignore (define in dts) window.api = api + if (deepchatDevApi) { + // @ts-ignore (define in dts) + window.__deepchatDev = deepchatDevApi + } } window.addEventListener('DOMContentLoaded', () => { cachedWebContentsId = ipcRenderer.sendSync('get-web-contents-id') diff --git a/src/renderer/settings/components/ProviderModelList.vue b/src/renderer/settings/components/ProviderModelList.vue index cd38a08bd..66fb5f4f5 100644 --- a/src/renderer/settings/components/ProviderModelList.vue +++ b/src/renderer/settings/components/ProviderModelList.vue @@ -63,13 +63,13 @@ -
+
{{ item.label }}
{{ getProviderName(item.providerId) }}
@@ -94,7 +94,7 @@
-
+
(() => { return items }) +const isLabelItem = (item: unknown): item is Extract => { + return ( + typeof item === 'object' && item !== null && (item as VirtualModelListItem).type === 'label' + ) +} + +const isProviderActionsItem = ( + item: unknown +): item is Extract => { + return ( + typeof item === 'object' && + item !== null && + (item as VirtualModelListItem).type === 'provider-actions' + ) +} + +const isModelItem = (item: unknown): item is Extract => { + return ( + typeof item === 'object' && item !== null && (item as VirtualModelListItem).type === 'model' + ) +} + const getItemSizeDependencies = (item: VirtualModelListItem) => { if (item.type === 'model') { return [ @@ -270,6 +292,10 @@ const getItemSizeDependencies = (item: VirtualModelListItem) => { return [item.label] } +const getScrollerItemSizeDependencies = (item: unknown) => { + return getItemSizeDependencies(item as VirtualModelListItem) +} + const getProviderName = (providerId: string) => { const provider = props.providers.find((p) => p.id === providerId) return provider?.name || providerId diff --git a/src/renderer/src/App.vue b/src/renderer/src/App.vue index c8c0a10fc..8a1794677 100644 --- a/src/renderer/src/App.vue +++ b/src/renderer/src/App.vue @@ -26,6 +26,8 @@ import AppBar from '@/components/AppBar.vue' import { useDeviceVersion } from '@/composables/useDeviceVersion' import WindowSideBar from './components/WindowSideBar.vue' +const DEV_WELCOME_OVERRIDE_KEY = '__deepchat_dev_force_welcome' + const route = useRoute() const configPresenter = usePresenter('configPresenter') const artifactStore = useArtifactStore() @@ -144,11 +146,45 @@ const handleErrorClosed = () => { const router = useRouter() const activeTab = ref('chat') +const isStartupRouteReady = ref(false) + +const isDevWelcomeOverrideEnabled = () => { + if (!import.meta.env.DEV) return false + + try { + return window.sessionStorage.getItem(DEV_WELCOME_OVERRIDE_KEY) === '1' + } catch { + return false + } +} + +const ensureStartupWelcomeState = async () => { + try { + await router.isReady() + + const currentRoute = router.currentRoute.value + const isWelcomeRoute = currentRoute.name === 'welcome' || currentRoute.path === '/welcome' -const getInitComplete = async () => { - const initComplete = await configPresenter.getSetting('init_complete') - if (!initComplete) { - router.push({ name: 'welcome' }) + if (isDevWelcomeOverrideEnabled()) { + if (!isWelcomeRoute) { + await router.replace({ name: 'welcome' }) + } + return + } + + const initComplete = Boolean(await configPresenter.getSetting('init_complete')) + if (!initComplete) { + if (!isWelcomeRoute) { + await router.replace({ name: 'welcome' }) + } + return + } + + if (isWelcomeRoute) { + await router.replace({ name: 'chat' }) + } + } finally { + isStartupRouteReady.value = true } } @@ -192,7 +228,7 @@ const handleEscKey = (event: KeyboardEvent) => { } } -getInitComplete() +void ensureStartupWelcomeState() onMounted(() => { // Set initial body class @@ -332,7 +368,7 @@ onBeforeUnmount(() => {
- +
diff --git a/src/renderer/src/components/mock/MockWelcomePage.vue b/src/renderer/src/components/mock/MockWelcomePage.vue index 9cf97e9d7..b25407d95 100644 --- a/src/renderer/src/components/mock/MockWelcomePage.vue +++ b/src/renderer/src/components/mock/MockWelcomePage.vue @@ -7,9 +7,11 @@ -

Welcome to DeepChat Agent

+

+ {{ t('welcome.page.title') }} +

- Connect a model provider to start build + {{ t('welcome.page.description') }}

@@ -21,7 +23,7 @@ @click="onAddProvider" > - {{ provider.name }} + {{ t(provider.nameKey) }} @@ -29,27 +31,27 @@ class="text-xs text-muted-foreground hover:text-foreground transition-colors mb-12" @click="onAddProvider" > - Browse all providers... + {{ t('welcome.page.browseProviders') }}
- or connect an agent + {{ t('welcome.page.connectAgent') }}
@@ -60,28 +62,56 @@