diff --git a/docs/mechanics.md b/docs/mechanics.md index 273aa33..09e8c6a 100644 --- a/docs/mechanics.md +++ b/docs/mechanics.md @@ -36,6 +36,8 @@ | **Anti-stall detection** | Tracks two signals: (1) consecutive iterations with no todo status change, (2) identical tool call signatures. When either hits threshold, injects a hard warning system message. | `profile.anti_stall_enabled`, `profile.anti_stall_threshold` | `agent.py` | ✅ | | **Adaptive replan on failure** | Detects newly-failed todo steps after each tool batch and queues a re-planning system message for the next iteration. | `profile.adaptive_replan_enabled` | `agent.py` | ✅ | | **Goal anchoring** | Injects `[Goal anchor]` system message with original request + todo state every N iterations. | `profile.goal_anchoring_enabled`, `profile.goal_anchoring_interval` | `agent.py` | ✅ | +| **Bounded autonomy — scope boundary** | Injects a standing `[Scope boundary]` system message keeping the agent within the user's literally requested scope — no expanding to sibling/parent dirs/projects, no executing discovered TODO/roadmap/milestone docs. | `profile.scope_boundary_enabled` | `agent.py`, `context_builder.py` | ✅ | +| **Observe-vs-act planning skip** | When Phase 1 classifies the request as `MODE: observe` (look/read/explain — no changes), skips Phase 2/3 — no execution plan, no auto-todo, no "execute step by step" prompt. `act` requests plan normally. | `profile.observe_skips_plan_enabled` | `planning.py` | ✅ | | **Todo status snapshot** | Captures frozenset of `(task_text, status)` before each iteration so anti-stall can detect progress. | None | `agent.py` | ❌ | | **Todo failed-steps tracking** | Captures frozenset of `(index, text)` for failed steps, used by adaptive replan. | None | `agent.py` | ❌ | | **Todo progress message injection** | Injects compact system reminder with current todo state and discipline notes at start of every iteration. | None | `agent.py` | ❌ | @@ -66,7 +68,8 @@ | Mechanic | Description | Config / Flags | Files | Docs | |---|---|---|---|---| | **3-phase planning engine** | Orchestrates Phase 1 (analysis), Phase 2 (review), Phase 3 (execution plan) as async generator. | `profile.planning_phase1_enabled`, `profile.planning_phase2_enabled`, `profile.planning_phase3_enabled`, `profile.planning_mandatory`, `profile.planning_enabled` | `planning.py` | ✅ | -| **Phase 1 — Task analysis** | LLM call reformulates task, identifies subtasks, unknowns, resources. Can output `DIRECT` to skip planning. | `profile.think_enabled`, `profile.planning_phase1_enabled` | `planning.py` | ✅ | +| **Phase 1 — Task analysis** | LLM call reformulates task, identifies subtasks, unknowns, resources. Classifies `MODE: observe | act` (intent). Can output `DIRECT` to skip planning. | `profile.think_enabled`, `profile.planning_phase1_enabled` | `planning.py` | ✅ | +| **Observe short-circuit** | When `observe_skips_plan_enabled=True` and Phase 1 outputs `MODE: observe`, returns after Phase 1 — Phase 2/3, the auto-todo, and the "execute step by step" prompt are all skipped. The agent gathers info with tools and answers directly. `MODE: act` and `force_plan` requests still plan normally. | `profile.observe_skips_plan_enabled` | `planning.py` | ✅ | | **Phase 2 — Structured review** | One critique pass when `planning_phase2_enabled=True` and Phase 1 outputs `REFLECT: yes`. Returns Critic/Pragmatist/Detailer/Plan Adjustments. | `profile.planning_phase2_enabled` | `planning.py` | ✅ | | **Phase 3 — Execution plan** | Produces milestones + numbered steps with executor assignments (`TOOL:`, `AGENT:`, `SELF`). Enforces comma-test splitting. | `profile.planning_phase3_enabled` | `planning.py` | ✅ | | **Auto-populate todo from plan** | Parses Phase 3 steps and calls `todo.set_tasks()` to initialize session todo list. | None | `planning.py` | ✅ | @@ -83,8 +86,10 @@ | **Cross-profile awareness** | Appends `## Available profiles` block listing all other profiles with descriptions. | None | `context_builder.py` | ⚠️ | | **Memory summary message** | Injects `## What I remember about the user` if memory store has a summary. | None | `context_builder.py` | ✅ | | **Memory facts message** | Searches memory facts from user message. Skips messages ≤20 chars or <2 words. Limits: 1 fact for <50 chars, 2 for ≤150, 3 otherwise. Deduplicates. | None | `context_builder.py` | ❌ | +| **Memory facts scope filter** | When `scope_boundary_enabled=True`, drops memory facts whose value is an absolute path outside the session `cwd` (e.g. a stale `project_root` pointing at another project). Facts inside the cwd and non-path facts are kept. No facts are deleted — only injection is filtered. | `profile.scope_boundary_enabled` | `context_builder.py` | ✅ | | **Context provider injection** | Injects global providers unconditionally, profile-named providers only if listed in `profile.context_providers`. | `profile.context_providers` | `context_builder.py` | ⚠️ | | **Goal anchor builder** | Constructs `[Goal anchor]` system message with original request + todo lines. | None | `context_builder.py` | ❌ | +| **Scope-boundary message** | Injects a standing `[Scope boundary]` system message keeping the agent within the user's literally requested scope — do not expand to sibling/parent dirs/projects, do not execute discovered TODO/roadmap/milestone docs unless explicitly asked. | `profile.scope_boundary_enabled` | `context_builder.py` | ✅ | | **Security policy message** | Injects `[Security policy]` based on `current_user_role`: admin = full access; user = sandbox + terminal allowlist. | `TERMINAL_ALLOWED_COMMANDS` | `context_builder.py` | ❌ | | **User context message** | Builds `[User context]` from `current_user_info` (display_name, email, locale, etc.). | None | `context_builder.py` | ❌ | | **MCP context message** | Combines MCP server instructions from handshake with overlay instructions from `mcp_servers.d/*.json`. | `profile.tools.agent.mcp` | `context_builder.py` | ❌ | diff --git a/docs/navi_code.md b/docs/navi_code.md index 873509d..986e1ff 100644 --- a/docs/navi_code.md +++ b/docs/navi_code.md @@ -69,6 +69,7 @@ - MCP: отключены (`"mcp": {}`) для чистого терминального опыта. - Отключённые инструменты: `share_file`, `content_publish`, `ssh_exec`, `gmail`, `image_view`, `mcp__navi-web`. - `planning_phase2_enabled: false` — уменьшает latency. +- Ограниченная автономия (bounded autonomy): `scope_boundary_enabled` и `observe_skips_plan_enabled` оба `true`. Агент действует строго в рамках запрошенной области — не лезет в соседние/родительские директории и проекты, не выполняет обнаруженные TODO/roadmap/milestone документы без явного запроса. Запросы `MODE: observe` (посмотреть/прочитать/объяснить) пропускают фазы планирования 2/3 и авто-todo — агент просто собирает информацию инструментами и отвечает. Чтобы воспроизвести прежнее поведение «свободного полёта», отключите оба флага. См. [`docs/profiles.md`](profiles.md#bounded-autonomy) и [`docs/mechanics.md`](mechanics.md). ## Безопасность diff --git a/docs/navi_code_cli.md b/docs/navi_code_cli.md index 697bdf6..15336f6 100644 --- a/docs/navi_code_cli.md +++ b/docs/navi_code_cli.md @@ -45,7 +45,11 @@ | `--no-events` | Скрывать события `tool_started` / `tool_call`. | | `--mouse` / `--no-mouse` | Включить/выключить мышь в TUI на один запуск (перекрывает `tui.json`). | | `--theme NAME` | Запустить TUI с указанной темой. | +| `--raw` | Запустить plain CLI вместо TUI (используется по умолчанию, когда передан позиционный запрос). | | `--version` | Версия клиента. | +| `-h`, `--help` | Показать справку по использованию. | + +Любой позиционный аргумент воспринимается как запрос и запускает plain CLI в one-shot режиме (например `navi-code "объясни этот файл"`). Неизвестные флаги передаются как часть запроса. ## Команды в интерактивном режиме @@ -74,15 +78,32 @@ Список сессий обновляется автоматически при запуске и при выполнении `/new`, `/sessions`, `/switch`. +### Поле ввода + +Поле ввода многострочное — перенос текста по ширине автоматический, высота поля растёт вместе с содержимым (в пределах ограничения). `Enter` отправляет сообщение целиком (вместе с переносами). Принудительный перенос строки не поддерживается: терминалы не различают `Ctrl+Enter` от обычного `Enter`, поэтому сделан только автоматический перенос. + +### Карточки в чате + +Помимо обычных сообщений и блоков рассуждений, чат рендерит карточки для специальных событий: + +- **Планирование.** Пока работает планировщик, показывается rolling-индикатор `⚙ Planning · <фаза>` (обновляется на месте, а не плодит строки). Когда план готов — карточка `Plan` с содержимым плана. +- **Субагент (`spawn_agent`).** Отдельная карточка `↘ subagent · <профиль>` при запуске и `↙ subagent · <профиль> ✓/✗` с результатом. Имя задачи и брифинг показаны в теле карточки. +- **Вложенные события субагента.** Рассуждения, планирование, карточки инструментов и плана субагента показываются с отступом и приглушённым стилем, чтобы визуально отделить их от основного хода сессии (TUI использует плоскую модель, вложенность передаётся через отступ). + ## Состояние Клиент сохраняет `session_id` в `~/.navi_code/state.json`, чтобы восстановить диалог при следующем запуске. Удалите файл или используйте `/clear`, чтобы начать с чистого листа. ## Рендеринг событий +События WebSocket рендерятся по-разному в TUI и в plain CLI (`--raw`): + - `stream_delta` — печатается inline, как в обычном чате. -- `tool_started` / `tool_call` — показываются имена инструментов и краткий результат (если включено `--show-events`). -- `thinking_delta` / `thinking_end` — показываются только с `--show-thinking`. +- `tool_started` / `tool_call` — карточки инструментов: имя, аргументы, краткий результат (если включено `--show-events` / `--no-events` не задан). +- `thinking_delta` / `thinking_end` — блоки рассуждений, показываются только с `--show-thinking`. +- `planning_status` — индикатор текущей фазы планирования (в TUI — rolling-строка `⚙ Planning · <фаза>`; в plain CLI — `[planning] <фаза>`). +- `plan_ready` — готовый план (в TUI — карточка `Plan`; в plain CLI — блок `[plan]…[/plan]`). +- `turn_thinking` — полный блок рассуждений субагента целиком (не стримится по частям); в TUI это `subagent thinking` с отступом, в plain CLI — `[thinking]…(subagent)`. - `error` — красным цветом. ## Пример сессии @@ -112,7 +133,8 @@ - `state.py` — сохранение `session_id` в `~/.navi_code/state.json`. - `config.py` — настройки из переменных окружения `NAVI_CODE_*`. - `tui/tui_app.py` — Textual-приложение. -- `tui/widgets/` — виджеты (`ChatPanel`, `StatusPanel`, `SessionsPanel`). +- `tui/widgets/` — виджеты (`ChatPanel`, `StatusPanel`, `SessionsPanel`, `InputBox`). +- `tui/renderers/` — рендереры карточек по типам событий (сообщения, рассуждения, инструменты, планирование, субагент); диспетчеризация через `RendererRegistry`. - `tui/commands/` — slash-команды (`/new`, `/sessions`, `/switch`, `/export`, `/themes`, `/mouse`). - `tui/settings.py` — persisted TUI config (`~/.navi_code/tui.json`). diff --git a/docs/profiles.md b/docs/profiles.md index bdb3479..6780ff5 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -78,6 +78,17 @@ | `step_validation_enabled` | bool | `false` | Reserved flag — todo validation is unconditional in the current implementation. | | `adaptive_replan_enabled` | bool | `false` | When a todo step is marked failed, trigger a re-planning pass. Depends on `step_validation_enabled`. | +### Bounded autonomy + +Two independent flags that keep an autonomous agent inside the user's literally requested scope. Both default `false` (legacy "free flight" behavior — explore broadly, finish discovered work). Enabled on `navi_code`. + +| Key | Type | Default | Description | +|---|---|---|---| +| `scope_boundary_enabled` | bool | `false` | Inject a standing `[Scope boundary]` system message telling the agent to act strictly within the requested scope — do not expand to sibling/parent directories or projects, and do not execute discovered TODO/roadmap/milestone/backlog docs unless explicitly asked. Also gates the memory-facts scope filter (see below). | +| `observe_skips_plan_enabled` | bool | `false` | When Phase 1 analysis classifies the request as `MODE: observe` (look/read/explain/inspect/list/find — no changes requested), skip Phase 2/3 — no multi-step execution plan, no auto-todo, no "execute step by step" prompt. The agent gathers info with tools and answers directly. `act` requests still plan normally. | + +The memory-facts scope filter: when `scope_boundary_enabled` is on, `_memory_facts_msg` drops memory facts whose value is an absolute path outside the session `cwd` (e.g. a stale `project_root` pointing at another project). Facts inside the session cwd and non-path facts are kept. No facts are deleted — only injection is filtered. See [`docs/mechanics.md`](mechanics.md). + ### Planning The planning pipeline runs before the main tool-calling loop and produces a structured execution plan. It has three phases: @@ -127,7 +138,8 @@ - **Native tools:** `todo`, `scratchpad`, `reflect`, `switch_profile`, `list_profiles`, `filesystem`, `code_exec`, `terminal`, `memory`, `list_tools`, `tool_manual`, `spawn_agent`, `schedule_recall`, `manage_recall`. - **MCP tools:** disabled (`"mcp": {}`) for the terminal experience. - **Excluded:** `share_file`, `content_publish`, `ssh_exec`, `gmail`, `image_view`, `mcp__navi-web`. -- **Planning:** Phase 1 and Phase 3 enabled, Phase 2 disabled to reduce latency. +- **Planning:** Phase 1 and Phase 3 enabled, Phase 2 disabled to reduce latency. Phase 1 classifies the request as `MODE: observe | act`. +- **Bounded autonomy:** `scope_boundary_enabled` and `observe_skips_plan_enabled` are both `true` — the agent stays within the requested scope (does not climb to sibling projects or execute discovered milestone/TODO docs) and `observe` requests (look/read/explain) skip the execution plan and just answer. Flip both off to reproduce the legacy "free flight" behavior. - **Safety:** the system prompt asks Navi to confirm destructive operations (`rm`, overwrites) before executing them. Use it with `NAVI_DEFAULT_PROFILE_ID=navi_code` so `POST /sessions` without a `profile_id` creates a `navi_code` session automatically. See [`docs/navi_code.md`](navi_code.md) for the full local-terminal setup. @@ -190,6 +202,8 @@ "anti_stall_threshold": 8, "step_validation_enabled": false, "adaptive_replan_enabled": false, + "scope_boundary_enabled": false, + "observe_skips_plan_enabled": false, "subagent_planning_enabled": false } ```