Add TRAMP support for remote agent execution#205
Add TRAMP support for remote agent execution#205csheaff wants to merge 7 commits intoxenodium:mainfrom
Conversation
- Add agent-shell--tramp-command-runner to run agents on remote hosts via SSH - Add agent-shell--resolve-tramp-path to convert paths between TRAMP and remote-local format - Add agent-shell-enable-tramp-support and agent-shell-disable-tramp-support commands - Fix temporary-file-directory returning remote path when default-directory is TRAMP path (icon caching bug) Closes xenodium#122
For remote TRAMP sessions, save transcripts to ~/.agent-shell/transcripts/<host>/<path>/ instead of the remote filesystem. This avoids slow TRAMP file operations on every append.
- Add agent-shell--local-temp-directory helper for cross-platform temp paths - Fix fallback icon caching to use local temp directory - Use ~/tmp instead of /tmp for Windows compatibility - Add ERT tests for TRAMP functions - Add README.org documentation for TRAMP support
- Error explicitly on multi-hop TRAMP paths (prevents silent wrong-host execution) - Use locate-user-emacs-file for cache instead of ~/tmp - Add declare-function for tramp-file-name-hop - Add negative ERT tests for multi-hop and unsupported methods - All 23 tests pass
|
Thank you for kicking this off! I need to start breaking the ps. I'm not using TRAMP myself, so may be good to ping the feature request at #122 and ask for feedback or folks to try it out. |
Move TRAMP-specific functions to a separate file per maintainer request: - agent-shell--tramp-command-runner - agent-shell--resolve-tramp-path - agent-shell-enable-tramp-support - agent-shell-disable-tramp-support - agent-shell--tramp-transcript-dir Keep agent-shell--local-temp-directory in main file as it's needed for icon caching even without TRAMP support. Add autoloads for enable/disable commands.
|
This is awesome -- love how support for containers and now TRAMP make @csheaff re. the unstable connection issues you mention in the issue, maybe have a look at detached.el, and more importantly, the dtach tool it uses under the hood. It certainly adds another layer of indirection, but would help the session survive a reconnect. Re. the PR, I was wondering if we could make TRAMP transparent, in the sense that it prefixes the command to run and resolves paths to/from remote machines automatically? After all, you should be able to defer from the current UPDATE: just realized that not everybody would want to run the agent on the remote machine. which is likely why you went with the custom functions to manually toggle the feature -- got it 💡. The PR's issue mentions how eglot runs the server on the remote machine transparently, and if I read the code right, that happens automatically for remote working directories (at least I didn't find anything in What do you think? |
|
Hey @fritzgrabo , thanks for the feedback. In addition to removing the disable/enable functionality, I've attempted to use
I will attempt to fix next weekend if i can find some time. |
|
I tried it a little bit and here's what I found:
(defun agent-shell--tramp-command-runner (buffer)
"Return command prefix for running commands on TRAMP remote host.
BUFFER is the agent-shell buffer.
Returns nil for non-TRAMP buffers, allowing local execution."
(require 'tramp)
(with-current-buffer buffer
(let ((cwd (agent-shell-cwd)))
(when (tramp-tramp-file-p cwd)
(let* ((vec (tramp-dissect-file-name cwd))
(method (tramp-file-name-method vec))
(user (tramp-file-name-user vec))
(host (tramp-file-name-host vec))
(port (tramp-file-name-port vec)))
(unless (member method '("ssh" "scp" nil))
(error "TRAMP method '%s' not supported; only SSH is supported" method))
(when (tramp-file-name-hop vec)
(error "Multi-hop TRAMP paths not supported"))
(append
(list "ssh")
(when port (list "-p" port))
(list (if user (format "%s@%s" user host) host))
(list "--" "zsh" "-lc")))))))
|
|
environment variables can be passed in the following way: to add quotes to the env variables |
|
Hi! first of all, thank you a lot for contributing on this 🙌 I took the branch for a spin to see how it works with The steps I performed:
Edit: just cleaned up some caches and gemini seems to start! but it does exhibit same behavior as qwen for linked files. As for If anything needs some additional test, I'm happy to help! |
|
Great call on the ENV vars, much agree that it's important to be able to set those on the remote host. TRAMP seems to have solved a lot of the issues around remote process execution already (including passing ENV vars and finding executables, see |
Now that acp.el handles TRAMP via :file-handler (acp.el PR xenodium#9), agent-shell no longer needs the SSH command prefix approach. Removed: - agent-shell--tramp-command-runner (acp.el handles this now) - agent-shell-enable/disable-tramp-support commands - SSH command runner tests TRAMP now works automatically when default-directory is a TRAMP path. Only the path resolver remains to convert paths between TRAMP and local format for the agent. Also fixed trailing underscore in transcript directory names.
|
Thanks everyone, I've pushed an update that changes the approach significantly. What changed:
@junyi-hou - The
@fritzgrabo - Agreed on using TRAMP built-ins. The file-handler approach inherently uses @neonmei - I wasn't able to reproduce the |
|
Edit: I'm getting the stall again at
not sure what's going on here... |
|
Okay I think I fixed the stall issue. Seems it was a race condition - the SSH connection wasn't fully established before the first message was sent. The fix is in xenodium/acp.el#9 |
fritzgrabo
left a comment
There was a problem hiding this comment.
This looks great to me, thanks for your updates!
Left a couple thoughts and nits in time for the weekend (sorry 😬).
| (if (and (fboundp 'tramp-tramp-file-p) | ||
| (tramp-tramp-file-p default-directory)) | ||
| ;; When in a TRAMP buffer, use Emacs-standard cache directory | ||
| (locate-user-emacs-file "agent-shell/cache/") |
There was a problem hiding this comment.
Should this be just (locate-user-emacs-file "cache/")?
Further down in lines 2213 and 2240, you're file-name-concat-ing another "agent-shell", so would end up with ".../agent-shell/cache/agent-shell".
| ;; TRAMP support is in agent-shell-tramp.el | ||
| (declare-function agent-shell--tramp-transcript-dir "agent-shell-tramp") | ||
|
|
||
| (defun agent-shell--local-temp-directory () |
There was a problem hiding this comment.
Nit: you might want to consider naming this agent-shell--tramp-temp-dir and moving it into agent-shell-tramp.el. It's quite similar in spirit to agent-shell--tramp-transcript-dir imho.
| (defcustom agent-shell-path-resolver-function nil | ||
| (autoload 'agent-shell--resolve-tramp-path "agent-shell-tramp") | ||
|
|
||
| (defcustom agent-shell-path-resolver-function #'agent-shell--resolve-tramp-path |
There was a problem hiding this comment.
Just a thought: since agent-shell--resolve-tramp-path does nothing for non-tramp paths (so is save to call in all cases), you might want to hardcode calling it into agent-shell--resolve-path, probably even before funcall-ing agent-shell-path-resolver-function. That way, TRAMP support would be entirely transparent.
|
I just tested this with the acp.el updates, and it worked for me with claude code. Hope this can get merged. |
Fixes #122
I've tested this with Claude Code and Copilot CLI. Unfortunately I realized in the process that I need persistent sessions with remote, as I often times lose connection. So SSH isn't ideal. But perhaps this PR will be useful for others with stable connections.