mirror of
https://github.com/lobehub/lobehub
synced 2026-04-21 09:37:28 +00:00
* ✨ feat(agent-runtime): implement server-side human approval flow Port the client-mode human approval executors (request_human_approve, call_tool resumption, handleHumanIntervention) to the server agent runtime so that execServerAgentRuntime can correctly pause on waiting_for_human and resume on approve / reject / reject_continue. - request_human_approve now creates one `role='tool'` message per pending tool call with `pluginIntervention: { status: 'pending' }` and ships the `{ toolCallId → toolMessageId }` mapping on the `tools_calling` stream chunk. - call_tool gains a `skipCreateToolMessage` branch that updates the pre-existing tool message in-place (prevents duplicate rows / parent_id FK violations that show up as LOBE-7154 errors). - AgentRuntimeService.handleHumanIntervention implements all three paths: approve → `phase: 'human_approved_tool'`; reject → interrupted with `reason: 'human_rejected'`; reject_continue → `phase: 'user_input'`. - ProcessHumanIntervention schema carries `toolMessageId` and a new `reject_continue` action; schema remains permissive (handler no-ops on missing toolMessageId) to keep legacy callers working. Fixes LOBE-7151 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix(agent-runtime): address LOBE-7151 review (P1 reject_continue, P2 duplicate tool msg) P1 — reject_continue with remaining pending tools must NOT resume the LLM. Previously `handleHumanIntervention` kept `status='waiting_for_human'` but returned `nextContext: { phase: 'user_input' }`, which `executeStep` would hand to `runtime.step` immediately, breaking batch semantics. Now when other tools are still pending, the rejection is persisted but no context is returned; the `user_input` continuation only fires when this is the last pending tool. P2 — request_human_approve was pushing an empty placeholder `{ role: 'tool', tool_call_id, content: '' }` into `newState.messages` to "reflect" the newly-created pending DB row. On resume, the `call_tool` skip-create path appends the real tool result, leaving two entries for the same `tool_call_id` in runtime state. The downstream short-circuit (`phase=human_approved_tool` → `call_tool`) doesn't consult state.messages, so the placeholder was unused cost. Removed. Also fixes a TS 2339 in the skipCreateToolMessage test where `nextContext.payload` is typed `{}` and needed an explicit cast. Tests: 99 pass (82 RuntimeExecutors + 17 handleHumanIntervention), type-check clean. Verified end-to-end via the human-approval eval — it now exercises a multi-turn retry path (LLM calls the gated tool twice) and both approvals resolve cleanly through to `completionReason=done`. Relates to LOBE-7151 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * pin @react-pdf/renderer * 🐛 fix(deps): pin @react-pdf/image to 3.0.4 to avoid privatized @react-pdf/svg @react-pdf/image@3.1.0 (auto-resolved via layout@4.6.0 ← renderer@4.4.1) declares `@react-pdf/svg@^1.1.0` as a dependency, but the svg package was unpublished/made private on npm (returns 404). CI installs blow up with ERR_PNPM_FETCH_404. Upstream issue: https://github.com/diegomura/react-pdf/issues/3377 Pin image to 3.0.4 (the last release before the broken svg dep was introduced) via pnpm.overrides until react-pdf publishes a fix. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| examples | ||
| src | ||
| package.json | ||
| vitest.config.mts | ||