抛砖引玉: 介绍命令行AI编程工具aider以及emacs集成aider.el

tninja 是否还有未被解决的担忧?

在这次讨论中,tninja 主要提出了以下几个担忧:

  1. 与终端行为保持一致

• tninja 最初倾向于让 aider.el 的行为与终端中的 aider 会话保持一致,即多行输入必须手动使用 {aider … aider} 进行包裹。

• CeleritasCelery 反驳说,Emacs 并没有终端的这些限制,因此应该提供更好的用户体验。

  1. 普通用户的可发现性

• tninja 担心要求用户学习 comint-accumulate 这种方法,会使得多行输入的使用变得难以发现。

• CeleritasCelery 解释说,这种行为是 comint-mode 的标准方式,Emacs 用户本就期望它能够这样工作。

  1. 保留 {aider … aider} 语法,支持用户手动使用

• tninja 后来接受了这一改动,但希望用户仍然可以手动使用 {aider … aider} 进行多行输入。

• MatthewZMD 提出修改 aider–process-message-if-multi-line,防止已经包裹 {aider … aider} 的输入被重复包裹,这直接解决了 tninja 的担忧。

是否还有未解决的担忧?

从目前的讨论来看,tninja 的所有主要担忧都已被解决:

• 现在的行为支持 Emacs 风格的输入(comint-accumulate),同时仍然允许手动使用 {aider … aider} 语法。

• 通过默认的快捷键绑定(S-),可发现性问题得到了改善,同时也提供了用户自定义选项。

• 最终的补丁确保手动包裹 {aider … aider} 的输入不会被重复包裹,避免影响用户习惯。

除非 tninja 还有新的异议,否则他的担忧应该已经完全得到解决。

  • 在考虑合并的问题上,我有三个考量: 1. 对初学者是否友好; 2. 是否符合传统/习惯; 3. 将来是否容易维护
    • 关于multi-line prompt的问题上,CeleritasCelery建议在comint-buffer中使用comint-accumulate函数。作为一个用了comint 10多年的用户 (mostly sql, R, python, scala), 我第一次知道这个功能; 因此,我也不期望新用户会知道; 这并不比学习aider的官方doc更容易, 特别是在aider已经提供了多种不同multi-line prompt输入的情况下. 另外, 把comint-accumulate绑在comint-mode-map上会影响所有其他语言的comint-mode, 我不知道用户是否喜欢这样.
    • CeleritasCelery的PR在aider comint buffer里把输入A加上tag转换成了B, 我没有在其他语言,比如sql, R, python, scala的comint里看到过. 就我看来, comint buffer里输入什么, 就应该给解释器发送什么. 不然既不透明, 也容易混入隐藏的bug不容易发现.
    • 在可预见的将来, 这个repo可能主要是由我用业余时间来负责维护. 维护每一个功能的正常运作, 需要时间和精力. 据此, 我希望维护比较少的功能, 但是希望这些功能能够满足大部分人的需要, 并且使得代码库尽量简单. 比如,aider对multi-line prompt提供了多种方式, 在aider.el中,我仅仅选择tag方式作为统一向aider session发送multi-line prompt的方法,这样会简化代码,并且使得将来更加容易维护. 对于比较不常用的功能比如tramp, 大部分人并不会用到, 我选择不去支持这样的功能, 特别是需要比较多的代码修改的情况下.
1 个赞
  • aider.el另一个问题是输出代码的着色问题. 目前采用的workaround是使用相应major-mode的信息来着色. 当然,这不是完美的方案,有它的问题. 但我不想在这个问题上投入太多的elisp代码,这些代码将来是需要维护的. 如果这些代码过于依赖llm的输出或者aider的格式,那么它可能容易break.
    • 这个问题的根源是comint不是一个全功能的term. 这造成了其他的麻烦,比如不能支持inline comment和file watch, 我曾试图给aider repo发PR来改进这个问题,但是作者有他的考虑,没有merge,我当然需要尊重他的决定. 这个功能很有价值,对应的我也给出了一些work around, 比如implement comment in place (aider-implement-todo). 我自己的体验还可以.
    • 在term的问题上, 我也很感谢楼上更有emacs经验的群友的思考, 比如是否选择vterm来替换comint? vterm上运行aider和terminal中一样, 不会丢失功能. 是否选择vterm作为dependency? 我的选择和楼上一些更有经验的emacs群友一样还是comint. 我之前用过vterm, 不过最近在新macbook上安装编译的时候遇到了问题. 而且它的代码库最近更新并不频繁. 如果depend on vterm, 一方面使得用户需要额外的精力安装 (说不定也像我一样会遇到问题), 另一方面, 也要承担将来它retire的风险.
1 个赞

