
1. HermesAgent 在 Windows 上到底卡在哪HermesAgent 是一个能自己调用终端、读写文件、跑测试的 AI Agent 框架适合在本地做二次开发、自动化脚本编排和长链路任务执行。它本身跨平台但 Windows 原生环境尤其是配合 Git Bash 当默认 shell时终端工具这条链路特别容易出问题。我最近在 Windows 11 上把它接到 TaoToken 的统一 Key/API 通道上跑就连续踩了两个 Bug一个是select.select()在 Git Bash 管道上直接抛OSError导致所有终端命令返回空输出另一个是 Git Bash 的/d/code/...路径格式被写回self.cwd让后续subprocess.Popen(cwd...)报NotADirectoryError。这两个问题的共同点是Agent 启动、模型对话、API 调用全都正常只有真正让 Agent 去执行 shell 命令时才暴露。如果你只跑一句hermes -z 11?根本发现不了。所以这篇按“先复现、再定位、后修复、最后验证”的顺序写配置部分给出可直接复制的config.toml、settings.json骨架以及 CC Switch / Cline 接入 TaoToken 的写法。适合已经在 Windows 上跑 HermesAgent、但终端工具时好时坏的同学。2. 前置TaoToken 统一 Key 与 API 通道TaoToken 在这里的角色是统一模型入口你只需要一个 Key就能在 HermesAgent、CC Switch、Cline 等多个客户端之间复用同一套 API 通道不用每个工具单独配一遍。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 这个不加 UTM。接入前先拿到 Key打开 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 新建一个 Key 并复制。注意 Key 只在创建时完整显示一次丢了就重建。模型名、可用模型列表可以在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 查别凭记忆填。HermesAgent 侧的配置我放在项目根目录的config.toml骨架如下把api_key换成你自己的# config.toml [llm] provider openai-compatible base_url https://taotoken.net/api api_key sk-你的TaoTokenKey model claude-sonnet-4-5 timeout 120 [terminal] shell C:\\Program Files\\Git\\usr\\bin\\bash.EXE cwd D:\\code\\HermesAgent timeout 30这里shell指向 Git Bash 的bash.EXEcwd用 Windows 反斜杠格式。很多人第一步就把cwd写成/d/code/HermesAgent那 Bug 2 会提前找上门。3. 可复制配置settings.json 与 CC Switch / Cline 接入HermesAgent 有些版本会读settings.json覆盖config.toml所以两边保持一致最稳。settings.json骨架{ llm: { base_url: https://taotoken.net/api, api_key: sk-你的TaoTokenKey, model: claude-sonnet-4-5 }, terminal: { shell: C:\\Program Files\\Git\\usr\\bin\\bash.EXE, cwd: D:\\code\\HermesAgent, timeout: 30 } }如果你同时用 CC Switch 管理多套配置在它的 provider 里新增一条Base URL 填https://taotoken.net/apiAPI Key 填同一个模型按需选。Cline 在 VS Code 设置里选 OpenAI CompatibleBase URL 同样填https://taotoken.net/apiKey 复用。这样 HermesAgent、CC Switch、Cline 三处走的是同一条通道排查问题时能快速判断是 Agent 侧还是通道侧。配置改完先别急着跑 Agent用一条最小请求验证通道通不通curl https://taotoken.net/api/v1/models \ -H Authorization: Bearer sk-你的TaoTokenKey返回模型列表就说明 Key 和通道没问题接下来所有异常都可以锁定在 HermesAgent 的终端工具实现上。4. 复现与定位两个 Bug 的逐步验证4.1 Bug 1select.select() 在 Windows 管道上抛 OSError先确认 Git Bash 本身没问题C:\Program Files\Git\usr\bin\bash.EXE -c pwd # 输出 /d/code/HermesAgent再用 Python 直接调 subprocess也能拿到输出import subprocess bash_path rC:\Program Files\Git\usr\bin\bash.EXE proc subprocess.Popen( [bash_path, -c, echo hello], stdoutsubprocess.PIPE, stderrsubprocess.STDOUT, textTrue, ) print(repr(proc.stdout.read())) # hello\n但走 HermesAgent 的终端工具就丢输出from tools.environments.local import LocalEnvironment env LocalEnvironment(cwdrD:\code\HermesAgent, timeout10) result env.execute(echo hello) print(repr(result.get(output, ))) # print(repr(result.get(returncode))) # 0返回码 0输出为空。问题在_wait_for_process里的_drain()它用select.select()轮询管道 fd。单独验证import subprocess, select proc subprocess.Popen( [bash_path, -c, echo hello], stdoutsubprocess.PIPE, stderrsubprocess.STDOUT, textTrue, ) fd proc.stdout.fileno() try: ready, _, _ select.select([fd], [], [], 1.0) print(select works! ready:, ready) except Exception as e: print(select FAILED:, type(e).__name__, e)输出是select FAILED: OSError [WinError 10093] 应用程序没有调用 WSAStartup或者 WSAStartup 失败。根因清楚了Windows 的select()来自 WinSock只支持 socket不支持管道文件描述符。_drain()捕获OSError后直接break输出永远读不到。4.2 Bug 1 修复Windows 上改用阻塞读取在tools/environments/base.py的_drain()里加平台分支Windows 下改用阻塞os.read()靠父线程超时 kill 进程兜底import platform def _drain(): fd proc.stdout.fileno() idle_after_exit 0 try: while True: try: ready, _, _ select.select([fd], [], [], 0.1) except (ValueError, OSError): if platform.system() Windows: try: chunk os.read(fd, 4096) except (ValueError, OSError): break if not chunk: break output_chunks.append(decoder.decode(chunk)) continue break if ready: chunk os.read(fd, 4096) if not chunk: break output_chunks.append(decoder.decode(chunk)) idle_after_exit 0 elif proc.poll() is not None: idle_after_exit 1 if idle_after_exit 3: break finally: pass4.3 Bug 2Git Bash 路径写回导致 NotADirectoryError修完 Bug 1 再跑报NotADirectoryError: [WinError 267] 目录名称无效。打印env.cwd发现它从D:\code\HermesAgent变成了/d/code/HermesAgent。原因是init_session执行pwd -P后_update_cwd把 Git Bash 风格路径直接写回self.cwd而subprocess.Popen(cwd...)不认这种格式。4.4 Bug 2 修复路径格式转换在tools/environments/local.py加一个静态方法并在_update_cwd里调用import re staticmethod def _git_bash_to_win_path(path: str) - str: m re.match(r^/([a-zA-Z])(/.*)?$, path) if m: drive m.group(1).upper() rest (m.group(2) or ).replace(/, \\) return f{drive}:{rest} return path def _update_cwd(self, result: dict): try: cwd_path open(self._cwd_file).read().strip() if cwd_path: if _IS_WINDOWS: cwd_path self._git_bash_to_win_path(cwd_path) self.cwd cwd_path except (OSError, FileNotFoundError): pass self._extract_cwd_from_output(result) if _IS_WINDOWS: self.cwd self._git_bash_to_win_path(self.cwd)注意最后三行_extract_cwd_from_output也会从命令输出的 CWD marker 里解析路径所以它之后还要再转一次。5. 验证请求与成功结果两个 Bug 修完后用同一段代码验证env LocalEnvironment(cwdrD:\code\HermesAgent, timeout10) print(env.execute(pwd)[output].strip()) # /d/code/HermesAgent print(env.execute(echo hello world)[output].strip()) # hello world print(env.execute(ls pyproject.toml)[output].strip()) # pyproject.toml print(env.execute(python --version)[output].strip()) # Python 3.13.13 env.execute(cd hermes_workspace pwd) print(env.cwd) # D:\code\HermesAgent\hermes_workspace命令输出正常CWD 跟踪也正确转回 Windows 格式。再用真实 Agent 跑一次python -m hermes_cli.main -z 当前工作空间的绝对路径是什么用pwd命令确认Agent 能拿到/d/code/HermesAgent并正常回复说明终端工具链路通了。如果你还想单独验证模型通道可以打开 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 发一条消息确认 Key 和模型名都对得上。6. 本篇常见错排查报错OSError [WinError 10093]就是select.select()用在管道 fd 上。确认_drain()里加了platform.system() Windows分支且import platform在文件顶部。报错NotADirectoryError [WinError 267]self.cwd被写成了/d/...格式。检查_update_cwd是否在_extract_cwd_from_output之后又做了一次转换漏掉这一步就会在cd类命令后复发。终端命令返回空但 returncode 为 0优先怀疑_drain()提前break。可以在except分支里临时加print确认是否命中 Windows 分支。改了代码不生效HermesAgent 可能装了包版本python -m hermes_cli.main走的是源码但hermes.exe走的是安装版。统一用源码方式启动改完即生效。Key 报 401先确认base_url是https://taotoken.net/api不要多加/v1后缀不同客户端要求不同以文档为准。Key 失效就去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 重建。长期跑编码任务频繁断连如果你打算让 HermesAgent 长时间做代码生成、Agent 编排建议用 Coding Plan 而不是按次调用配置入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 接入方式与上面一致只是计费模型不同。最后提醒一句Windows 上跑 HermesAgent别用hermes.exe验证终端工具一定用python -m hermes_cli.main从源码启动这样断点、日志、异常栈都能直接看到两个 Bug 都是这么定位出来的。