fix(mcp): SSE 消息端点立即返回 202,后台异步处理工具调用
poll_now 等耗时工具(发出 HTTP 请求到 Gitea)阻塞了 handle_sse_message, 导致客户端 POST 超时。改为 tokio::spawn 在后台处理 + SSE 推回结果, HTTP 握手立即完成,符合 MCP SSE 传输规范。 另:新增 docs/ai-context/git-workflow.md(分支策略 + Conventional Commits), .gitignore 排除炼境实例数据(.claude/liangjing.json / dev_manager.db)。
This commit is contained in:
parent
6d10c71d15
commit
d4cb236ace
4
.gitignore
vendored
4
.gitignore
vendored
@ -25,5 +25,9 @@ src-tauri/target/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# 炼境实例数据(项目 ID 和端口,每台机器不同,不入库)
|
||||
.claude/liangjing.json
|
||||
src-tauri/dev_manager.db
|
||||
|
||||
# 防止签名密钥被误提交(Windows ~ 路径展开问题)
|
||||
~/
|
||||
|
||||
82
docs/ai-context/git-workflow.md
Normal file
82
docs/ai-context/git-workflow.md
Normal file
@ -0,0 +1,82 @@
|
||||
# Git 工作流 — AI Agent 操作指南
|
||||
|
||||
> 把此文件粘贴给任何 AI Agent,让它了解本项目的 git 工作方式。由炼境接入包分发。
|
||||
> `ONBOARDING_MANAGED` 标记块由炼境版本化管理(重跑接入包可原位升级),块外可自由补充项目特有约定。
|
||||
|
||||
<!-- ONBOARDING_MANAGED_START version="1.1.0" -->
|
||||
|
||||
## 分支策略
|
||||
|
||||
```
|
||||
dev ← 日常开发在这里 commit/push
|
||||
↓
|
||||
main ← 稳定分支,通过 PR 合入(合入时触发 CI code review)
|
||||
```
|
||||
|
||||
- 小改动可直接 push `dev`
|
||||
- 功能完整后开 PR(dev → main)
|
||||
- 不要直接 push `main`,除非紧急热修复
|
||||
|
||||
## Commit 规范(lefthook 强制)
|
||||
|
||||
格式:`<type>(<scope>): <描述>`
|
||||
|
||||
| type | 用途 |
|
||||
|------|------|
|
||||
| `feat` | 新功能 |
|
||||
| `fix` | Bug 修复 |
|
||||
| `chore` | 配置、依赖、脚本 |
|
||||
| `docs` | 文档 |
|
||||
| `refactor` | 重构(不改功能) |
|
||||
| `ci` | CI 配置 |
|
||||
| `perf` | 性能优化 |
|
||||
| `style` | 代码格式 |
|
||||
| `test` | 测试 |
|
||||
|
||||
`scope` 用「模块/子模块」二级结构(如 `auth/login`、`api/user`、`db/order`),对应项目功能模块。
|
||||
|
||||
```bash
|
||||
git commit -m "feat(auth/login): 新增手机号登录"
|
||||
git commit -m "fix(api/user): 修正分页 off-by-one"
|
||||
```
|
||||
|
||||
> 炼境会解析这些 commit 的 type/scope 作为飞轮数据:`fix` 计入返工率、`scope` 归到模块。
|
||||
> **commit 写得越规范,飞轮数据越准。**
|
||||
|
||||
## Rules-Applied trailer(规则命中回传)
|
||||
|
||||
若本次任务中触发过 CONVENTIONS 自动推荐规则(R01-R11,见 `.blueprint/CONVENTIONS.md` 规则列表),
|
||||
在 commit message 末尾追加一行 trailer(与正文空行分隔):
|
||||
|
||||
```
|
||||
feat(auth/login): 新增手机号登录
|
||||
|
||||
Rules-Applied: R01,R05
|
||||
```
|
||||
|
||||
- 只记录**真实触发**(主动检查或执行)的规则,未触发则整行省略
|
||||
- 炼境自动解析此 trailer 做「规则命中 × 返工」交叉统计,是 CONVENTIONS 置信度进化的数据来源
|
||||
- 凭空罗列会污染数据——宁缺毋滥
|
||||
|
||||
## 一个 commit = 一件独立的事
|
||||
|
||||
不要 `git add -A` 一次提交所有。按功能分批:
|
||||
|
||||
```bash
|
||||
git add <相关文件>
|
||||
git commit -m "feat(模块): 一件事"
|
||||
```
|
||||
|
||||
## PR 大小控制
|
||||
|
||||
PR 别攒太大(建议每 3~5 个 commit 或几百行内就开一次),否则 CI code review 易超时失效。
|
||||
「所有检测通过」≠ 代码被审查过——大 PR 即使 CI 全绿,review 可能已静默失效。
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git log --oneline -10
|
||||
git reset --soft HEAD~1 # 撤销最后一次 commit(保留改动)
|
||||
```
|
||||
<!-- ONBOARDING_MANAGED_END -->
|
||||
@ -323,7 +323,7 @@ async fn handle_sse_connect(
|
||||
}
|
||||
|
||||
/// POST /mcp/group/:group_id/messages?session_id=xxx
|
||||
/// 客户端通过此 URL 发送 JSON-RPC 请求,响应经 SSE channel 推回。
|
||||
/// 客户端通过此 URL 发送 JSON-RPC 请求,立即返回 202,响应经 SSE channel 异步推回。
|
||||
async fn handle_sse_message(
|
||||
State(sessions): State<Sessions>,
|
||||
Path(group_id): Path<String>,
|
||||
@ -333,27 +333,30 @@ async fn handle_sse_message(
|
||||
if req.id.is_none() {
|
||||
return StatusCode::ACCEPTED.into_response();
|
||||
}
|
||||
let id = req.id.clone();
|
||||
|
||||
let response_json = match process_rpc(&group_id, &req).await {
|
||||
Ok(result) => json!({ "jsonrpc": "2.0", "id": id, "result": result }),
|
||||
Err(msg) => json!({
|
||||
"jsonrpc": "2.0", "id": id,
|
||||
"error": { "code": -32601, "message": msg }
|
||||
}),
|
||||
};
|
||||
|
||||
let mut sessions_guard = sessions.lock().await;
|
||||
if let Some(tx) = sessions_guard.get(&query.session_id) {
|
||||
if tx
|
||||
.send(("message".to_string(), response_json.to_string()))
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
// 连接已关闭,惰性清理
|
||||
sessions_guard.remove(&query.session_id);
|
||||
// 立即返回 202,在后台 task 里处理(避免长时间工具调用阻塞 HTTP 连接)
|
||||
let sessions_clone = sessions.clone();
|
||||
let session_id = query.session_id.clone();
|
||||
tokio::spawn(async move {
|
||||
let id = req.id.clone();
|
||||
let response_json = match process_rpc(&group_id, &req).await {
|
||||
Ok(result) => json!({ "jsonrpc": "2.0", "id": id, "result": result }),
|
||||
Err(msg) => json!({
|
||||
"jsonrpc": "2.0", "id": id,
|
||||
"error": { "code": -32601, "message": msg }
|
||||
}),
|
||||
};
|
||||
let mut guard = sessions_clone.lock().await;
|
||||
if let Some(tx) = guard.get(&session_id) {
|
||||
if tx
|
||||
.send(("message".to_string(), response_json.to_string()))
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
guard.remove(&session_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
StatusCode::ACCEPTED.into_response()
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user