# Техническое Задание: Система Ссылок и Раскрытия Контента в LLM Agent Plugin Obsidian

## 1. Введение

Данный документ описывает функциональность системы ссылок и механизм раскрытия контента в плагине LLM Agent для Obsidian. Целью является предоставление пользователю возможности динамически включать содержимое файлов (заметок, документов, кода) и шаблонов (специальных промптов) в свои запросы к LLM-агенту, используя удобный синтаксис ссылок, автодополнение и визуальное представление.

Система вдохновлена подходом таких инструментов, как Continue.dev, но адаптирована под экосистему Obsidian и требования пользователя.

## 2. Терминология

*   **Ссылка:** Специальный синтаксис в сообщении пользователя, указывающий на файл или промпт в хранилище Obsidian.
*   **Одинарная ссылка:** Ссылка, содержимое которой раскрывается только один раз, при отправке текущего сообщения на сервер. В последующих сообщениях эта ссылка остаётся в своём исходном виде. Имеет префикс `@` (для файлов) или `#` (для промптов).
*   **Постоянная ссылка (Persistent Reference):** Ссылка, содержимое которой раскрывается при отправке *любого* сообщения пользователя, если она присутствовала в предыдущих сообщениях. Предназначена для поддержания постоянного контекста. Имеет префикс `@@` (для файлов) или `##` (для промптов).
*   **Промпт:** Markdown-файл, содержащий шаблон запроса или часть запроса для LLM. Хранится в специально выделенной папке.
*   **Шаблонная ссылка (Template Reference):** Ссылка внутри *промпта* на другой промпт. Использует синтаксис `@{prompt_name}`. Поддерживает только один уровень вложенности (нет рекурсии).
*   **Бокс ссылки (Reference Box):** Визуальное представление ссылки в поле ввода (contenteditable div) после её выбора пользователем через автодополнение. Содержит иконку и имя.
*   **Раскрытие контента (Content Expansion):** Процесс замены ссылки её фактическим содержимым файла или промпта перед отправкой запроса LLM-агенту.
*   **Снапшот (Snapshot):** Сохранённое содержимое файла на момент его раскрытия. (**TODO**: будет реализовано позднее в отдельной таблице БД.)

## 3. Требования к Функциональности

### 3.1. Синтаксис Ссылок в Поле Ввода

Система должна распознавать следующие типы ссылок:

*   **Ссылки на файлы:**
    *   `@<имя_файла>`: Одинарная ссылка на файл.
    *   `@@<имя_файла>`: Постоянная ссылка на файл.
*   **Ссылки на промпты:**
    *   `#<имя_промпта>`: Одинарная ссылка на промпт.
    *   `##<имя_промпта>`: Постоянная ссылка на промпт.

**Правила именования:**
*   `<имя_файла>` и `<имя_промпта>` должны соответствовать `basename` файла (название файла без расширения и пути).
*   Ссылки могут содержать пробелы, если имя файла/промпта заключено в кавычки, например, `@ "My Awesome File"`. В противном случае пробелы являются разделителями.

### 3.2. Автодополнение Ссылок (Autocomplete)

При вводе пользователем символов `@`, `@@`, `#`, `##` в поле ввода сообщения (ChatPanel), система должна показывать выпадающий список (autocomplete) релевантных файлов или промптов.

*   **Триггеры:** Ввод `@` или `#`. Автодополнение должно появляться, как только пользователь начинает вводить имя после префикса.
*   **Фильтрация:** Список должен фильтроваться по мере ввода имени файла/промпта.
*   **Опции:** Каждая опция в списке автодополнения должна включать:
    *   Иконку (соответствующую типу файла или промпту).
    *   Имя файла/промпта.
    *   Путь к файлу (относительно корня хранилища Obsidian, может быть сокращён).
*   **Навигация:** Пользователь должен иметь возможность навигировать по списку с помощью клавиш `ArrowUp`/`ArrowDown`.
*   **Выбор:** Выбор элемента осуществляется по `Enter` или `Tab` (или кликом).
*   **Позиционирование:** Выпадающий список должен позиционироваться динамически:
    *   Если есть место, он появляется под курсором.
    *   Если места снизу недостаточно, он появляется над курсором.
    *   Должен учитывать границы экрана.

### 3.3. Визуальное Представление Ссылок (Reference Boxes)

После выбора элемента из списка автодополнения, текстовое представление ссылки в поле ввода должно заменяться на визуальный "бокс ссылки".

*   **Состав бокса:** Иконка ( Obsidian icon, соответствующая типу) и имя файла/промпта.
*   **Стилизация:**
    *   Боксы для файлов (`@`/`@@`) и промптов (`#`/`##`) должны иметь отличающиеся цветовые схемы (фон, рамка).
    *   Боксы для одинарных ссылок (`@`/`#`) и постоянных ссылок (`@@`/`##`) должны иметь отличающиеся стили (например, более яркий фон/толстая рамка для постоянных).
*   **Интерактивность:** При клике на бокс, должна быть предусмотрена возможность предпросмотра содержимого файла/промпта (функциональность **TODO** для будущих итераций).
*   **Редактирование:** Пользователь должен иметь возможность удалять или редактировать боксы (например, нажать Delete/Backspace).
*   **Сохранение информации:** Бокс должен содержать данные, достаточные для восстановления исходной ссылки (тип, имя, путь, признак постоянной ссылки).

### 3.4. Раскрытие Контента перед Отправкой на Сервер

