🐛 fix(page-agent): inject active documentId into context on send#15610
Conversation
Page-scoped conversations never carried the open document id to the agent runtime. At send time `operationContext` only had agentId/scope/ topicId, so the gateway's `appContext.documentId` was undefined and the server-side PageAgent runtime threw "received a tool call without documentId in context". Inject the live document id from the page editor runtime (`pageAgentRuntime.getCurrentDocId()`) into `operationContext` when scope is `page`, so it flows through `execAgentTask` → server `state.metadata.documentId` → tool execution context. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: adfa47c19e
ℹ️ 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".
| const activePageDocumentId = | ||
| context.scope === 'page' && !context.documentId | ||
| ? pageAgentRuntime.getCurrentDocId() | ||
| : undefined; |
There was a problem hiding this comment.
Avoid injecting a stale page document id
When a page-scoped send omits context.documentId, this now falls back to the singleton pageAgentRuntime.getCurrentDocId(). That singleton is updated later by PageEditor/StoreUpdater effects, while sendAsWrite creates a new document, calls navigate('/page/${newDoc.id}'), and immediately calls sendMessage({ context: { agentId: pageAgentId, scope: 'page' } }) without waiting for the new editor to mount. If the runtime is still bound to the previous page, the gateway context is populated with that previous document id, so server-side PageAgent tools can read/modify the wrong document instead of the new one. Prefer passing the known new document id through the context (or only inject when the runtime is known to match the active page).
Useful? React with 👍 / 👎.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## canary #15610 +/- ##
==========================================
+ Coverage 67.14% 67.18% +0.04%
==========================================
Files 3353 3350 -3
Lines 338505 338338 -167
Branches 35060 36160 +1100
==========================================
+ Hits 227278 227318 +40
+ Misses 111036 110829 -207
Partials 191 191
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
…avoid stale injection The page-scoped documentId fallback reads the page editor runtime singleton, which is only authoritative once the active page's editor has mounted. `sendAsWrite` creates a document, navigates, and sends immediately — before the new editor mounts — so the singleton may still be bound to the previously open page, scoping server-side PageAgent tools to the wrong document. Thread the freshly created `newDoc.id` through the conversation context; the existing `!context.documentId` guard then skips the singleton fallback entirely. Document the constraint at the fallback site. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# 🚀 LobeHub Release (20260610) **Release Date:** June 10, 2026 **Since v2.2.2:** 131 merged PRs · 13 contributors > This weekly release strengthens agent collaboration across cloud, desktop, CLI, and workspace flows, with steadier runtime behavior and a broader foundation for workspace-scoped data. --- ## ✨ Highlights - **Agent execution across devices** — Unifies per-device working directories, project skill discovery, and sub-agent suspend/resume behavior across server, QStash, and device RPC flows. (#15543, #15566, #15481, #15620, #15591) - **Connector and sandbox platform** — Expands connector permissions, custom OAuth MCP connector onboarding, sandbox provider support, and user-uploaded file sync into cloud sandbox runs. (#15463, #15546, #15184, #15550) - **Desktop and CLI reliability** — Fixes desktop cold-start, auto-update, Windows build, CLI skill discovery, and `lh connect` agent dispatch paths. (#15547, #15525, #15527, #15562, #15632, #15634) - **Pages and sharing** — Refreshes topic sharing, improves Page Editor layout behavior, and routes Page Agent tool execution through the server-side editor path. (#15581, #15556, #15588, #15023, #15610) - **Model availability and provider updates** — Adds user-scoped LobeHub model availability, Claude Fable 5, Qwen thinking preservation, and MiniMax M3 updates. (#15590, #15639, #13494, #15376) --- ## 🏗️ Core Product & Architecture ### Agent Runtime & Heterogeneous Agents - Improves sub-agent lifecycle handling, including async suspend/resume, queue-mode QStash resume delivery, and blocking nested sub-agent calls. (#15481, #15620, #15575) - Stabilizes heterogeneous agent ingestion and streaming with raw stream dumps, per-turn usage, image forwarding on regenerate, and duplicate-text fixes. (#15602, #15577, #15592, #15585) - Adds execution-device and working-directory controls across device RPC, legacy defaults, and remote-spawned Claude Code sessions. (#15543, #15566, #15591, #15572) - Improves runtime diagnostics and compatibility, including Gemini multimodal output capture, abort stream semantics, and trace quality analysis. (#15535, #13677, #15508) --- ## 📱 Platforms, Integrations & UX ### Connectors, Sandbox & Tools - Ships API-level connector tool permissions, custom OAuth MCP connector onboarding, and connector-first runtime execution. (#15463, #15546) - Adds sandbox provider support, cloud sandbox file sync, and safer external URL file input handling with SSRF validation. (#15184, #15550, #12657) - Improves tool visibility and execution with pinned app-fixed tools, ANSI output rendering, gateway-tunneled MCP calls, and automatic headless tool runs. (#15509, #15516, #15469, #15492) ### Desktop, CLI & Web UX - Restores desktop startup and reload behavior, preserves IPC error causes, and keeps the tab bar new-tab action visible across routes. (#15547, #15597, #15638) - Fixes desktop update and build stability for browser quit guards, macOS update signing, and Windows Visual Studio detection. (#15525, #15527, #15562) - Shows the plan-limit upgrade UI on desktop builds. (#15628) - Adds the Agent Run delivery checker and fixes CLI device dispatch plus skill list/search output. (#15489, #15634, #15632) - Refreshes onboarding, auth source preservation, topic UI states, referral/Fable campaign copy, and chat-input control bar behavior. (#15629, #15544, #15573, #15614, #15616, #15617, #15622, #15643) --- ## 🔒 Security, Reliability & Rollout Notes - External URL file input now includes SSRF validation for safer Google file handling. (#12657) - Database workspace-scope migrations are part of this release; self-hosted operators should run the normal migration path before serving the updated app. (#15446, #15465, #15468, #15472) - The release branch was re-cut from `canary` and includes the latest `main` release-version commit so `v2.2.2` is the verified compare base. --- ## 👥 Contributors @ONLY-yours, @sxjeru, @hardy-one, @xujingli, @hezhijie0327, @Coooolfan, @arvinxx, @tjx666, @Innei, @rivertwilight, @rdmclin2, @cy948, @AmAzing129 **Full Changelog**: v2.2.2...release/weekly-20260610-recut-3
💻 Change Type
🔗 Related Issue
🔀 Description of Change
Page-scoped conversations (the Page editor's agent) never carried the currently open document id to the agent runtime. When a message was sent,
operationContextonly heldagentId/scope/topicId, so the gateway'sappContext.documentIdwasundefined. On the server,state.metadata.documentIdwas therefore empty and the PageAgent server runtime rejected every tool call:Root cause: the whole server chain (TRPC
ExecAgentSchema→appContext→state.metadata→RuntimeExecutors→ tool ctx) already reserved adocumentIdslot; the gateway whitelist (gateway.ts) already readscontext.documentId. The only gap was that nobody filled that field at send time — the client path works because it reads theEditorRuntimesingleton directly, but the gateway/server path can only see what travels in the context.Fix: at send time in
sendMessage, whenscope === 'page', inject the live document id from the page editor runtime (pageAgentRuntime.getCurrentDocId()) intooperationContext. This is the same source the client-side executor uses, so both paths now agree. It flows:operationContext→executeGatewayAgent→execAgentTaskappContext→ serverstate.metadata.documentId→ tool execution ctx.Guards:
scope === 'page'(no leakage into normal chats).!context.documentIdpreserves an explicitly-provided value.getCurrentDocId()returnsundefined→ nothing added.🧪 How to Test
Added two unit tests in
conversationLifecycle.test.ts:executeGatewayAgentreceivescontext.documentIdfromgetCurrentDocId().documentIdis not injected even when a doc is open.bun run type-checkpasses;conversationLifecycle.test.ts32/32 pass.Manual: open a page in the editor, send a message to the Page agent in gateway/cloud mode, and confirm the agent's document tool calls (
readDocument/modifyNodes) succeed instead of throwing the missing-documentId error.