diff --git a/main.ts b/main.ts index 25aee30..ad05304 100644 --- a/main.ts +++ b/main.ts @@ -42,6 +42,9 @@ interface LLMAgentSettings { promptMetrics: string; markerStart: string; markerStop: string; + + lastActiveGraphId: string | null; + lastActiveNodeId: string | null; } const DEFAULT_SETTINGS: LLMAgentSettings = { @@ -71,7 +74,10 @@ const DEFAULT_SETTINGS: LLMAgentSettings = { promptCommands: '', promptMetrics: '', markerStart: 'старт', - markerStop: 'стоп' + markerStop: 'стоп', + + lastActiveGraphId: null, + lastActiveNodeId: null, }; // ----------------------------------------------- Main Plugin Class --------------------------------------------------------------- diff --git a/src/views/ChatView.ts b/src/views/ChatView.ts index af96902..80165a9 100644 --- a/src/views/ChatView.ts +++ b/src/views/ChatView.ts @@ -160,13 +160,25 @@ export class ChatView extends ItemView { async handleSendMessage(message: string, selectedModel?: string, attachments?: Attachment[], customMaxTokens?: number, customTemperature?: number): Promise { try { + // ЗАЩИТА: Если граф не выбран, создаем его на лету, чтобы не потерять текст if (!this.selectedGraphId) { - new Notice('Граф не выбран или не инициализирован. Пожалуйста, начните новый чат или выберите существующий.', 3000); - console.warn('selectedGraphId is null in handleSendMessage. Current state:', { - selectedGraphId: this.selectedGraphId, - currentNode: this.currentNode + const createResponse = await fetch(`${this.plugin.settings.apiBaseUrl}/graphs/new`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' } + }); + + if (!createResponse.ok) { + throw new Error(`Ошибка автоматического создания графа: ${createResponse.status}`); + } + + const createResult = await createResponse.json(); + this.selectedGraphId = createResult.graph_id; + + // Уведомляем другие компоненты о том, что выбран новый граф + this.plugin.eventBus.emit('graph-selected', { + graphId: this.selectedGraphId, + currentNode: null }); - return; } const cacheFolder = this.getCacheFolderPath(); diff --git a/src/views/GraphView.ts b/src/views/GraphView.ts index 3942e68..2bb0090 100644 --- a/src/views/GraphView.ts +++ b/src/views/GraphView.ts @@ -188,6 +188,9 @@ export class GraphView extends ItemView { // Загружаем данные await this.fetchGraphsList(); + + // Автоматический выбор стартового графа + await this.initializeInitialGraph(); } // Вынес для чистоты @@ -233,6 +236,48 @@ export class GraphView extends ItemView { this.plugin.eventBus.off('stream-ended', this.handleStreamEnded); } + // ----------------------------------------------- Save graph id --------------------------------------------------- + + /** + * Определяет, какой граф открыть при запуске (из настроек или последний свежий). + */ + private async initializeInitialGraph(): Promise { + const savedGraphId = (this.plugin.settings as any).lastActiveGraphId; + const savedNodeId = (this.plugin.settings as any).lastActiveNodeId; + + if (this.graphsList && this.graphsList.length > 0) { + // Проверяем, существует ли еще граф из настроек + const graphExists = this.graphsList.some(g => g.id === savedGraphId); + + if (savedGraphId && graphExists) { + // Вариант 1: Открываем граф из настроек + await this.fetchGraphData(savedGraphId); + if (savedNodeId) { + this.currentNode = savedNodeId; + } + // Синхронизируем интерфейс + this.plugin.eventBus.emit('graph-selected', { graphId: savedGraphId, currentNode: this.currentNode }); + } else { + // Вариант 2: Графа из настроек нет, берем самый свежий из истории + const mostRecentGraph = this.graphsList[0]; + await this.fetchGraphData(mostRecentGraph.id); + this.plugin.eventBus.emit('graph-selected', { graphId: mostRecentGraph.id, currentNode: this.currentNode }); + } + } else { + // Вариант 3: История вообще пуста, создаем новый чистый лист + await this.handleNewChat(); + } + } + + /** + * Сохраняет текущий граф и узел в настройки плагина + */ + private async saveCurrentStateToSettings(graphId: string | null, nodeId: string | null) { + (this.plugin.settings as any).lastActiveGraphId = graphId; + (this.plugin.settings as any).lastActiveNodeId = nodeId; + await this.plugin.saveSettings(); + } + // ----------------------------------------------- Custom Title Update --------------------------------------------------- /** @@ -506,6 +551,9 @@ export class GraphView extends ItemView { graph_id: graphId, custom_system_prompt: this.currentGraphCustomSystemPrompt }); + + // Сохраняем стейт в настройки при успешной загрузке + await this.saveCurrentStateToSettings(graphId, this.currentNode); } catch (error) { console.error('Ошибка загрузки данных графа:', error); this.selectedGraphTitle = null; @@ -621,6 +669,9 @@ export class GraphView extends ItemView { if (this.graphSettingsButton) { this.graphSettingsButton.setAttr('disabled', null); } + + // Обновляем настройки после создания нового чата + await this.saveCurrentStateToSettings(this.selectedGraphId, null); } catch (error: any) { console.error('Ошибка при создании нового чата:', error); new Notice(`Ошибка при создании нового чата: ${error?.message || error}`, 5000); @@ -647,7 +698,7 @@ export class GraphView extends ItemView { * Обработчик события выбора узла из других компонентов (например, ChatPanel). * Синхронизирует визуальное состояние графа (подсветку текущего узла). */ - private handleNodeSelectedFromBus = (data: { nodeId: string; graphId: string }) => { + private handleNodeSelectedFromBus = async (data: { nodeId: string; graphId: string }) => { // Реагируем только если это для нашего текущего графа if (this.selectedGraphId === data.graphId) { this.currentNode = data.nodeId; @@ -659,6 +710,9 @@ export class GraphView extends ItemView { // Перерисовываем канвас (это передаст новый activeNodeId в ReactFlow и сдвинет фокус) this.renderGraphPanel(); + + // Сохраняем в настройки переключение ветки + await this.saveCurrentStateToSettings(this.selectedGraphId, this.currentNode); } };