Skip to content

Commit f6971b5

Browse files
authored
Feat: add open interpreter cli support, code from swithin chan (#445)
* add open interpreter cli support, code from swithin chan * add installation instruction * fix from codex * test open interpreter backend integration * add author
1 parent a27cf88 commit f6971b5

7 files changed

Lines changed: 291 additions & 4 deletions

README.org

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ An Emacs interface for AI-assisted software development. *The purpose is to prov
1515
- [[https://opencode.ai/][Opencode]]
1616
- [[https://github.com/anthropics/claude-code][Claude Code]]
1717
- [[https://docs.github.com/en/copilot/how-tos/use-copilot-agents/use-copilot-cli][GitHub Copilot CLI]]
18-
- [[https://github.com/google-gemini/gemini-cli][Gemini CLI]]
1918
- [[https://kilo.ai/][Kilo]]
2019
- [[https://grokcli.io/][Grok CLI]]
2120
- [[https://docs.cursor.com/en/cli][Cursor CLI]]
21+
- [[https://github.com/openinterpreter/openinterpreter][Open Interpreter CLI]] (Codex-compatible)
2222
- [[https://kiro.dev/cli/][Kiro CLI]]
2323
- [[https://cnb.cool/codebuddy/codebuddy-code][CodeBuddy Code CLI]]
24+
- [[https://github.com/google-gemini/gemini-cli][Gemini CLI]]
2425
- [[https://aider.chat/][Aider CLI]]
2526
- It also supports external backend packages:
2627
- [[https://eca.dev/][ECA (Editor Code Assistant)]] (`[[./ai-code-eca.el][ai-code-eca.el]]`)
@@ -85,7 +86,7 @@ Enable installation of packages from MELPA by adding an entry to package-archive
8586
(use-package ai-code
8687
;; :straight (:host github :repo "tninja/ai-code-interface.el") ;; if you want to use straight to install, no need to have MELPA setting above
8788
:config
88-
;; use codex as backend, other options are 'claude-code, 'gemini, 'github-copilot-cli, 'opencode, 'kilo, 'grok, 'cursor, 'kiro, 'codebuddy, 'aider, 'eca, 'agent-shell, 'claude-code-ide, 'claude-code-el
89+
;; use codex as backend, other options are 'claude-code, 'gemini, 'github-copilot-cli, 'open-interpreter, 'opencode, 'kilo, 'grok, 'cursor, 'kiro, 'codebuddy, 'aider, 'eca, 'agent-shell, 'claude-code-ide, 'claude-code-el
8990
(ai-code-set-backend 'codex)
9091
;; Optional: default menu stays unchanged; use a narrower 2-column layout on smaller frames
9192
;; (setq ai-code-menu-layout 'two-columns)
@@ -474,6 +475,7 @@ To transfer development work between different AI coding backends (e.g., from Co
474475
- [[https://kilo.ai/][Kilo]] (`[[./ai-code-kilo.el][ai-code-kilo.el]]`)
475476
- [[https://grokcli.io/][Grok CLI]] (`[[./ai-code-grok-cli.el][ai-code-grok-cli.el]]`)
476477
- [[https://docs.cursor.com/en/cli][Cursor CLI]] (`[[./ai-code-cursor-cli.el][ai-code-cursor-cli.el]]`)
478+
- [[https://github.com/openinterpreter/openinterpreter][Open Interpreter CLI]] (`[[./ai-code-open-interpreter-cli.el][ai-code-open-interpreter-cli.el]]`)
477479
- [[https://kiro.dev/cli/][Kiro CLI]] (`[[./ai-code-kiro-cli.el][ai-code-kiro-cli.el]]`)
478480
- [[https://cnb.cool/codebuddy/codebuddy-code][CodeBuddy Code CLI]] (`[[./ai-code-codebuddy-cli.el][ai-code-codebuddy-cli.el]]`)
479481
- [[https://aider.chat/][Aider CLI]] (`[[./ai-code-aider-cli.el][ai-code-aider-cli.el]]`)
@@ -524,6 +526,18 @@ To transfer development work between different AI coding backends (e.g., from Co
524526
`ai-code-select-backend` or bind a helper in your config.
525527
The resume command adds =--continue= automatically.
526528

529+
**** Open Interpreter CLI setup
530+
[[https://github.com/openinterpreter/openinterpreter][Open Interpreter CLI]] is treated as a Codex-compatible CLI. It can be installed with:
531+
=curl -fsSL https://www.openinterpreter.com/install | sh=
532+
Ensure the `interpreter` executable is on your PATH.
533+
Customize `ai-code-open-interpreter-cli-program` or `ai-code-open-interpreter-cli-program-switches` if needed.
534+
The backend config command opens =~/.openinterpreter/config.toml=.
535+
Then select the backend:
536+
#+begin_src emacs-lisp
537+
(ai-code-set-backend 'open-interpreter)
538+
#+end_src
539+
Resume runs =interpreter resume --last= to reopen the most recent session.
540+
527541
You can add other backends by customizing the `ai-code-backends` variable.
528542

529543
**** Add a new AI coding CLI backend

ai-code-autoloads.el

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,15 @@ When called from Lisp code, sends CMD directly without prompting.
328328
:agent-file "AGENTS.md" :upgrade
329329
"npm install -g @openai/codex@latest" :install-skills nil
330330
:cli "codex")
331+
(open-interpreter :label "Open Interpreter CLI" :require
332+
ai-code-open-interpreter-cli :start
333+
ai-code-open-interpreter-cli :switch
334+
ai-code-open-interpreter-cli-switch-to-buffer
335+
:send ai-code-open-interpreter-cli-send-command
336+
:resume ai-code-open-interpreter-cli-resume
337+
:config "~/.openinterpreter/config.toml"
338+
:agent-file "AGENTS.md" :upgrade nil
339+
:install-skills nil :cli "interpreter")
331340
(opencode :label "Opencode" :require ai-code-opencode :start
332341
ai-code-opencode :switch ai-code-opencode-switch-to-buffer
333342
:send ai-code-opencode-send-command :resume
@@ -1220,6 +1229,32 @@ prompt for the project directory.
12201229
(register-definition-prefixes "ai-code-mcp-debug-tools" '("ai-code-mcp-"))
12211230

12221231

1232+
;;; Generated autoloads from ai-code-open-interpreter-cli.el
1233+
1234+
(autoload 'ai-code-open-interpreter-cli "ai-code-open-interpreter-cli" "\
1235+
Start Open Interpreter using `ai-code-backends-infra' logic.
1236+
With prefix ARG, prompt for CLI args using
1237+
`ai-code-open-interpreter-cli-program-switches' as the default input.
1238+
1239+
(fn &optional ARG)" t)
1240+
(autoload 'ai-code-open-interpreter-cli-switch-to-buffer "ai-code-open-interpreter-cli" "\
1241+
Switch to the Open Interpreter CLI buffer.
1242+
When FORCE-PROMPT is non-nil, prompt to select a session.
1243+
1244+
(fn &optional FORCE-PROMPT)" t)
1245+
(autoload 'ai-code-open-interpreter-cli-send-command "ai-code-open-interpreter-cli" "\
1246+
Send LINE to Open Interpreter CLI.
1247+
1248+
(fn LINE)" t)
1249+
(autoload 'ai-code-open-interpreter-cli-send-escape "ai-code-open-interpreter-cli" "\
1250+
Send escape key to Open Interpreter CLI." t)
1251+
(autoload 'ai-code-open-interpreter-cli-resume "ai-code-open-interpreter-cli" "\
1252+
Resume a previous Open Interpreter CLI session.
1253+
Argument ARG is passed to the start command.
1254+
1255+
(fn &optional ARG)" t)
1256+
(register-definition-prefixes "ai-code-open-interpreter-cli" '("ai-code-open-interpreter-cli-"))
1257+
12231258

12241259
;;; End of scraped data
12251260

ai-code-backends.el

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,18 @@ so the CLI itself handles the installation details."
265265
:upgrade "npm install -g @openai/codex@latest"
266266
:install-skills nil
267267
:cli "codex")
268+
(open-interpreter
269+
:label "Open Interpreter CLI"
270+
:require ai-code-open-interpreter-cli
271+
:start ai-code-open-interpreter-cli
272+
:switch ai-code-open-interpreter-cli-switch-to-buffer
273+
:send ai-code-open-interpreter-cli-send-command
274+
:resume ai-code-open-interpreter-cli-resume
275+
:config "~/.openinterpreter/config.toml"
276+
:agent-file "AGENTS.md"
277+
:upgrade nil
278+
:install-skills nil
279+
:cli "interpreter")
268280
(opencode
269281
:label "Opencode"
270282
:require ai-code-opencode

ai-code-mcp-agent.el

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
:group 'tools
1919
:prefix "ai-code-mcp-agent-")
2020

21-
(defcustom ai-code-mcp-agent-enabled-backends '(codex github-copilot-cli claude-code)
21+
(defcustom ai-code-mcp-agent-enabled-backends '(codex open-interpreter github-copilot-cli claude-code)
2222
"Backends that should receive automatic Emacs MCP integration."
2323
:type '(repeat symbol)
2424
:group 'ai-code-mcp-agent)
@@ -108,6 +108,13 @@
108108
(format "mcp_servers.%s={ url = %s }"
109109
ai-code-mcp-agent--server-name
110110
(json-encode url)))))
111+
('open-interpreter
112+
(concat command
113+
" -c "
114+
(shell-quote-argument
115+
(format "mcp_servers.%s={ url = %s }"
116+
ai-code-mcp-agent--server-name
117+
(json-encode url)))))
111118
('github-copilot-cli
112119
(concat command
113120
" --additional-mcp-config "

ai-code-open-interpreter-cli.el

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
;;; ai-code-open-interpreter-cli.el --- Thin wrapper for Open Interpreter CLI -*- lexical-binding: t; -*-
2+
3+
;; Author: swithin chan, Kang Tu, AI coding agent
4+
;; SPDX-License-Identifier: Apache-2.0
5+
6+
;;; Commentary:
7+
;;
8+
;; Thin wrapper that reuses `ai-code-backends-infra' to run Open Interpreter CLI.
9+
;; Provides interactive commands and aliases for the AI Code suite.
10+
;;
11+
;;; Code:
12+
13+
(require 'ai-code-backends)
14+
(require 'ai-code-backends-infra)
15+
(require 'ai-code-mcp-agent)
16+
17+
(defgroup ai-code-open-interpreter-cli nil
18+
"Open Interpreter CLI integration via `ai-code-backends-infra'."
19+
:group 'tools
20+
:prefix "ai-code-open-interpreter-cli-")
21+
22+
(defcustom ai-code-open-interpreter-cli-program "interpreter"
23+
"Path to the Open Interpreter CLI executable."
24+
:type 'string
25+
:group 'ai-code-open-interpreter-cli)
26+
27+
(defcustom ai-code-open-interpreter-cli-program-switches nil
28+
"Command line switches to pass to Open Interpreter CLI on startup."
29+
:type '(repeat string)
30+
:group 'ai-code-open-interpreter-cli)
31+
32+
(defconst ai-code-open-interpreter-cli--session-prefix "open-interpreter"
33+
"Session prefix used in Open Interpreter CLI buffer names.")
34+
35+
(defvar ai-code-open-interpreter-cli--processes (make-hash-table :test 'equal)
36+
"Hash table mapping Open Interpreter session keys to processes.")
37+
38+
;;;###autoload
39+
(defun ai-code-open-interpreter-cli (&optional arg)
40+
"Start Open Interpreter using `ai-code-backends-infra' logic.
41+
With prefix ARG, prompt for CLI args using
42+
`ai-code-open-interpreter-cli-program-switches' as the default input."
43+
(interactive "P")
44+
(ai-code-backends-infra--start-cli-session
45+
(list :program ai-code-open-interpreter-cli-program
46+
:switches ai-code-open-interpreter-cli-program-switches
47+
:label "Open Interpreter"
48+
:process-table ai-code-open-interpreter-cli--processes
49+
:session-prefix ai-code-open-interpreter-cli--session-prefix
50+
:escape-function #'ai-code-open-interpreter-cli-send-escape
51+
:prepare-launch
52+
(lambda (working-dir command)
53+
(ai-code-mcp-agent-prepare-launch 'open-interpreter working-dir command)))
54+
arg))
55+
56+
;;;###autoload
57+
(defun ai-code-open-interpreter-cli-switch-to-buffer (&optional force-prompt)
58+
"Switch to the Open Interpreter CLI buffer.
59+
When FORCE-PROMPT is non-nil, prompt to select a session."
60+
(interactive "P")
61+
(ai-code-backends-infra--cli-switch-to-buffer
62+
"Open Interpreter" ai-code-open-interpreter-cli--session-prefix force-prompt))
63+
64+
;;;###autoload
65+
(defun ai-code-open-interpreter-cli-send-command (line)
66+
"Send LINE to Open Interpreter CLI."
67+
(interactive "sOpen Interpreter> ")
68+
(ai-code-backends-infra--cli-send-command
69+
"Open Interpreter" ai-code-open-interpreter-cli--session-prefix line))
70+
71+
;;;###autoload
72+
(defun ai-code-open-interpreter-cli-send-escape ()
73+
"Send escape key to Open Interpreter CLI."
74+
(interactive)
75+
(ai-code-backends-infra--terminal-send-escape))
76+
77+
;;;###autoload
78+
(defun ai-code-open-interpreter-cli-resume (&optional arg)
79+
"Resume a previous Open Interpreter CLI session.
80+
Argument ARG is passed to the start command."
81+
(interactive "P")
82+
(let ((ai-code-open-interpreter-cli-program-switches
83+
(append ai-code-open-interpreter-cli-program-switches '("resume" "--last"))))
84+
(ai-code-open-interpreter-cli arg)))
85+
86+
(provide 'ai-code-open-interpreter-cli)
87+
88+
;;; ai-code-open-interpreter-cli.el ends here

ai-code.el

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
;; - Grok CLI
3434
;; - Cursor CLI
3535
;; - Kiro CLI
36+
;; - Open Interpreter CLI (Codex-compatible)
3637
;; - CodeBuddy Code CLI
3738
;; - Aider CLI
3839
;; - agent-shell
@@ -58,7 +59,7 @@
5859
;;
5960
;; (use-package ai-code
6061
;; :config
61-
;; ;; use codex as backend, other options are 'gemini, 'github-copilot-cli, 'opencode, 'kilo, 'grok, 'claude-code-ide, 'claude-code-el, 'claude-code, 'cursor, 'kiro, 'codebuddy, 'aider, 'agent-shell, 'eca
62+
;; ;; use codex as backend, other options are 'gemini, 'github-copilot-cli, 'open-interpreter, 'opencode, 'kilo, 'grok, 'claude-code-ide, 'claude-code-el, 'claude-code, 'cursor, 'kiro, 'codebuddy, 'aider, 'agent-shell, 'eca
6263
;; (ai-code-set-backend 'codex) ;; set your preferred backend
6364
;; ;; Optional: use a narrower transient menu on smaller frames
6465
;; ;; (setq ai-code-menu-layout 'two-columns)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
;;; test_ai-code-open-interpreter-cli.el --- Tests for Open Interpreter CLI -*- lexical-binding: t; -*-
2+
3+
;; Author: Kang Tu <tninja@gmail.com>
4+
;; SPDX-License-Identifier: Apache-2.0
5+
6+
;;; Commentary:
7+
;; Tests for the ai-code-open-interpreter-cli module.
8+
9+
;;; Code:
10+
11+
(require 'ert)
12+
(require 'cl-lib)
13+
(require 'subr-x)
14+
(unless (featurep 'magit)
15+
(defun magit-toplevel (&optional _dir) nil)
16+
(defun magit-get-current-branch () nil)
17+
(defun magit-git-lines (&rest _args) nil)
18+
(provide 'magit))
19+
(require 'ai-code-open-interpreter-cli)
20+
(require 'ai-code-mcp-agent nil t)
21+
22+
(ert-deftest ai-code-test-open-interpreter-cli-backend-contract ()
23+
"Open Interpreter should expose the expected backend and MCP defaults."
24+
(should (equal ai-code-open-interpreter-cli-program "interpreter"))
25+
(let ((spec (cdr (ai-code--backend-spec 'open-interpreter))))
26+
(should spec)
27+
(should (eq (plist-get spec :require) 'ai-code-open-interpreter-cli))
28+
(should (eq (plist-get spec :start) 'ai-code-open-interpreter-cli))
29+
(should (eq (plist-get spec :switch)
30+
'ai-code-open-interpreter-cli-switch-to-buffer))
31+
(should (eq (plist-get spec :send)
32+
'ai-code-open-interpreter-cli-send-command))
33+
(should (eq (plist-get spec :resume)
34+
'ai-code-open-interpreter-cli-resume))
35+
(should (equal (plist-get spec :config)
36+
"~/.openinterpreter/config.toml"))
37+
(should (equal (plist-get spec :cli) "interpreter")))
38+
(should (memq 'open-interpreter ai-code-mcp-agent-enabled-backends)))
39+
40+
(ert-deftest ai-code-test-open-interpreter-cli-resume-appends-last ()
41+
"Resuming Open Interpreter should request the most recent session."
42+
(let ((captured-arg nil)
43+
(captured-switches nil)
44+
(ai-code-open-interpreter-cli-program-switches '("--model" "test")))
45+
(cl-letf (((symbol-function 'ai-code-open-interpreter-cli)
46+
(lambda (&optional arg)
47+
(setq captured-arg arg
48+
captured-switches
49+
ai-code-open-interpreter-cli-program-switches))))
50+
(ai-code-open-interpreter-cli-resume 'prefix-arg))
51+
(should (eq captured-arg 'prefix-arg))
52+
(should (equal captured-switches
53+
'("--model" "test" "resume" "--last")))))
54+
55+
(ert-deftest ai-code-test-open-interpreter-cli-start-injects-session-mcp-config ()
56+
"Starting Open Interpreter should inject MCP config and lifecycle hooks."
57+
(should (fboundp 'ai-code-open-interpreter-cli))
58+
(let ((captured-command nil)
59+
(captured-cleanup-fn nil)
60+
(captured-post-start-fn nil)
61+
(registered nil)
62+
(unregistered nil)
63+
(builtins-called nil)
64+
(ensure-called nil)
65+
(ai-code-mcp-agent-enabled-backends '(open-interpreter))
66+
(session-buffer
67+
(generate-new-buffer " *ai-code-open-interpreter-mcp*")))
68+
(unwind-protect
69+
(cl-letf (((symbol-function
70+
'ai-code-backends-infra--session-working-directory)
71+
(lambda () "/tmp/test-open-interpreter"))
72+
((symbol-function
73+
'ai-code-backends-infra--resolve-start-command)
74+
(lambda (&rest _args)
75+
(list :command "interpreter --model test")))
76+
((symbol-function 'ai-code-mcp-builtins-setup)
77+
(lambda () (setq builtins-called t)))
78+
((symbol-function 'ai-code-mcp-http-server-ensure)
79+
(lambda ()
80+
(setq ensure-called t)
81+
8765))
82+
((symbol-function 'ai-code-mcp-register-session)
83+
(lambda (session-id project-dir buffer)
84+
(setq registered (list session-id project-dir buffer))))
85+
((symbol-function 'ai-code-mcp-unregister-session)
86+
(lambda (session-id)
87+
(setq unregistered session-id)))
88+
((symbol-function
89+
'ai-code-backends-infra--toggle-or-create-session)
90+
(lambda (&rest args)
91+
(cl-destructuring-bind
92+
(_working-dir _buffer-name _process-table command
93+
&optional _escape-fn cleanup-fn
94+
_instance-name _prefix _force-prompt
95+
_env-vars _multiline-input-sequence
96+
post-start-fn)
97+
args
98+
(setq captured-command command
99+
captured-cleanup-fn cleanup-fn
100+
captured-post-start-fn post-start-fn))
101+
nil)))
102+
(ai-code-open-interpreter-cli)
103+
(should builtins-called)
104+
(should ensure-called)
105+
(should (string-match-p
106+
"\\`interpreter --model test " captured-command))
107+
(should (string-match-p
108+
"mcp_servers\\.emacs_tools" captured-command))
109+
(should (string-match-p
110+
"mcp/open-interpreter-" captured-command))
111+
(should (functionp captured-cleanup-fn))
112+
(should (functionp captured-post-start-fn))
113+
(funcall captured-post-start-fn session-buffer nil "default")
114+
(should (string-prefix-p "open-interpreter-" (car registered)))
115+
(should (equal "/tmp/test-open-interpreter" (nth 1 registered)))
116+
(should (eq session-buffer (nth 2 registered)))
117+
(with-current-buffer session-buffer
118+
(let ((status (ai-code-mcp-agent-buffer-status)))
119+
(should (eq 'open-interpreter (plist-get status :backend)))
120+
(should (string-match-p
121+
"^http://127\\.0\\.0\\.1:8765/mcp/open-interpreter-"
122+
(plist-get status :server-url)))))
123+
(funcall captured-cleanup-fn)
124+
(should (equal (car registered) unregistered)))
125+
(when (buffer-live-p session-buffer)
126+
(kill-buffer session-buffer)))))
127+
128+
(provide 'test_ai-code-open-interpreter-cli)
129+
130+
;;; test_ai-code-open-interpreter-cli.el ends here

0 commit comments

Comments
 (0)