feat: 终端诊断 Phase 2 + 供应商与模型管理 — PTY 代理架构升级与自动诊断闭环#545
feat: 终端诊断 Phase 2 + 供应商与模型管理 — PTY 代理架构升级与自动诊断闭环#545pionxe merged 27 commits into1024XEngineer:mainfrom
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
- 提取并重构数据过滤 (`filter.go`)、前置脱敏 (`sanitizer.go`) 与日志截断 (`truncator.go`) 逻辑,强化隐私保护并解耦核心链路。 - 规范化进程间通信 (IPC),引入基于 JSON-Lines 的协议抽象 (`ipc_protocol.go`) 及 Unix Socket 路径管理 (`socket_paths.go`)。 - 引入动态 OSC 133 Shell 事件探测与状态管理机制 (`shell_events.go`, `shell_init.go`)。 - 缩减并重构 `proxy_unix.go` 的超大文件实现,大幅提升代码可维护性。 - 补充完整的并发安全与边界条件单元测试。
- 完善 IDM (Intelligent Diagnostic Mechanism) 上下文管理与数据流转链路。 - 修复并加固技能依赖 (skill-dependency) 逻辑,确保并发诊断请求安全处理。 - 新增 `agent_test.go` 以强化并发数据处理与核心工具逻辑的单元测试覆盖率。
- 确立清晰的 "动词-名词 (Verb-Noun)" 命令层级,整合零散的临时诊断指令。 - 规范化网关守护进程 (Gateway/Daemon) 管理及 Provider 配置初始化流程。 - 遵循非侵入式环境初始化原则,提升工具在生产环境中的可维护性与用户体验。 - 更新相关 CLI 命令测试,保障重构后的输入与配置解析符合预期。
- 新增 'neocode provider add' 命令,支持通过命令行直接注册自定义模型供应商。 - 引入自动化 YAML 配置生成机制,简化底层配置细节,保障配置原子性更新。 - 新增 'neocode use' 命令,支持全局快速切换活跃供应商。 - 完善相关命令的单元测试,覆盖 Mock 注入与原子更新链路。
- 新增 'neocode model ls' 命令,支持查看当前供应商的所有可用模型及激活状态。 - 新增 'neocode model set' 命令,允许手动切换并持久化模型配置。 - 扩展 'neocode use' 命令,支持 '--model' 参数实现供应商与模型的一键切换。 - 采用轻量化配置操作机制,避免 CLI 模式下沉重的运行时依赖注入。
|
@xgopilot 分析PR的实际代码中还有没有PR描述以外的修改 |
This comment was marked as resolved.
This comment was marked as resolved.
|
P0 / High:Auto off 会被下一次 PromptReady 自动打开 这个已经有 review 指出来了:PromptReady 会无条件把 autoState.Enabled 设回 true,所以用户执行: neocode diag auto off 之后,只要下一次 prompt ready,Auto 又被打开。review 里也明确说需要把“OSC ready 状态”和“用户开关状态”拆开。 这是 blocker,因为它破坏了用户显式关闭 Auto 的承诺,也违反 #525 里“用户可通过 neocode diag auto off 实时关闭自动触发”的回滚方案 |
|
P1:zsh 写了 init 脚本,但 shell proxy 没自动注入 PR 描述和 #525 都说要兼容 bash/zsh,但 buildShellCommand 只对 bash 走 --rcfile 注入。代码里 prepareBashInitRC(shellPath) 只检查 isBashShell,zsh 不走等价 bootstrap。 review 也指出了:neocode shell --shell /bin/zsh 时不会自动注入 zsh integration,OSC 133 永远不会出现,1.5s 后 fallback manual,所以 Auto 实际 bash-only。 这个不是安全问题,但属于“宣传与实际不一致”。你有两个选择: 方案 A:补 zsh 自动注入。 方案 B:承认第一版 auto-injection 只支持 bash |
|
/review |
| } | ||
|
|
||
| if apiKeyEnv != "" { | ||
| if envErr := deleteUserEnvVarForCreate(apiKeyEnv); envErr != nil { |
There was a problem hiding this comment.
If user-env cleanup fails here, the provider YAML has already been deleted but the method returns before manager.Load() / EnsureSelection(). That leaves the current selection pointing at a provider that no longer exists, so later model/use commands can fail on inconsistent state. This path needs rollback or it needs to continue repairing selection even when env cleanup fails.
| return diagIPCResponse{}, err | ||
| } | ||
|
|
||
| legacyPath, fallbackErr := ResolveLegacyTmpDiagSocketPath() |
There was a problem hiding this comment.
This fallback is not scoped to the requested shell/session; it just picks the newest legacy socket under $TMPDIR. If the primary ~/.neocode/run/... socket is gone, diag or diag auto off can be delivered to a stale or unrelated shell, and its buffered output may be sent into diagnose. Please make this opt-in or validate that the fallback target matches the intended session before dialing it.
| fmt.Fprintf(out, "当前模型: %s\n", displayCurrentModel(currentModel)) | ||
| fmt.Fprintln(out, "可用模型:") | ||
|
|
||
| models, err := svc.ListModelsSnapshot(cmd.Context()) |
There was a problem hiding this comment.
model ls is described as 'prefer snapshot, then do sync discovery if needed', but this only falls back when the snapshot list is empty. Any snapshot read error returns immediately even if live discovery would succeed, so a corrupt/missing snapshot becomes a hard failure instead of a recoverable path.
概述
本 PR 基于 #512、#525,继续推进终端诊断链路,并把 Provider / Model 选择能力补齐到可直接落盘、可切换、可回退的状态管理闭环。
相对
origin/main...HEAD,当前实际变更为 44 files / +7480 / -1010。变更不只包含“终端诊断 Phase 2 + Provider / Model 管理”,还额外带入了:provider rm删除能力diag auto status、diag diagnose、socket 自动发现等诊断命令面扩展Close #525
一、这个 PR 解决了什么问题
1.1 Phase 1 终端诊断仍然不够“可持续使用”
Phase 1 只能手动触发诊断,存在几个明显问题:
Ctrl+C/SIGTSTP/SIGCONT/SIGWINCH等信号在 PTY 转发链路上不完整,容易出现中断吞噬、分页器排版异常或僵尸子进程1.2 Provider / Model 选择还停留在“配置存在”,缺少完整运维闭环
在本 PR 之前,Provider / Model 相关能力还不完整:
1.3 需要把“诊断工具”从 demo 变成真实闭环
手动 / 自动诊断的最终目标,不是打印占位文案,而是把终端错误日志真正接入 NeoCode 的工具体系,通过 gateway -> system tool -> sub-agent 完成根因分析,并在失败时具备可预期的降级路径。
二、核心设计思路
2.1 终端诊断仍然沿主链路收敛,不在 TUI / runtime 侧散落逻辑
本 PR 延续仓库既有边界:
用户输入(TUI/CLI) -> Gateway -> Runtime / Tool Manager -> diagnose tool -> 结果回传其中:
internal/tools/diagnose负责真正的诊断执行与降级策略这样做的原因是把“终端交互细节”和“模型可调用能力”继续隔离,避免把诊断逻辑塞回 runtime 或 UI。
2.2 用 Shell Integration + OSC 133 建立“可观测的命令生命周期”
Auto 诊断能否可靠,关键不在关键词匹配,而在于能否知道:
因此本 PR 引入 shell integration 注入脚本,并统一发射 / 解析
OSC 133;A/C/D事件,把命令生命周期结构化成prompt_ready / command_start / command_done。这样 Auto 模式不再依赖脆弱的文本猜测,而是建立在 shell 事件流上。2.3 用“探针 + 动态降级 / 升级”兼容真实终端环境
不同 shell、tmux、SSH、终端模拟器对 OSC 的实现并不稳定,所以这里没有把 Auto 模式当成硬依赖,而是采用:
prompt_ready时自动降级为 Manual目标是优先保证 shell 可用性,而不是为了 Auto 模式牺牲兼容性。
2.4 Provider / Model 选择统一收敛到 SelectionService
Provider、Model、Use 三组命令本质上都在操作同一份“当前选择状态”。本 PR 新增 CLI 侧的 resolver / 缓存层,把三组命令统一接到同一个
SelectionService,避免重复 bootstrap,也让后续命令行为更一致。同时,
SelectProvider、SetCurrentModel、SelectProviderWithModel都纳入 provider create lock 保护,并对跨进程 provider create/remove 引入更稳健的锁语义,减少状态写入竞争。三、终端诊断 Phase 2:PTY 代理与自动诊断闭环
3.1 PTY 代理稳定性升级
为保证代理 shell 可长期使用,本 PR 在
internal/ptyproxy/proxy_unix.go中补上了多层稳定性防线:defer term.Restore()兜底恢复宿主终端状态SIGHUP、SIGINT、SIGTSTP、SIGCONTSIGWINCH窗口尺寸,保证less/vim等全屏程序显示正常此外,代理在启动阶段会预建并复用 gateway RPC 长连接,避免每次诊断再重复做一次完整连接与鉴权。
3.2 Shell Integration 注入与 OSC 133 事件流
新增:
internal/ptyproxy/shell_init.gointernal/ptyproxy/shell_events.go能力包括:
neocode shell --init输出 shell integration 脚本OSC 133序列3.3 Auto 模式触发过滤
为了避免“命令非零退出就一律诊断”的误报,本 PR新增过滤引擎:
130、137不触发 Autogrep、find、test、false等常见命令豁免这样做的目的是把 Auto 诊断聚焦在“值得分析的失败”上,而不是把正常 shell 行为误判成异常。
3.4 日志清洗、脱敏与 UTF-8 安全截断
新增:
internal/ptyproxy/sanitizer.gointernal/ptyproxy/truncator.go诊断 RPC 发起前会统一执行:
\r覆盖输出折叠这样既提高模型可读性,也降低把真实密钥送入模型上下文的风险。
3.5 IPC 协议升级为 JSON-Lines
新增
internal/ptyproxy/ipc_protocol.go,将原先简单的行文本协议升级为 JSON-Lines:{"cmd":"diagnose","payload":"..."} {"cmd":"auto","enabled":true} {"ok":true,"message":"diagnosis completed","auto_enabled":true}升级原因:
3.6 Socket 路径规范化与自动发现
新增
internal/ptyproxy/socket_paths.go,并把 socket 路径统一收敛到~/.neocode/run/。同时补充:EADDRINUSE风险$TMPDIR路径并给出 warningdiag命令侧支持--socket > NEOCODE_DIAG_SOCKET > 最近一次运行目录 socket的自动发现回退链路这解决了用户每次都要手动记 socket 路径的问题,也提高了命令行诊断入口的可达性。
3.7 真实 diagnose 工具闭环
internal/tools/diagnose/tool.go不再是占位实现,而是接到真实 system tool 闭环:diagnose系统工具SpawnSubAgent做根因分析目标不是“始终成功调用 AI”,而是在失败时仍然返回保守建议,避免 panic 或空白结果。
四、Provider / Model 管理闭环
4.1
provider add/provider rm/provider ls本 PR 实际补齐了完整的 provider 管理命令面,而不只是新增
provider add:neocode provider add <name> --driver --url --api-key-env [--discovery-endpoint]neocode provider lsneocode provider rm <name>其中
provider add会:provider rm会:EnsureSelection4.2
use命令与 provider+model 原子切换新增
neocode use <provider> [--model <model-id>]。如果只切 provider,会自动修正到该 provider 下的可用模型;如果同时指定
--model,则通过SelectProviderWithModel在同一临界区内完成切换,避免先切 provider 再切 model 的两次写入间隙被并发插入。4.3
model ls/model set新增:
neocode model lsneocode model set <model-id>其中
model ls优先读取 snapshot,必要时再触发同步发现;model set会校验模型归属关系,避免把不属于当前 provider 的模型写进配置。4.4 SelectionService 与状态一致性改造
除了命令本身,本 PR 还调整了 state 层语义:
selectionServiceResolver,按 workdir 缓存 selection serviceSelectProvider/SetCurrentModel纳入 provider create lockSelectProviderWithModel30s调整到60s这些调整的目标是减少并发切换、配置热更新和远程发现失败时的状态漂移问题。
五、CLI 结构调整
诊断与选择能力的命令面现在更清晰:
同时,诊断命令继续保持 skip preload / skip update check,保证错误现场下的响应尽可能直接。
六、测试与验证
本 PR 为以下模块补充了大量测试:
internal/ptyproxyinternal/tools/diagnoseinternal/cliinternal/config/state覆盖重点包括:
实测方面,PR 也验证了:
gateway.executeSystemTool(diagnose)七、风险与注意事项
关联 Issue / 文档