Skip to content

🐛 fix: consolidate agent-documents tools and fix empty readDocument#14288

Merged
arvinxx merged 1 commit into
canaryfrom
fix/agent-documents-tools
Apr 29, 2026
Merged

🐛 fix: consolidate agent-documents tools and fix empty readDocument#14288
arvinxx merged 1 commit into
canaryfrom
fix/agent-documents-tools

Conversation

@arvinxx

@arvinxx arvinxx commented Apr 28, 2026

Copy link
Copy Markdown
Member

💻 Change Type

  • 🐛 fix
  • ♻️ refactor

🔗 Related Issue

Related to LOBE-8358 (cloud team).

🔀 Description of Change

Two changes in one PR — both about the lobe-agent-documents builtin tool.

**1. Fix: readDocument returns empty content for ~5% of agent documents **

AgentDocumentsService.attachLiteXML was the only read path that did not apply the markdown fallback when editorData hydration silently failed. For documents that have valid markdown in documents.content but a editor_data JSON saved by an older Lexical schema, editor.hydrateEditorData() throws (HeadingNode.splice: start + deleteCount > oldSize (undefined + 0 > undefined) in Lexical 0.42), the error is caught by @lobehub/editor, and the editor ends up empty. Previously the empty snapshot was returned to the LLM as content: "" — indistinguishable from a genuinely empty document, leading agents to retry with different formats / filenames.

The fix detects the empty-snapshot case and re-hydrates from the markdown column (exportEditorDataSnapshot({ editorData: undefined, fallbackContent: doc.content, litexml: true })), which produces both correct markdown and a fresh, valid LiteXML.

Verified against a real prod row (1387 chars markdown, 16 568 chars stale editor_data) — fix yields content.length = 1387 and litexml.length = 4673 with proper <h1>/<quote>/<p> nodes.

2. Refactor: consolidate the agent-documents tool surface

Goal: one read entry, no by-filename variants, clearer write API name.

  • Drop readDocumentByFilename from the LLM tool — read by ID is the only entry now.
  • Drop upsertDocumentByFilename from the LLM tool. Internal AgentDocumentsService.upsertDocumentByFilename is kept because cloud onboarding flows (user.ts, webOnboarding) still rely on it; only the LLM-facing surface is removed.
  • Rename editDocumentreplaceDocumentContent across manifest, types enum, executor, ExecutionRuntime, Inspector, TRPC, client service, i18n keys, Conversation workflow constants, and tests.
  • systemRole.ts gains an explicit "If the response contains empty content, the document is genuinely empty; do not retry with a different format or filename" hint to stop the format/filename retry loop seen in production traces.

Net result: 11 LLM-facing APIs → 9. No more dual read paths, no `format` / `filename` combinations for the model to thrash through.

🧪 How to Test

  • Tested locally — repro'd the empty-content bug end-to-end against a prod row before/after the fix.
  • Added/updated tests — `agentDocuments.test.ts`, `runtime/agentDocuments.test.ts`, `agentDocument.test.ts`, `action.test.ts`, `toolSetComposer.test.ts` — 83/83 passing.
  • `bun run type-check` — no errors related to these files.

📝 Additional Information

Breaking changes (LLM-facing):

  • The model can no longer call `lobe-agent-documents____readDocumentByFilename____builtin` or `lobe-agent-documents____upsertDocumentByFilename____builtin`. In-flight conversations that have those tool definitions in context will see "tool not found" if the model tries them.
  • `lobe-agent-documents____editDocument____builtin` is renamed to `lobe-agent-documents____replaceDocumentContent____builtin`.

The agent-documents-index already names `readDocument` as the only read entry, so the model has guidance to fall back gracefully when it sees the new tool list.

Non-breaking:

  • Internal `AgentDocumentsService` exposes `replaceDocumentContentById` (renamed from `editDocumentById`); `upsertDocumentByFilename` method is retained.
  • TRPC procedure renamed `editDocument` → `replaceDocumentContent`; client service method renamed accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

@vercel

vercel Bot commented Apr 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lobehub Ready Ready Preview, Comment Apr 28, 2026 6:58pm

