Skip to content

Harden edit_file matching and complete VPS SSH tools - #18

Closed
nvdorman wants to merge 15 commits into
enowdev:mainfrom
nvdorman:fix/edit-file-vps-tools
Closed

Harden edit_file matching and complete VPS SSH tools#18
nvdorman wants to merge 15 commits into
enowdev:mainfrom
nvdorman:fix/edit-file-vps-tools

Conversation

@nvdorman

@nvdorman nvdorman commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • edit_file: recover from common read_file → edit failures (LF paste against CRLF files, pasted NUMBER| line prefixes), diagnose tab-vs-space mismatches, and teach the NUMBER|CONTENT contract in the system prompt.
  • vps_run: fix flaky/false timeouts on systemctl-class work — default timeout 120s (max 900), agent envelope above that, race-free session cancel, keyboard-interactive password auth, SSH keepalives, and actionable timeout errors with partial output.
  • vps_upload / vps_download: new SFTP tools to push/pull single files (max 256 MiB), registered in default/security toolsets, with skill/role/docs updates.

Root causes (researched, not guessed)

  1. read_file always displays LF while edit_file must match on-disk bytes; this completes CRLF recovery, strips accidental NUMBER| pastes, and surfaces tab/space diagnostics.
  2. vps_run defaulted to 60s while systemctl restart/stop often exceeds that; the agent tool envelope (5m) could cut off long timeout_seconds early; password-only auth failed on keyboard-interactive hosts; the timeout path raced on output and did not reliably close the SSH session.

Test plan

  • go test ./internal/tools/ ./internal/vps/ ./internal/agent/ -count=1
  • go build ./cmd/antares
  • Manual: project session — read_file a CRLF/tabbed source, edit_file with content after |
  • Manual: vps_run list servers; systemctl status … --no-pager; restart with timeout_seconds=180
  • Manual: vps_upload a small file, vps_download it back, confirm bytes

nvdorman added 15 commits August 2, 2026 23:30
edit_file now recovers from the common read_file→edit failures (CRLF vs LF,
pasted NUMBER| prefixes) and diagnoses tab/space mismatches; system prompt
documents the NUMBER|CONTENT contract.

vps_run no longer false-timeouts on systemctl-class work: default 120s,
agent envelope above the 900s max, race-free cancel, keyboard-interactive
auth, and clear timeout errors. Add vps_upload/vps_download over SFTP.
//go:embed all:dist fails on a bare checkout because built assets are
gitignored. Track a .gitkeep placeholder and recreate it in CI so test/vet
compile without a frontend build.
Persistent-shell scripts keep stdin open for the next tool call. Children
like `adb shell` inherit that pipe, steal the completion sentinel or block
on it, and the tool waits until timeout even though remote work finished.
Run each command in a brace group with stdin from /dev/null so the sentinel
can fire immediately; brace group preserves cd/export across calls.
Dashboard login sessions lived only in memory, so after antares restart the
browser cookie looked valid but /api/chat/attach returned 401 in a 3s loop —
live tool/stream updates never arrived. Persist sessions to disk and accept
allowlisted ?token= in dashboard auth.

The chat UI ignored EventNotice, so multi-minute context compaction showed
only "Working… · Ns". Surface notices in the streaming indicator, and stream
GET attach via fetch+credentials instead of EventSource for reliable cookies.
… turn

Compaction ran on every turn for oversized sessions because the summary
lived only in memory while loadHistory always reloaded all raw messages.
Store the summary and through_seq on session meta; subsequent turns load
head+summary+tail and only compact again when that view exceeds the threshold.
Clear the meta on edit-message so history rewrites stay consistent.
Tools existed but system prompt never steered models away from terminal
rsync/scp. Add tool-notes guidance whenever the VPS transfer tools are active,
and tighten tool descriptions plus the vps-manager skill/role.
Arrow keys previously only navigated the slash-command palette. Store recent
sends in localStorage and recall them with ↑/↓ when the caret is on the
first/last line, matching shell-style prompt history without breaking
multi-line editing.
Re-apply the missing fix: Go's append(nil, empty...) encodes tools as JSON
null, and the MCP page called .length on it. Return a non-nil empty slice and
normalize tools on the client with mcpToolsOrEmpty.
Brings the remaining coverage from the closed daemon-stdin fix so a
background setsid/adb-style child cannot pin the shell's completion sentinel.
Prevent top-level model credentials from clobbering named providers, rename
web_search on Antigravity wires, preserve Gemini thought signatures, accept
CLI-style /antigravity base URLs (append /v1beta), and pin sticky session
signals so multi-account gateways keep account affinity across agent turns.
MCP stdio held a lock for the full RPC duration, so Close/Refresh blocked when
IDA or another backend hung, leaving zombie children and freezing the web UI.
Chat also re-mapped the entire transcript every frame and grew unbounded
reasoning strings during high-effort turns.

