subagents, secrets: an honest result contract, and two leaks closed
A pass over the sub-agent system, plus the two findings from the previous one.

Leaks:

- `redact_args` / `is_sensitive_key` (navi/tools/_internal/redact.py) mask
  credential-shaped keys at every log site that prints tool arguments — by key
  name, for all tools, so a future MCP tool is covered without declaring
  anything. ssh_exec passwords were sitting in the prod journal in plaintext.
- `mcp_servers.d/*.json` are tracked in git and carried the scaffolding
  machine's absolute paths, so navi-3d/navi-web silently vanished from the
  toolset off that machine. They now hold project-relative paths, resolved in
  `McpClient.open_transport` — not at load time, because create_mcp_server
  round-trips every config file through save_mcp_servers.

Sub-agent result contract:

- `run_ephemeral` returns a `SubAgentOutcome` (text + status: ok, timeout,
  max_iterations, thinking_stall, user_stop, context_overflow) instead of
  `(text, bool)`. Every exit routes through `SubAgentRunner._finish`, so token
  accounting is never dropped and a partial run always carries a progress
  report — the stop-after-stream path used to return a bare string.
- `spawn_agent` renders its header from the status. Before this, every short
  run reached the parent as "hit iteration limit", and the parent repeats that
  diagnosis to the user — a timeout was reported as an iteration limit.
- `ContextTooLargeError` no longer kills a sub-agent: the parent compresses its
  own context, a sub-agent has no session to compress into, so it stops with
  `context_overflow` and hands back what it did rather than surfacing as
  "Sub-agent failed: …" with the whole run discarded.
- The result is capped at 8000 chars (head and tail kept) so a long run cannot
  flood the parent's context, and tool arguments in the progress report go
  through `redact_args`.
- The navi-3d calling convention left the runner for the server's own tool
  schemas — a generic runner should not know one MCP server's path shapes.
- Validation moved inside spawn_agent's try: a bad argument is a clean
  ToolResult the model can read, not an exception in the parent's loop.

Tests: 1636 passed, 1 skipped. New: SubAgentOutcome paths and headers, result
truncation, context overflow, clean argument failures.
1 parent 947a717 commit b3fa54b87e2b515328db1809b8f84a5e7da0f67d
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 4 hours ago
Showing 24 changed files
View
docs/agent.md
View
docs/mechanics.md
View
manuals/create_mcp_server.md
View
manuals/spawn_agent.md
View
mcp_servers.d/navi-3d.json
View
mcp_servers.d/navi-web.json
View
navi/api/routes/peer.py
View
navi/core/agent.py
View
navi/core/subagent_runner.py
View
navi/core/tool_executor.py
View
navi/mcp/client.py
View
navi/mcp/config.py
View
navi/profiles/developer/system_prompt.txt
View
navi/tools/_internal/logging_middleware.py
View
navi/tools/_internal/redact.py 0 → 100644
View
navi/tools/create_mcp_server.py
View
navi/tools/spawn_agent.py
View
navi/tools/todo.py
View
tests/unit/core/test_agent.py
View
tests/unit/core/test_tool_executor.py
View
tests/unit/mcp/test_config_paths.py 0 → 100644
View
tests/unit/test_peer_routes.py
View
tests/unit/tools/test_redact_args.py 0 → 100644
View
tests/unit/tools/test_spawn_agent.py