Request Review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @arvinxx, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. feature:tool Tool calling and function execution labels Apr 28, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19be44107f

ℹ️ 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".

Comment on lines 121 to +123
const scheduleNode = task.automationMode ? (
<TaskScheduleConfig
currentInterval={taskDetail?.heartbeat?.interval ?? 0}
taskId={task.identifier}
>
<TaskTriggerTag
automationMode={task.automationMode}
heartbeatInterval={taskDetail?.heartbeat?.interval}
schedulePattern={task.schedulePattern}
scheduleTimezone={task.scheduleTimezone}
/>
</TaskScheduleConfig>
<TaskTriggerTag
automationMode={task.automationMode}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep schedule trigger wrapped in TaskScheduleConfig

Replacing TaskScheduleConfig with a bare TaskTriggerTag removes the schedule popover and its click stopPropagation, so clicking the schedule pill now bubbles to the parent clickable row and navigates to /task/:id instead of opening inline schedule controls. This is a functional regression for automated tasks because list-level schedule edits are no longer possible from this entry point.

Useful? React with 👍 / 👎.

@codecov

codecov Bot commented Apr 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 33.33333% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.28%. Comparing base (6f9f564) to head (c99e627).
⚠️ Report is 1 commits behind head on canary.

Additional details and impacted files
@@            Coverage Diff             @@
##           canary   #14288      +/-   ##
==========================================
- Coverage   68.28%   68.28%   -0.01%     
==========================================
  Files        2328     2328              
  Lines      201505   201464      -41     
  Branches    25376    25376              
==========================================
- Hits       137607   137577      -30     
+ Misses      63765    63754      -11     
  Partials      133      133              
Flag Coverage Δ
app 62.05% <33.33%> (-0.01%) ⬇️
database 92.30% <ø> (ø)
packages/agent-runtime 79.93% <ø> (ø)
packages/context-engine 83.25% <ø> (ø)
packages/conversation-flow 92.40% <ø> (ø)
packages/file-loaders 87.02% <ø> (ø)
packages/memory-user-memory 74.74% <ø> (ø)
packages/model-bank 99.89% <ø> (ø)
packages/model-runtime 83.71% <ø> (ø)
packages/prompts 68.63% <ø> (ø)
packages/python-interpreter 92.90% <ø> (ø)
packages/ssrf-safe-fetch 0.00% <ø> (ø)
packages/utils 88.93% <ø> (ø)
packages/web-crawler 88.41% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Store 66.42% <50.00%> (+<0.01%) ⬆️
Services 53.48% <50.00%> (+0.09%) ⬆️
Server 69.19% <22.22%> (-0.02%) ⬇️
Libs 53.30% <ø> (ø)
Utils 80.04% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Rework the lobe-agent-documents builtin tool surface and fix a
long-standing bug where readDocument returned empty content for ~5% of
agent documents that had non-empty markdown plus a stale editor_data
JSON.

Tool surface changes (LLM-facing):
- Drop readDocumentByFilename — read by ID is the only entry now
- Drop upsertDocumentByFilename from the LLM tool (kept on the internal
  AgentDocumentsService for onboarding/user.ts/webOnboarding)
- Rename editDocument → replaceDocumentContent across manifest, types
  enum, executor, ExecutionRuntime, Inspector, TRPC, client service,
  i18n keys, Conversation workflow constants, and tests
- systemRole gains an explicit "empty content means the document is
  empty, do not retry" hint to stop the format/filename retry loop

readDocument empty-content fix:
- AgentDocumentsService.attachLiteXML now detects when hydrating a
  stale editorData yields an empty editor while doc.content has
  markdown, and re-hydrates from the markdown column with a fresh
  litexml. Previously the empty snapshot was returned as-is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arvinxx arvinxx force-pushed the fix/agent-documents-tools branch from 19be441 to c99e627 Compare April 28, 2026 18:42
@arvinxx arvinxx merged commit a2b8f4c into canary Apr 29, 2026
42 of 45 checks passed
@arvinxx arvinxx deleted the fix/agent-documents-tools branch April 29, 2026 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature:tool Tool calling and function execution size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant