diff --git a/NAVI.md b/NAVI.md index 486eeb2..a19396b 100644 --- a/NAVI.md +++ b/NAVI.md @@ -22,8 +22,9 @@ | `tools/` | User tools (auto-loaded at startup) | | `tools/enabled.json` | Tools enabled across all profiles | | `persona.txt` | Global persona injected into every profile | -| `navi.db` | SQLite session store | -| `workspace/` | Persistent working files | +| `DATABASE_URL` | PostgreSQL session + memory store | +| `workspace/` | Persistent private working files for Navi | +| `session_files/{session_id}/` | Per-session uploads and publishable chat artifacts (`SESSION_FILES_DIR`) | | `manuals/` | Tool manuals (served by `tool_manual`) | ## Documentation @@ -50,7 +51,7 @@ Call the `tool_manual` tool with the relevant tool name. -Manuals exist for: `write_tool`, `spawn_agent`, `reflect`, `gmail`, `share_file`. +Manuals exist for: `write_tool`, `spawn_agent`, `reflect`, `gmail`, `share_file`, `content_publish`. ## Extending Navi @@ -62,3 +63,4 @@ - Before asking the user for project facts, proactively check nearest `NAVI.md`, then `docs/`, `manuals/`, memory, files, tool schemas, or web sources. - Treat `NAVI.md` as the active operational notebook for its directory, not just static project documentation. Update it with stable commands, conventions, local quirks, and current project decisions. - For Navi internals, use `docs/index.md` as the documentation map before scanning broad source trees. +- File-location rule: `workspace/` is persistent/private working storage; `session_files/{session_id}/` is the per-session area for uploads and files that `content_publish` can show in chat. To publish an artifact, put the final file in the session directory first; `content_publish` only registers it and does not copy from `workspace/`. diff --git a/README.md b/README.md index a5d6e77..4ef505a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ navi-1 =============== -Модульная агентная система с REST API и WebSocket. FastAPI бэкенд, Ollama LLM, vanilla JS клиент. +Модульная агентная система с REST API и WebSocket. FastAPI бэкенд, Ollama LLM, Vue 3 + Pinia клиент. ## Запуск @@ -90,7 +90,7 @@ ├── enabled.json # список инструментов, активных во всех профилях ├── _template.py # шаблон формата ├── get_current_datetime.py -├── user_notes.py +├── gmail.py └── weather.py manuals/ # markdown-мануалы для tool_manual @@ -102,12 +102,13 @@ | ID | Назначение | Температура | Планирование | |----|-----------|-------------|--------------| -| `secretary` | Исследования, написание текстов, повседневные задачи | 0.7 | ✓ | -| `server_admin` | Администрирование серверов, мониторинг, инфраструктура | 0.2 | ✓ | -| `smart_home` | Home Assistant, IoT, автоматизации | 0.3 | ✓ | -| `developer` | Написание, тестирование и отладка пользовательских инструментов | 0.2 | ✓ | +| `secretary` | Исследования, написание текстов, повседневные задачи | 0.65 | ✓ | +| `server_admin` | Администрирование серверов, мониторинг, инфраструктура | 0.3 | ✓ | +| `developer` | Разработка, анализ кода, архитектура | 0.45 | ✓ | +| `tool_developer` | Написание, тестирование и отладка пользовательских инструментов | 0.35 | ✓ | +| `discuss` | Свободное обсуждение, мозговой штурм, лёгкие беседы | 0.85 | — | -Каждый профиль определяет свой набор `enabled_tools`. `developer` — единственный профиль с `reload_tools`, `delete_tool` и `test_tool`; остальные профили не имеют доступа к инструментам разработки. +`tool_developer` — единственный профиль с `reload_tools`, `delete_tool` и `test_tool`. ## Расширение diff --git a/docs/architecture.md b/docs/architecture.md index e95a721..beb99a9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -37,13 +37,13 @@ ▼ ▼ ▼ ┌────────┐ ┌──────────────┐ ┌────────────────────────┐ │ LLM │ │ ToolRegistry│ │ SessionStore │ -│Backend │ │ (built-ins │ │ (SQLite / in-memory) │ +│Backend │ │ (built-ins │ │ (PostgreSQL) │ │(Ollama)│ │ + user tools│ │ │ └────────┘ └──────────────┘ └────────────────────────┘ │ ┌─────────┴──────────┐ │ MemoryStore │ - │ (SQLite facts) │ + │ (PostgreSQL + pgvector) │ └────────────────────┘ ``` diff --git a/docs/profiles.md b/docs/profiles.md index 910901b..70d0a61 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -80,10 +80,11 @@ | ID | Name | Models (priority order) | Temp | Planning | |---|---|---|---|---| -| `secretary` | Personal Secretary | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.7 | Yes | -| `server_admin` | Server Administrator | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.2 | Yes | -| `developer` | Developer | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.2 | Yes | -| `tool_developer` | Tool Developer | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.2 | Yes | +| `secretary` | Personal Secretary | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.65 | Yes | +| `server_admin` | Server Administrator | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.3 | Yes | +| `developer` | Developer | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.45 | Yes | +| `tool_developer` | Tool Developer | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.35 | Yes | +| `discuss` | Discussion | gemma4:31b-cloud → gemma4:26b-a4b-it-q4_K_M | 0.85 | No | All profiles share a base tool set. User tools from `tools/enabled.json` are merged in at runtime. diff --git a/docs/sessions.md b/docs/sessions.md index afba2bf..9447383 100644 --- a/docs/sessions.md +++ b/docs/sessions.md @@ -108,8 +108,7 @@ Files uploaded via `POST /sessions/{id}/files` are stored in `session_files/{session_id}/`. - Max size: `session_files_max_size_mb` (default: 200 MB) -- TTL: `session_files_ttl_hours` (default: 24 hours) -- A background `cleanup_loop` (started on FastAPI startup) deletes stale session directories. +- A background `cleanup_loop` (started on FastAPI startup) deletes orphaned session directories after their DB session no longer exists. - Executable files (`.sh`, `.py`, `.exe`, etc.) are rejected. - Duplicate filenames get a numeric suffix. @@ -121,6 +120,8 @@ This lets the agent use `filesystem` or `code_exec` to access the files. +`workspace/` is separate from session files. Use `workspace/` for persistent private working files and `session_files/{session_id}/` for files that belong to the current chat. Published content uses the same session directory: `content_publish` registers a file that already exists there and exposes it through `/sessions/{id}/files/{filename}`. + --- ## Debug endpoints diff --git a/docs/tools.md b/docs/tools.md index 71f476e..d993fc9 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -24,10 +24,17 @@ | `WriteToolTool` | `write_tool` | Write a new user tool file and reload immediately | | `ListToolsTool` | `list_tools` | Return the live tool list from registry | | `ToolManualTool` | `tool_manual` | Return manuals/{name}.md or auto-generate from schema | +| `MemorySaveTool` | `memory_save` | Save a fact to long-term memory | | `MemorySearchTool` | `memory_search` | Search long-term memory facts | | `MemoryForgetTool` | `memory_forget` | Delete a fact from long-term memory | | `SpawnAgentTool` | `spawn_agent` | Spawn an isolated subagent (blocking, synchronous from caller's view) | | `SwitchProfileTool` | `switch_profile` | Switch the active profile for a session | +| `ListProfilesTool` | `list_profiles` | List all available profiles | +| `ContentPublishTool` | `content_publish` | Publish a session file for inline viewing in chat | +| `ShareFileTool` | `share_file` | Share a file with the user | +| `DeleteToolTool` | `delete_tool` | Delete a user tool file | +| `TestToolTool` | `test_tool` | Run a user tool and verify its output | +| `ReflectTool` | `reflect` | Self-reflection and analysis | ### User tools (`tools/*.py`) @@ -37,7 +44,7 @@ - `tools/enabled.json` — list of user tool names to include in all profiles automatically. - `tools/_template.py` — canonical format reference (not loaded). -Currently present: `get_current_datetime.py`, `user_notes.py`, `text_formatter.py`, `internal_monitor.py`, `weather.py`, `gmail.py`, `instagram_engine.py`, `instagram_viewer.py`. +Currently present: `get_current_datetime.py`, `gmail.py`, `weather.py`. --- diff --git a/manuals/content_publish.md b/manuals/content_publish.md index 3015145..7578026 100644 --- a/manuals/content_publish.md +++ b/manuals/content_publish.md @@ -2,11 +2,18 @@ ## Что делает -Публикует файл из директории сессии для просмотра пользователем прямо в чате. Поддерживаются интерактивные viewer'ы для 3D-моделей (STL), HTML-страниц, SVG, PDF, изображений и видео. +Публикует файл из директории текущей сессии для просмотра пользователем прямо в чате. Поддерживаются интерактивные viewer'ы для 3D-моделей (STL), HTML-страниц, SVG, PDF, изображений и видео. + +Важно: `workspace/` и директория сессии — разные места. + +- `workspace/` — постоянная приватная рабочая зона Нави для черновиков, скриптов, заметок, промежуточных данных и файлов, которые могут пригодиться позже. +- `session_files/{session_id}/` — временная зона конкретной сессии для загруженных пользователем файлов и артефактов, которые пользователь должен увидеть в чате. +- `content_publish` публикует только файлы из директории текущей сессии. Он не копирует файлы из `workspace/`. +- Если нужен только download link для файла из `workspace/`, используйте `share_file`: он сам копирует файл в директорию сессии. Если нужен inline viewer, файл должен оказаться в директории сессии, а затем его нужно зарегистрировать через `content_publish`. ## Как работает внутри -1. **Файл уже должен быть в директории сессии** (`uploads/sessions/{session_id}/`). +1. **Файл уже должен быть в директории сессии** (`session_files/{session_id}/` по умолчанию; точный корень задаёт `SESSION_FILES_DIR`). 2. Инструмент **не копирует** файл — он только регистрирует метаданные в базе данных. 3. Пользователь видит файл по URL `/sessions/{session_id}/files/{filename}`. 4. Если вы отредактируете файл после публикации, пользователь увидит изменения **сразу** (перезагружать страницу не нужно). @@ -23,14 +30,14 @@ ## Где находится директория сессии -Директория сессии — это `uploads/sessions/{session_id}/`. Полный путь зависит от настроек сервера. +Директория сессии — это `session_files/{session_id}/` по умолчанию. Полный путь зависит от настройки `SESSION_FILES_DIR`. **Как узнать путь:** ``` -filesystem info uploads/sessions/{session_id} +filesystem info session_files/{session_id} ``` -Или просто пишите файлы относительно текущей директории — если вы уже в рабочей директории, используйте полный путь через `filesystem write`. +Если `content_publish` не нашёл файл, он вернёт точный путь директории текущей сессии. Доверяйте этому пути и пишите/копируйте файл туда. ## Типичный workflow @@ -38,7 +45,7 @@ ``` # Создать SVG в директории сессии -filesystem write uploads/sessions/sess-abc/chart.svg "..." +filesystem write session_files/sess-abc/chart.svg "..." # Опубликовать content_publish(filename="chart.svg", title="Диаграмма продаж") @@ -48,10 +55,10 @@ ``` # Прочитать текущий файл -filesystem read uploads/sessions/sess-abc/chart.svg +filesystem read session_files/sess-abc/chart.svg # Отредактировать -filesystem write uploads/sessions/sess-abc/chart.svg "...исправлено..." +filesystem write session_files/sess-abc/chart.svg "...исправлено..." ``` Пользователь увидит изменения мгновенно — URL не меняется. @@ -72,6 +79,7 @@ ## Важные правила 1. **Файл должен существовать ДО вызова** — `content_publish` не создаёт файлы, только регистрирует. -2. **Проверяйте коллизии** — если файл с таким именем уже есть, он будет перезаписан при публикации. -3. **Используйте понятные имена** — `chart.svg` лучше чем `file_1.svg`. -4. **Для редактирования используйте тот же путь** — не создавайте новые копии, правьте оригинал. +2. **Не публикуйте напрямую из `workspace/`** — сначала поместите финальный файл в директорию текущей сессии. +3. **Проверяйте коллизии** — если файл с таким именем уже есть, запись публикации будет обновлена, а файл останется тем же путём. +4. **Используйте понятные имена** — `chart.svg` лучше чем `file_1.svg`. +5. **Для редактирования используйте тот же путь** — не создавайте новые копии, правьте оригинал в директории сессии. diff --git a/navi/content_store.py b/navi/content_store.py index 9f0c2aa..34871fa 100644 --- a/navi/content_store.py +++ b/navi/content_store.py @@ -1,6 +1,6 @@ -"""Content store — tracks published files for inline viewing. +"""Content store — tracks session files published for inline viewing. -Files live in the session directory (uploads/sessions//). +Files live in the session directory (settings.SESSION_FILES_DIR//). Publishing only registers metadata in the DB; the file itself is NOT copied. The URL points to the existing /sessions/{id}/files/{filename} endpoint. """ @@ -85,7 +85,7 @@ ) -> dict: """Register a file from the session directory for inline viewing. - The file must already exist in uploads/sessions/{session_id}/. + The file must already exist in settings.SESSION_FILES_DIR/{session_id}/. Returns {"id": "...", "url": "...", "filename": "...", "content_type": "..."} """ src = ensure_session_dir(session_id) / filename diff --git a/navi/tools/content_publish.py b/navi/tools/content_publish.py index cfc258a..bb1fcb8 100644 --- a/navi/tools/content_publish.py +++ b/navi/tools/content_publish.py @@ -1,4 +1,4 @@ -"""content_publish tool — publish a file for inline viewing in the chat client. +"""content_publish tool — publish a session file for inline viewing in chat. The file must already exist in the session's file directory. Publishing only registers metadata; the file itself is NOT copied. @@ -9,7 +9,8 @@ from pathlib import Path from navi.content_store import publish -from navi.session_files import ensure_session_dir, session_dir +from navi.config import settings +from navi.session_files import session_dir from .base import Tool, ToolResult, current_session_id @@ -20,13 +21,19 @@ "Publish a file for inline viewing in the chat client. " "Use this when you generate or produce content the user will want to see interactively " "(3D models, HTML pages, SVG graphics, images, videos, PDFs, etc.).\n\n" - "IMPORTANT — the file MUST already be inside the session directory. " - "Before publishing, write or move the file into the session folder. " - "To find the session directory path, use `filesystem info ` or write directly to it. " + "There are two different file areas: workspace/ is for persistent private working files; " + "the session directory is for files visible to the user in this chat. " + "IMPORTANT — the file MUST already be inside the current session directory. " + "The default path is session_files/{session_id}/, but the root is configured by " + "SESSION_FILES_DIR. This tool does NOT copy from workspace/. " + "Before publishing, write, copy, or move the final file into the session folder. " "If a file with the same name already exists in the session directory, choose a different name " "or check the directory contents first with `filesystem list `.\n\n" "Best practices:\n" - "- Always create files in the session directory (uploads/sessions/{session_id}/)\n" + "- Use workspace/ for drafts and reusable work files\n" + "- Use the session directory for final artifacts the user should view now\n" + "- If a file already exists elsewhere and only needs a download link, use share_file instead\n" + "- If a file exists elsewhere but needs an inline viewer, copy it into the session directory first\n" "- Use descriptive filenames (e.g., 'sales_chart.svg' not 'file.svg')\n" "- After publishing, you can edit the file directly and the user will see changes immediately\n" "- For images, use PNG or JPEG; for interactive content, use HTML or SVG" @@ -73,7 +80,9 @@ success=False, output=( f"File '{filename}' not found in the session directory: {sess_dir}\n" - f"Make sure the file was written or moved there before publishing. " + f"SESSION_FILES_DIR is configured as: {settings.session_files_dir}\n" + f"Make sure the file was written, copied, or moved there before publishing. " + f"`workspace/` is separate and is not publishable directly. " f"You can check the directory contents with `filesystem list {sess_dir}`." ), error="not_found", diff --git a/persona.txt b/persona.txt index 1e12c87..6457f26 100644 --- a/persona.txt +++ b/persona.txt @@ -24,8 +24,21 @@ - Never switch back and forth repeatedly within one conversation. - When unsure which profile fits, call list_profiles. -WORKSPACE: -You have a persistent workspace directory at workspace/ (relative to the project root). Use it freely for any long-term files: scripts, notes, data, configs, research results. Do NOT write working files to the project root. +FILE LOCATIONS: +You have two different file areas. Do not confuse them. + +1. Persistent workspace: `workspace/` (relative to the project root). +Use it for long-term private working files: scripts, notes, datasets, configs, research results, intermediate code, and artifacts that should survive beyond one chat session. Do NOT write working files to the project root. + +2. Session files directory: `session_files/{session_id}/` by default; the exact root is configured by `SESSION_FILES_DIR`. +This is the per-session file area used for user uploads and files the user should view in the chat. `content_publish` can publish ONLY files that already exist directly inside the current session directory. It does not copy files from `workspace/`. + +Decision rule: +- If the file is private, reusable later, or part of your own work process — use `workspace/`. +- If the user should open, preview, download, or see live updates to the file in this chat — create or move it into the current session directory, then call `content_publish`. +- If you create something in `workspace/` and later decide to publish it, copy or rewrite the final artifact into the session directory first. +- If the user only needs a download link for an existing local file, `share_file` can copy it into the session directory. If the user needs an inline viewer card, the file must be in the session directory and then `content_publish` registers it. +- To discover the exact session directory, call `content_publish` after checking/creating the intended filename, or inspect the filesystem path from uploaded-file hints/tool output. When a publish fails, trust the error message's session directory path. EXECUTION MODES: By default you operate collaboratively — you may flag risks and confirm before irreversible actions.