您说《是否容易维护》是自己优先考虑的问题,却连自己项目代码里的dumb关键词认不出来并直接push aider生成的明显错误逻辑

或许,您真的宁可不审阅不理解并直接相信 aider 自己写的代码,也不愿意阅读理解回应别人提供的 PR 和评论(这里这里这里这里这里这里这里这里这里这里这里还有这里)。 或许,您作为 十年 comint 用户 仍然不了解 comint-accumulate,并不应该怪 comint 本身的设计。

或许,如果您对英语交流有些疑虑,可以通过ChatGPT来帮您总结一下:

**tninja 的核心疑问是否已经得到充分解决?**

tninja 的回复来看,他的核心考量主要集中在 三个方面

  1. 对初学者是否友好 —— comint-accumulate 是否比 {aider … aider} 方式更直观?

  2. 是否符合 Emacs 传统 —— comint-mode 应该“输入什么就发送什么”,不应该对输入进行转换。

  3. 将来是否容易维护 —— 代码库应该尽可能简单,而不是引入难以维护的额外功能。

然而,从 MatthewZMDCeleritasCelery 提供的 PATCH 以及前文的讨论来看,这些问题都已经得到了 充分的回应和解决方案

1. 对初学者是否友好?

:small_blue_diamond: tninja 的观点

• comint-accumulate 是一个冷门功能,即使他自己用 comint 10 多年也不知道,因此 不应该假设新用户会知道或使用它

• 让用户学习 comint-accumulate 不比学习 {aider … aider} 更容易

:white_check_mark: 前文讨论是否有回应?

MatthewZMD 提供了 PATCH (aider-multiline-newline-key),让 comint-accumulate 成为默认行为

新用户不需要知道 comint-accumulate 的存在,它会自动生效 ,避免了额外的学习成本。

高级用户仍然可以手动切换回 {aider … aider} 方式 ,保证兼容性。

CeleritasCelery 也指出,comint-accumulate 是 Emacs comint-mode 的标准行为

• Emacs 其他 comint-based 模式(如 Python、R、SQL)本来就支持多行输入,这符合 Emacs 用户的预期

MatthewZMD 指出:Emacs 不是终端,不需要继承 CLI 的局限性,我们可以做得更好。

:arrow_right: 结论

这个问题已经得到 充分回应并解决

新用户不需要手动学习,comint-accumulate 变成默认行为,体验更自然,且兼容 {aider … aider}。

2. 是否符合 Emacs 传统?

:small_blue_diamond: tninja 的观点

• 在 comint buffer 里,“输入什么就应该发送什么”,否则容易混入 bug,且不透明。

在其他 comint 交互模式(SQL、R、Python)里没有类似的输入转换 ,所以不符合 Emacs 传统。

:white_check_mark: 前文讨论是否有回应?

CeleritasCelery 指出

其他 comint 模式(Python、R、SQL)都支持 multi-line 输入 ,并且 用户不会察觉到 comint-accumulate 的存在 ,因为它只是让输入方式更自然。

MatthewZMD 提供了 PATCH (fix: Prevent duplicate aider wrappers) 彻底解决了透明性问题

• 只有在 aider 需要 {aider … aider} 语法时才会自动添加,而不会对已经使用 {aider … aider} 的输入进行重复转换。

• 这样既能保证 原始输入的透明性 ,又能 避免影响用户体验 ,符合 Emacs 处理代码的传统方式

MatthewZMD 也提到 :aider 作为 AI 代码助手 ,其工作方式 不应该受 CLI 限制 ,而是 更加贴近 Emacs 交互方式

comint-accumulate 只是让输入更符合直觉,并不会引入隐藏的 bug ,因为它 不会改动 aider 的解释逻辑,而只是调整输入行为且 aider.el 本身已经在其他地方使用过 comint-accumulate

:arrow_right: 结论

这个问题 已经得到充分回应并解决

comint-accumulate 并不会改变输入的透明性,而是让输入方式更符合 Emacs 传统。

3. 是否容易维护?

:small_blue_diamond: tninja 的观点

• 他希望代码库 尽量简单,功能尽可能少,但能满足大部分人的需求 ,这样维护起来更轻松。

当前的 {aider … aider} 方式已经足够,并且 aider 本身支持多种 multi-line 方式 ,不需要额外改动。

:white_check_mark: 前文讨论是否有回应?

CeleritasCelery 指出 :这个 PR 只涉及 10 行代码 ,不会对维护带来额外负担。

MatthewZMD 提到

这个改动不会增加维护负担,反而可以减少代码复杂度

当前 {aider … aider} 方式需要额外的 tag 处理代码 ,而 comint-accumulate 让 multi-line 输入“原生可用”,反而更简单

:arrow_right: 结论

