✨ feat(agent-runtime): server-side human approval flow (resume approve / reject / reject_continue)#13829
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## canary #13829 +/- ##
==========================================
+ Coverage 66.70% 66.76% +0.06%
==========================================
Files 2031 2032 +1
Lines 172508 172782 +274
Branches 20197 17734 -2463
==========================================
+ Hits 115064 115360 +296
+ Misses 57320 57298 -22
Partials 124 124
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 517504e360
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return { newState: state, nextContext: undefined }; | ||
| } | ||
|
|
||
| const rejectionContent = rejectionReason |
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>
…2 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>
6666e61 to
ff7e676
Compare
…-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: diegomura/react-pdf#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.
# 🚀 LobeHub v2.1.50 (20260416) **Release Date:** April 16, 2026\ **Since v2.1.49:** 107 commits · 101 merged PRs · 13 contributors > This weekly release focuses on improving runtime stability and gateway execution consistency, while making Home/Recents workflows faster to navigate and easier to manage in daily use. --- ## ✨ Highlights - **Server-side Human Approval Flow** — Agent runtime now supports more reliable approve/reject/reject-continue handling in gateway mode, reducing stalled execution paths in long-running tasks. (#13829, #13863, #13873) - **Message Gateway End-to-End Hardening** — Gateway message flow, queue handling, tool callback routing, and stop interruption behavior were strengthened for better execution continuity. (#13761, #13816, #13820, #13815) - **Client Tool Execution in Gateway Mode** — Client-executor tools now run more predictably across gateway and desktop callers, with improved executor dispatch behavior. (#13792, #13790) - **Home / Recents / Sidebar Upgrade** — Sidebar layout, custom sort, recents operations, and profile actions were improved to reduce navigation friction in active sessions. (#13719, #13812, #13723, #13739, #13878, #13734) - **Agent Workspace and Documents Expansion** — Working panel and agent document workflows were expanded and polished for better day-to-day agent operations. (#13766, #13857) - **Provider and Model Compatibility Improvements** — Added GLM-5.1 support and refined model/provider edge-case handling, including schema and error-path fixes. (#13757, #13806, #13736, #13740) --- ## 🏗️ Core Agent & Architecture ### Agent runtime and intervention lifecycle - Added server-side human approval and improved runtime coordination across approve/reject decision paths. (#13829, #13863) - Improved interrupted-task handling and operation lifecycle consistency to reduce half-finished runtime states. (#13714) - Refined error classification and payload propagation so downstream surfaces receive clearer actionable errors. (#13736, #13740) ### Execution model and dispatch behavior - Introduced executor-aware runtime behavior to better separate client/server tool execution semantics. (#13758) - Improved tool/plugin resolution and manifest handling to avoid runtime failures on malformed inputs. (#13856, #13840, #13807) --- ## 📱 Gateway & Platform Integrations - Added message gateway support and strengthened queue/error behavior for more stable cross-channel execution. (#13761, #13816, #13820) - Improved gateway callback pipeline with protocol and API additions for `tool_execute` / `tool_result`. (#13762, #13764, #13765) - Improved bot/channel reliability and DM/slash handling in Discord-related paths. (#13805, #13724) --- ## 🖥️ CLI & User Experience - Improved CLI reliability across message/topic operations and build/minify-related paths. (#13731, #13888) - Added image-to-video options and improved command behavior for generation workflows. (#13788) - Improved desktop runtime behavior for remote fetch and Linux notification urgency handling. (#13789, #13782) --- ## 🔧 Tooling - Extracted gateway stream client into `@lobechat/agent-gateway-client` to centralize protocol usage and reduce duplication. (#13866) - Improved built-in tool coverage and runtime support, including GTD server runtime and missing lobe-kb tools. (#13854, #13876) - Updated skill and frontmatter consistency in workflow tooling. (#13730) --- ## 🔒 Security & Reliability - **Security:** Strengthened API key WS auth behavior and safer serverUrl forwarding in gateway-related auth paths. (#13824) - **Reliability:** Reduced runtime stalls by improving gateway stop/interrupt and approval-state routing behavior. (#13815, #13863, #13873) - **Reliability:** Added defensive guards for malformed tool manifests and non-string content edge cases. (#13856, #13753) --- ## 👥 Contributors **101 merged PRs** from **13 contributors** across **107 commits**. ### Community Contributors - @arvinxx - Runtime, gateway, and execution reliability improvements - @Innei - Navigation, workflow UX, and desktop/CLI refinements - @rdmclin2 - Sidebar, recents, and channel behavior updates - @ONLY-yours - Tooling/runtime fixes and model execution compatibility - @tjx666 - Model support and release/tooling maintenance - @nekomeowww - Memory and search-path stability fixes - @cy948 - CLI indexing and command flow fixes - @octo-patch - Local system runtime edge-case fixes - @djthread - Desktop runtime request reliability improvements - @rivertwilight - Documentation and changelog updates - @sudongyuer - Subscription/mobile support improvements - @Zhouguanyang - Provider/model configuration correctness fixes - @lobehubbot - Translation and maintenance automation support --- **Full Changelog**: v2.1.49...v2.1.50
Summary
Implements the server-side human approval flow so
execServerAgentRuntimecan correctly pause onwaiting_for_humanand resume on approve / reject / reject_continue. Mirrors the client-mode executors one-to-one — no new design.Fixes LOBE-7151
What changes
request_human_approveexecutor (src/server/modules/AgentRuntime/RuntimeExecutors.ts):role='tool'message per pending tool call withpluginIntervention: { status: 'pending' }skipCreateToolMessage(resumption path): looks up existing tool messages bytool_call_idinstead{ toolCallId → toolMessageId }map on thetools_callingstream chunk so clients can render approval UI without waiting foragent_runtime_endcall_toolexecutor (same file):skipCreateToolMessagebranch →updateToolMessageon the pre-existing pending row instead of inserting a new onetool_call_idrows andparent_idFK violations on approve (directly eliminates the LOBE-7154 class of errors on the approval path)AgentRuntimeService.handleHumanIntervention(src/server/services/agentRuntime/AgentRuntimeService.ts):intervention=approved+ returnphase: 'human_approved_tool'withskipCreateToolMessage: trueintervention=rejected+ transition tointerruptedwithreason='human_rejected'intervention=rejected+ returnphase: 'user_input'(LLM sees the rejection as user feedback)waiting_for_humanuntil the last tool is resolvedtoolMessageIdandrejectAndContinuenow flow from the tRPC schema (aiAgent.processHumanIntervention) through QStash payload,/runroute body,AgentExecutionParams, andexecuteStepintohandleHumanIntervention. A new actionreject_continuedistinguishes B from C cleanly.What's NOT in this PR
The frontend pieces (
conversationControl.tsserver-mode branches,gatewayEventHandlerchunk consumption,gateway.tsoperation metadata) will land in a follow-up PR so this change can be reviewed and shipped as a self-contained backend increment. The backend wire is backward compatible — legacy callers that don't sendtoolMessageIdno-op cleanly inside the handler.Test plan
bunx vitest run --silent=passed-only src/server/modules/AgentRuntime/__tests__/RuntimeExecutors.test.ts— 82 tests pass (12 new acrossrequest_human_approve+call_toolskip branch)bunx vitest run --silent=passed-only src/server/services/agentRuntime/__tests__/handleHumanIntervention.test.ts— 18 new tests pass (approve / pure reject / reject_continue / no-op paths)bunx vitest run --silent=passed-only src/server/services/agentRuntime/__tests__/executeStep.test.ts— 18 tests pass (regression check on transit)bun run type-check— clean for this diff (remaining errors are pre-existing:@dnd-kit,hono,larksuite, workflow memory routes)call_toolupdates rather than inserts a second row🤖 Generated with Claude Code