# walissh **Repository Path**: WangRuoXv/walissh ## Basic Information - **Project Name**: walissh - **Description**: 基于小傅哥的walissh和ai-agent脚手架开发的SshAgent,目前支持:记忆持久化,长命令执行,subAgent动态调度,subAgent任务规划等。目前是一个最小可用Mvp - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-14 - **Last Updated**: 2026-11-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringAI, GoogleADK, jsch ## README # Ai Agent Scaffold > AIAgent开发脚手架 ## Question: 1. 指出项目里不符合纯 DDD 的地方,怎么改? 考察点:批判性思维。答:① types 引入 spring-boot-starter-web(基础层太重,可去掉或用 starter 最小化);② api 的 chatStream 签名暴露 ResponseBodyEmitter(MVC 类型渗入接口层,可改为返回自定义流对象由 trigger 适配);③ 会话用内存 Map 而非仓储(可下放到 infrastructure 用 Redis 实现,走 domain 定义的端口)。 2. 会话是干什么用的? 3. 创建会话需要远程请求baseUrl吗? 4. 用户的聊天记录是怎么管理的? 5. 如果一个用户在聊天的过程中,换了一个模型,这个会话会怎样 6. 如果一个用户在聊天的过程中更换了模型,下一个模型还会知道用户和上一个模型的聊天记录吗? --- ## 已知隐患(Known Issues) ### P1:SSH 工具的 ThreadLocal 可能绑错终端会话 ⚠️(未修复) 一句话:**AI 可能在另一台服务器上执行命令,而且不会报错。** **相关代码** - `SshExecuteAdkTool.currentTerminalSession` —— 静态 `InheritableThreadLocal` - `ChatService.handleMessageStream(agentId, userId, sessionId, message, terminalSessionId)` —— 在请求线程上 set 值 - `AgentServiceController.chatStream` —— 实际生效的流式入口;`clearCurrentTerminalSession()` 只出现在该文件被注释掉的旧实现里,**没有任何生效代码调用它** **调用链** ``` HTTP 请求线程: AgentServiceController.chatStream └─> ChatService.handleMessageStream(5参) ← 在这里 setCurrentTerminalSession(terminalSessionId) └─> runner.runAsync(...) ← ADK 内部用线程池异步执行 └─> SshExecuteAdkTool.executeCommand() ← 工具调用线程在这里 .get() 读值 ``` **问题拆解** 1. `InheritableThreadLocal` 只在「子线程被创建的那一刻」把父线程的值复制过去;之后父线程再怎么改,子线程都看不到。 2. ADK 的工具调用跑在**线程池**里,线程是复用的,不是每个请求新建一个: - 请求 A 带 `terminalSessionId=甲`,线程 T1 执行工具 → 读到「甲」✅ - 请求 B 没带 `terminalSessionId`(前端终端未连接时传 null)→ 不会 set → 若复用到 T1,读到的是 **A 残留的「甲」** ❌ 3. `clearCurrentTerminalSession()` 存在但没有调用方,陈旧值永不清除。 **触发条件**:请求不带 terminalSessionId,且线程池复用到带陈旧值的线程。单人自用几乎不触发;多用户、多连接、或重启后并发时概率上升。 **修复方向** - 治本:去掉 ThreadLocal,改显式传参——例如在 `ChatService` 维护 `sessionId → terminalSessionId` 映射,或把 terminalSessionId 写进 ADK 的 session state,工具执行时按当前 sessionId 取值。 - 治标:`setCurrentTerminalSession` 之前先 `clear`,并在流结束的 `finally` 里 `clear`,把污染窗口从「进程整个生命周期」缩小到「单次请求」。