fix(agents): 修复 HIL 工具审批 interrupt 被误当 ask_user_question 处理#791
fix(agents): 修复 HIL 工具审批 interrupt 被误当 ask_user_question 处理#791xiangfei258 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces support for LangChain's HumanInTheLoopMiddleware tool approval interrupts, resolving issues where they were incorrectly handled as standard user questions. Key changes include backend routing of HIL interrupts to a new human_approval_required status, payload compacting whitelist updates, and frontend support via a new HumanToolApprovalModal component allowing users to approve, reject, or edit tool arguments. Feedback on the PR highlights a potential issue in HumanToolApprovalModal.vue where editing string-based or empty tool arguments could cause JSON.parse to fail, and suggests a more robust parsing implementation.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const parseEditedArgs = () => { | ||
| try { | ||
| const parsed = JSON.parse(editText.value) | ||
| editError.value = '' | ||
| return parsed | ||
| } catch (e) { | ||
| editError.value = `参数不是合法 JSON:${e.message}` | ||
| return null | ||
| } | ||
| } |
There was a problem hiding this comment.
当原始参数 args 是一个普通字符串(例如 "some_string")或者为空(null/undefined)时,点击“编辑参数”后,formatArgs 会将其转换为 "some_string" 或 ""。在提交编辑时,parseEditedArgs 会直接调用 JSON.parse,这会导致解析失败(抛出 SyntaxError),使用户无法成功提交编辑。\n\n建议:在 parseEditedArgs 中,先对空输入进行处理(默认返回 {}),并判断原始参数是否为字符串类型。如果是字符串类型,则直接返回编辑后的文本,而不需要进行 JSON.parse。
const parseEditedArgs = () => {
const trimmed = editText.value.trim()
if (!trimmed) {
editError.value = ''
return {}
}
const originalArgs = props.actionRequests[0]?.args
if (typeof originalArgs === 'string') {
editError.value = ''
return trimmed
}
try {
const parsed = JSON.parse(trimmed)
editError.value = ''
return parsed
} catch (e) {
editError.value = '参数不是合法 JSON:' + e.message
return null
}
}
HumanInTheLoopMiddleware 触发的工具审批 interrupt 载荷为 action_requests/review_configs(HITLRequest),与 ask_user_question 的 questions 结构不同,原有逻辑在三处按 questions 假设导致 HIL 不可用: 1. check_and_handle_interrupts 无 questions 时塞默认空问题 「请选择一个选项」,前端收到空弹窗。现按 payload 是否含 action_requests 分流,HIL 中断发 human_approval_required 并携带 action_requests/review_configs,ask_user_question 保持原有行为。 2. _compact_stream_chunk 的 verbose=false 精简白名单漏掉 action_requests/review_configs,前端拿不到审批载荷。白名单补入 这两个字段。 3. run_worker 的 interrupt 摘要只取 questions,HIL 摘要为空。 _interrupt_summary 兼容两类载荷,HIL 摘要改为 「操作需要确认: 工具名(参数)」。 补充单元测试覆盖 payload 分流、compact 字段保留与摘要生成。
前端按 interrupt 类型分流:
- human_approval_required 渲染新的 HumanToolApprovalModal,
展示待审批工具名与参数,提供确认执行/编辑参数/拒绝三种决策,
提交 { decisions: [{ type: "approve" | "reject" | "edit", ... }] }
与后端 Command(resume=...) 恢复语义一致
- ask_user_question_required 仍走原有选项式弹窗,行为不变
useApproval 与 useAgentRunStream 的 hasPendingInterruptForRun
兼容 actionRequests(HIL 中断无 questions),避免弹窗一闪而过。
将 extractPendingInterrupt 抽到 approvalInterrupt.js 纯函数文件,
便于纯 node 单测。补充前端分流单测。
2a31144 to
4fdaba5
Compare
说明
本 PR 是 #784 的干净重新提交。
#784 误夹带了与 HIL 修复无关的本地定制 commit(logo / 首页 / 登录页 / 配置等),已被关闭。本 PR 仅保留 HIL 工具审批相关的改动。
改动内容
后端
ask_user_question处理(agent_run_service/chat_service/run_worker)test_agent_run_service/test_chat_stream_interrupt单测前端
HumanToolApprovalModal.vue工具审批弹窗,支持 approve / reject / editapprovalInterrupt.js,调整useApproval.js/useAgentRunStream.js/AgentChatComponent.vue接入审批弹窗Supersedes #784