Перед отправкой сообщения пользователя на backend LLM-агента, все ссылки в сообщении должны быть раскрыты.

*   **Одинарные ссылки (`@`/`#`):** Содержимое файла/промпта раскрывается и вставляется *только* в текущее отправляемое сообщение. В истории чата (в поле ввода) ссылка остаётся как бокс или текстовое представление.
*   **Постоянные ссылки (`@@`/`##`):** Содержимое файла/промпта раскрывается и вставляется в текущее отправляемое сообщение. Более того, при загрузке истории для любого узла, если в этой истории есть сообщения пользователя с *постоянными* ссылками, их содержимое также должно быть раскрыто. Это обеспечивает поддержание постоянного контекста для LLM.
*   **Форматирование раскрытого контента:** Раскрытое содержимое должно быть обернуто специальными маркерами для ясности, например:
    ```
    --- Содержимое файла: my-file.md ---
    (текст файла)
    --- Конец файла: my-file.md ---
    ```
*   **Размер файла:** Нет явных ограничений на размер файла для раскрытия. В случае превышения разумного размера, пользователь и/или LLM-агент могут обрабатывать это (например, через суммаризацию, но это вне рамок данной задачи).
*   **Обработка ошибок:** Если файл/промпт не найден, вместо содержимого вставляется сообщение об ошибке (например, `[Ошибка: Файл "filename" не найден]`).
*   **TODO: Снапшоты:** В будущем будет реализована функция сохранения "снимка" содержимого файла на момент его раскрытия. Это позволит гарантировать воспроизводимость диалога, даже если исходный файл изменится.

### 3.5. Система Промптов и Шаблонные Ссылки

*   **Папка для промптов:** Пользователь должен указать путь к папке в настройках плагина, где хранятся все промпты. Все промпты являются Markdown-файлами (`.md`).
*   **Шаблонные ссылки ВНУТРИ промптов (`@{prompt_name}`):**
    *   Промпты могут содержать ссылки на другие промпты. Синтаксис: `@{prompt_name}`.
    *   **Ограничение:** Поддерживается только один уровень вложенности. То есть, промпт C не может ссылаться на промпт B, который в свою очередь ссылается на промпт A. (A -> B -> C -> LLM is OK, but A -> B -> C -> B -> LLM is not).
    *   **Пример:** `prompts/base-personality.md` может содержать текст, а `prompts/game-master.md` может начинаться с `@{base-personality}`.
*   **Наследование типа подстановки:** Если промпт `master-prompt` ссылается на `sub-prompt` через `@{sub-prompt}`, и `master-prompt` был вызван как `##master-prompt` (постоянная ссылка), то содержимое `sub-prompt` также должно раскрыться как часть постоянного контекста. То есть, тип (одинарный/постоянный) определяется префиксом (`#`/`##`) корневой ссылки пользователем в ChatPanel.
*   **Валидация промптов:** При сохранении промпта (или при попытке его раскрытия), система должна проверять корректность синтаксиса `@{...}` и наличие файлов, на которые ссылаются шаблонные ссылки. Ошибки должны быть зарегистрированы.

### 3.6. Настройки Плагина

В настройках плагина должны быть добавлены следующие опции:

*   **`promptsFolder`**: (Строка) Путь к папке, где хранятся Markdown-файлы промптов. По умолчанию: "prompts".
*   **`enableFileReferences`**: (Boolean) Включить/выключить функцию ссылок на файлы (@/@@). По умолчанию: `true`.
*   **`enablePromptReferences`**: (Boolean) Включить/выключить функцию ссылок на промпты (#/##). По умолчанию: `true`.

### 3.7. Интеграция с Backend

*   Frontend должен отправлять на backend *полностью раскрытый* текст сообщения.
*   Backend не должен знать о системе ссылок, он работает только с конечным текстом.
*   **TODO: Снапшоты (Backend):** Позднее, при реализации снапшотов, в модель данных `AgentState` и в базу данных (`graph_history_manager`) будут добавлены поля для хранения информации о раскрытых файлах и их содержимом.

### 3.8. Технические Требования

*   **Производительность:** Автодополнение и раскрытие контента должны работать быстро, не вызывая заметных задержек в UI.
*   **Совместимость:** Должна быть сохранена совместимость с существующей функциональностью плагина (слеш-команды, граф диалогов).
*   **Иконки:** Использовать стандартные иконки Obsidian.
*   **CSS:** Все новые стили должны быть аккуратно добавлены в `styles.css`.

## 4. Ограничения

*   **Отсутствие рекурсии в шаблонных ссылках (`@{...}`):** Промпт не может ссылаться на себя или на промпт, который явно или косвенно ссылается на него. Система должна обнаружить подобные попытки и выдать ошибку. (Текущее требование - только 1 уровень вложенности, что фактически исключает рекурсию)
*   **Снапшоты:** Отложенная функциональность.
*   **Предпросмотр контента:** Отложенная функциональность для клика по Reference Box.

---
**TODO:** (Для будущих итераций)

*   Реализовать сохранение снапшотов файлов в базе данных.
*   Добавить UI для предпросмотра содержимого Reference Box при клике.
*   Улучшить обработку ошибок (уведомления пользователю).
*   Оптимизация производительности для очень больших хранилищ с множеством файлов.
*   Поддержка других типов файлов (изображения, PDF) - раскрытие метаданных или ссылки на файл.
*   Управление версиями промптов, история изменений.