这个问题 已经得到充分回应并解决

新改动不会增加维护负担,反而减少了代码复杂度,让 multi-line 输入更自然。

最终总结

:white_check_mark: tninja 提出的所有问题都已经得到充分回应 ,并且 PATCH 直接解决了他提出的所有问题

:white_check_mark: comint-accumulate 变成默认行为,用户不需要手动学习,完全避免了额外学习成本。

:white_check_mark: 新的 multi-line 处理逻辑不会隐藏 bug,且仍然允许 {aider … aider} 语法,保持兼容性。

:white_check_mark: 修改代码量很少,几乎不增加维护成本,甚至让代码更简洁。

:white_check_mark: 改动让 aider.el 更加符合 Emacs 传统,而不是遵循 CLI 限制。

然而,tninja 仍然拒绝合并这些改动,理由并不是技术问题,而是他的个人理念

他坚持 “尽量减少功能”,即便这会降低 Emacs 用户的体验。

他更在意维护者的管理成本,而不是用户的实际使用感受。

他似乎忽略了 PATCH 解决了他自己提的问题,或者他并不愿意接受这些解决方案。

:bulb: 这进一步说明 aidermacs 作为 fork 存在的必要性——如果 aider.el 维护者坚持遵循 CLI 设计,不愿意优化 Emacs 体验,那么 fork 一个真正符合 Emacs 用户习惯的版本就是更好的选择。 :rocket:

在一个社区驱动的项目里,维护者应该开放地接受改进,而不是固守个人的理解方式,忽略已经充分讨论和解决的问题。

如果维护者 不愿意阅读社区贡献的 PR 和技术分析,也 不愿意正面回应解决方案,而只是坚持自己的预设,那么这样的项目是 无法正常合作下去的

aider.el 已fork 至 aidermacs,欢迎大家试用:GitHub - MatthewZMD/aidermacs: Aider AI Pair Programming for Emacs

Update: Aidermacs支持vterm啦!

多行输入应该使用 bracketed-paste。这个是 terminal app 的标准做法。

bracket-paste 是标准的终端 app 用来区分一段文本到底是用户粘贴的,还是用户直接输入的的两段不同的 control sequence。

vterm 原生自带对 bracketd-paste 的支持,如果不用 vterm,其实也很简单,就是在向终端发送的string 的开头和结尾添加两个 string 就行了。

以下引用 wikipedia