Release the send lock while waiting for responses, kill+Wait on Close, batch
stream patches by message only, and make live reasoning display configurable
via display.show_reasoning and display.max_live_reasoning_chars.
Reasoning traces are long decompiler-style text. Rendering them through the
chat Markdown pipeline on expand created hundreds of React nodes and locked
the main thread (Chrome "Page Unresponsive"). Show reasoning as plain
pre-wrap text in a height-capped scroller, and defer the body to the next
frame so the toggle stays responsive.
…-misses

Most edit_file failures are model-side: short old_string hits many sites, or
stale/wrong identifiers (entity vs attachEntity) never exist in the file.
Surface occurrence line numbers when the match is ambiguous, and near-miss
file lines when nothing matches, so the agent re-reads instead of inventing.
Also steer the prompt to require unique context and prefer edit_file over sed.
enowdev pushed a commit that referenced this pull request Aug 9, 2026
…avity routing

Merges nvdorman's work covering edit_file CRLF/line-prefix recovery,
vps_run timeout fixes plus new vps_upload/vps_download SFTP tools,
persisted context compaction, dashboard session persistence, MCP tool
refresh, composer prompt history, and Gemini thoughtSignature handling.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
enowdev pushed a commit that referenced this pull request Aug 9, 2026
Three defects found reviewing the merge:

- config: ANTARES_BASE_URL / ANTARES_API_KEY became silently inert.
  PR #18 made a named provider's stored credentials always beat the
  top-level model.* fields, but those env vars are documented overrides
  that write into model.*, so exporting them stopped having any effect
  whenever providers.<id> already had a key (the common case). Track
  whether the value came from the environment and let an env-supplied
  credential win, while a stale value left in config.yaml still loses.
  The cross-provider leak PR #18 targeted is already handled by its own
  ClearInlineModelCredentials() calls on every provider-switch path.

- server: POST /api/mcp/refresh panicked when MCP was not configured.
  handleMCPRefresh boxed a possibly-nil *mcp.Manager into the
  mcpRefresher interface, where the 'refresher == nil' guard is false,
  so Refresh dereferenced a nil receiver. Check the concrete pointer
  first, matching handleMCPStatus.

- vps: vps_download/vps_upload could destroy the file they replace.
  Both opened the destination with O_TRUNC before the first byte
  arrived, so a mid-transfer timeout left a truncated stub and no
  original — worst on upload, whose whole purpose is replacing a live
  service config. Stream to a temp path and rename on success.
  Download also created the local file with the *remote* file's
  permission bits, so a 0777 remote file produced a world-writable
  local one; use a fixed 0600 instead.

Also adds tool_call argument validation and retryable provider-side
truncated-JSON messages (prior local work).

Pre-existing issues found while reviewing, left alone as out of scope:
Manager.Connect replaces m.clients without closing the old clients or
updating the registry (leaks one stdio subprocess per server on every
MCP add/delete), and Status unconditionally overwrites the connect
error with the tool-listing error.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@enowdev

enowdev commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Landed on main. The edit_file/VPS-tools work from this PR was integrated locally (commit dff21d7 + review fixes 5d8406a) and pushed to main; GitHub could not auto-detect it as merged because the integrated commits have different SHAs than this branch. The remaining un-integrated commits from this branch (MCP-deadlock + reasoning-freeze fixes) were delivered via PR #19. Closing as fully merged.

@enowdev enowdev closed this Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants