- agent-session-lock.js 新增 acquireLockWithWait:锁被占用时按 pollMs 轮询排队等待
AGENT_CHAT_QUEUE_WAIT_MS 预算(默认 60s),check-and-set 之间无 await,天然原子;
等到锁释放就正常执行,等满预算仍抢不到才 429,不再"撞上就立刻拒绝"。
内部自唤醒(TaskCallback/TaskDispatch 等 selfChat 调用)是 fire-and-forget,之前
429 等于这次唤醒直接消失,只能靠别处巡检兜底;排队等待让大多数几秒到几十秒的
短暂碰撞能自然衔接上。
- AgentChat.vue 的 handleSend() 之前拿到 fetch 响应后不检查 r.ok 就直接当 SSE 流读,
非 200 响应体是普通 JSON,逐行解析全部匹配不上 event/data 前缀,被静默当空流吞掉——
用户发的消息挂在界面上,没有任何回复也没有报错。现在先判 r.ok,非 200 时读 JSON
错误体,429 显示"Agent 正忙,请稍后重试",其他状态显示带状态码的错误提示。
- agent-chat-interrupt.test.js 相应更新:原来断言"并发第二个请求立刻 429"的用例
改为断言"预算内排队等待、等到就正常执行、两次调用不重叠",另加一条"预算耗尽仍
抢不到锁时返回 429"的回归。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CwGcvMfUcgCcweN5vjhTkn