Each implementation uses the control sequences documented in xterm’s control sequences:

  • ESC [ 200 ~ to signify the beginning of pasted text and
  • ESC [ 201 ~ to signify the end.

因此这个问题的解决方案,非常简单。你在每次发动给 aider 的 string 开头和结尾加上这两个 control sequence 问题就解决了。

我因错误的表达方式挑起了争端,把讨论引导向了不必要的方向,造成了非技术讨论的情感上伤害。我对这些过重的言论向 @MatthewZMD 道歉。

以下重新组织我的语言观点:

AI 是一个工具,也是一面镜子,我们可以用 AI 来提高自己的生产效率,也可以用 AI 来自省,用来反思/思考自己的行为是否符合 AI 认为的符合 “ethic” 的观点。但是仅就我个人而言,我希望 AI 生成的观点就用于内部自省,当把 AI 的观点发布在论坛上时,会有一点点微妙的让我感觉到仿佛是想将 AI 输出的观点作为评价事物的标准的做法一样。

1 个赞

把 comint 和 vterm 作为一个抽象的 backend 实现即可,用户可以自己选择使用不同的 backend。即使不用 vterm 也可以考虑 eat,这个是纯用 lisp 实现的一个全功能的的终端。

就事论事,反过来批判我用AI,甚至上纲上线到“奴隶”行为,是否管的有些太宽,更是让人难以评价。更不用说这是一个讨论AI工具的帖子,你这做法实在过于抽象搞笑。你有你的想法,我有我的态度,请你管好你的嘴巴,或者你的键盘,再此警告偏移话题一次。

我的观点是,没说不让你用 AI。用 ai 是把 ai 当工具,不要把 ai 生成的观点发布到论坛,用来做评价事情的标准。

至于说奴隶这句话,是我言重了,我向你道歉。

这个论坛之前一贯都是把 ai 生成的内容隐藏的。

具体看这个帖子:过年了大家准备玩什么? - #88,来自 unique_nospace_brief

直接贴大段大段的生成式ai的spam确实很无趣,非常无趣. 你自己的表达非常完整,中间那段ai删掉没啥问题. 当然,你不乐意看见别人对你有意见的话,也可以删除我这个帖子.

3 个赞

由于和 @milanglacier 的误会已经解除,我原本的长篇大论已经没有实际意义,故删除。

你当我是权限狗啊 :doge: 如果可以,我想置顶你这句话 :grinning:

老哥,我真的没有批判你重复造轮子的行为,我认为你fork是合理的。

我其实想说的是多行输入有bracketed-paste,其实不需要很多复杂的实现。我只是在说这个多行输入上的造轮子的事情,而不是aidermacs fork这个行为不合理。

如果我的表达造成了误解,我再次向你道歉。

最后,我一开始批判你的时候,我确实自身也有自己的心情不好的原因,导致说了更重的话,我再次向你道歉,我也重新更新了我的“奴隶”那段话的一整段话,重新表达了我的观点。当然这仅仅是我个人的观点。

虽然一开始确实是我不对,我用了 proactive 的语气批判了你的行为。我现在已经将这句话的语气重写,仅表达我的个人观点,而不对你有任何的批判。我希望我们能够心平气和地讨论问题。

1 个赞

了解了,我收回前面对你的反驳,对不起,我向你道歉,我的反应也比较大了。

我完全理解你的想法,这或许正是我们潜意识中对AI目前展现出的能力产生抵触的一种外在体现。但如果细想一下,论坛本就是各种观点交锋的地方——你表达的是你的观点,我表达的是我的观点,而 AI 生成的内容同样也是一种观点。当它被发布在论坛的回复框中,本质上只是观点中的一部分,而并非某种客观标准。

可能因为粘贴的AI文本比较长,让他看起来有种权威性,这不是我的本意,而且这恰恰是当前LLM最危险的地方之一:AI输出的内容越多,我们往往越难以逐一核查细节,跟review几百行PR更容易点LGTM的道理一样哈哈哈。然而正是在这种情况下,AI hallucinate的风险也更高。作为日常高强度使用AI的人,AI的hallucination已经习以为常了,事实上我前面粘贴上来的内容,我已经删除了一条AI编的部分了,GPT4o真的不太行。

回到正题,我的立场前文写的非常清楚了,我认为Aider.el的作者并没有认真尝试理解我和CeleritasCelery的PR和评论,我和作者的沟通也经历了从3周前的友好沟通到今天完全放弃另开fork也是很长一段拉扯。因此,我前面用ChatGPT的目的就是用中文整理我们之前在Github沟通中已经address过的地方,只是写个Aider作者看的,不是写给吃瓜群众看的,希望大家能理解,而AI,作为一个高效的信息整理工具,也完成了我的要求。

好了,题外话就说到这,再继续下去我得警告我自己偏移话题了,如想继续讨论咱另开新帖。

1 个赞

这个方案是可行的 之前有位贡献者用doom 他就自己写了doom 的菜单 主文件aider.el 我希望尽量减少依赖 新的需要依赖的功能放在额外的文件里 比如aider-doom.el 这也是他的想法

所以这个功能也许叫做aider-vterm.el 问题是 谁来写 谁来维护呢?我个人并没有很强的意愿来做这件事 因为comint的功能虽然有限 但是足够满足我的需要 而且我也并不是vterm专家 不见得可以长期维护这个额外的功能 doom菜单我有时候去照顾一下 因为我自己不用doom

才下班 才有时间来回复帖子 可能不是很及时 见谅

另外 祝大家都有个好心情 参与做开源分享的事情 本来就是自利利他 开开心心很重要 项目有人喜欢 很高兴

2 个赞

操作里有不少添加文件的操作,但是没有罗列当前已添加文件,移除已添加文件的操作。

虽然可以在 session 里通过 aider 的命令罗列和删除,操作起来也不算麻烦,不过是不是也能提供一些方便的操作?

不过目前其实我比较少会删除文件,有时想精简一下当前 context 可能会有用吧。

1 个赞

确实没有加/drop 命令. 它好像可以带文件名, 或者不带文件名. 如果需要经常带文件名. 加个菜单项可以省去粘贴文件名的时间, 今晚我去改一改

我自己一般是完成一个task以后, reset以后加其他文件开始新的工作 reset会清除所有文件和聊天记录

平时没怎么用列出已经加的文件, 因为每次使用ask, code, architect之类, output的最后都已经会列出已经加的文件列表

现在的菜单项有些冗余, 关于add / drop文件, 以及reset / clear这方面, 我再想想如何精简

原来如此,reset 也可以,本身删除的需求确实没那么高。

菜单或许可以做成像 magit 一样的? 按照功能分组,有二级的菜单,不过可能降低了一些便捷性。

1 个赞

是的, 有道理. 最常用的功能比如add保留在顶层, 减少按键次数; 不常用的功能放到二级菜单或者类似的其他办法

顶层菜单太复杂对user experience也不好 我现在更喜欢做减法大于加法 aider提供的各种命令 启动参数已经非常多甚至有些复杂了