Skip to content

fix(docs): drop tabs field mask to support smart-chip docs in get/write/replace#382

Open
elisabuonanni-nu wants to merge 1 commit into
gemini-cli-extensions:mainfrom
elisabuonanni-nu:fix/docs-include-comments
Open

fix(docs): drop tabs field mask to support smart-chip docs in get/write/replace#382
elisabuonanni-nu wants to merge 1 commit into
gemini-cli-extensions:mainfrom
elisabuonanni-nu:fix/docs-include-comments

Conversation

@elisabuonanni-nu
Copy link
Copy Markdown

Summary

docs_getText, docs_writeText, and docs_replaceText all fail against any Google Doc containing smart chips (Person, Date, RichLink, Dropdown, etc.) with:

Field mask cannot retrieve comment-specific fields when include_comments is false.

The Docs API treats some content reachable via the fields: 'tabs' mask as comment-anchored once smart chips are present in the doc. The REST API does not expose any include_comments parameter that callers can set — an attempt to pass includeComments: true is rejected by the SDK as Unknown name 'include_comments'. The fix is to drop the explicit field mask while keeping includeTabsContent: true, which still returns the tab content but no longer trips the trigger.

What changed

workspace-server/src/services/DocsService.ts, three call sites:

  • writeText — end-of-doc preflight (resolving position: 'end')
  • getText
  • replaceText — preflight that locates ranges before issuing replaceAllText requests

Each docs.documents.get(...) call now passes only documentId and includeTabsContent: true. The downstream code only consumes tabs.tabProperties.tabId and tabs.documentTab.body.content (via the existing _flattenTabs helper), all of which are returned in the API default field set.

Repro

Any Google Doc with at least one smart chip and any of the three affected tools. Before this PR: field-mask error. After: full body returned, smart chips preserved as inline tokens.

Test plan

  • npm run build clean
  • docs_getText against a doc with Person, Date, and RichLink chips → returns body
  • No regression on plain docs (still returns content via the default mask)
  • Reviewer: confirm jest suite still green (I did not run the full suite locally)

🤖 Generated with Claude Code

When a Google Doc contains smart chips (Person, Date, RichLink, Dropdown,
or other structural inline tokens), calls to `docs.documents.get` with
`fields: 'tabs'` and `includeTabsContent: true` fail with:

  Field mask cannot retrieve comment-specific fields when
  include_comments is false.

The Docs API treats some content reachable via the `tabs` mask as
comment-anchored when smart chips are present, but the REST API does
not expose any `include_comments` parameter that callers can set.
Removing the explicit field mask while keeping `includeTabsContent: true`
sidesteps the trigger and works on both smart-chip and plain docs.

Fixed in three call sites in `DocsService.ts`:

- `writeText` — end-of-doc preflight (resolving `position: 'end'`)
- `getText`
- `replaceText` — preflight to locate ranges

Repro: any Google Doc containing at least one smart chip, calling
`docs_getText`, `docs_writeText`, or `docs_replaceText` against it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Jun 1, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request removes the explicit 'fields: 'tabs'' mask from Google Docs API calls in DocsService.ts to prevent errors when fetching documents containing smart chips. While this successfully avoids API errors, the reviewer identified a critical index mismatch and potential data corruption bug in replaceText when dealing with smart chips. Because smart chips are rendered as markdown strings in _getFullDocumentText, the text length exceeds the actual document's index space, causing index drift and misaligned replacement requests. The reviewer recommends introducing a keepAlignment flag to represent smart chips with length-aligned placeholders.

Comment on lines 730 to 733
const docBefore = await docs.documents.get({
documentId: id,
fields: 'tabs',
includeTabsContent: true,
});
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.

critical

Critical Index Mismatch / Data Corruption Bug in replaceText with Smart Chips

While this PR successfully fixes the API error when fetching documents containing smart chips, enabling replaceText on these documents exposes a severe correctness and potential data corruption bug.

Root Cause

  1. replaceText calls _generateReplacementRequests, which relies on _getFullDocumentText to build a plain-text representation of the document for finding search term occurrences.
  2. _getFullDocumentText calls _readStructuralElement, which renders smart chips (Person, RichLink, Date) into markdown strings (e.g., [John Doe](mailto:john@example.com)).
  3. In a Google Doc, a smart chip occupies a specific index span (typically exactly 1 character in the document's UTF-16 coordinate space).
  4. By rendering the chip as a long markdown string, the length of documentText becomes much larger than the actual document's index space. This causes all subsequent text indices to drift and become completely misaligned.
  5. _generateReplacementRequests then uses these drifted indices to construct deleteContentRange and insertText requests, which will point to incorrect offsets in the actual document.

Consequence

This will result in either:

  • API Errors: The update requests fail because the calculated indices are out of bounds.
  • Silent Data Corruption: The API successfully executes the update but deletes/replaces the wrong text in the document, corrupting user data.

Recommended Solution

Introduce a parameter to _readStructuralElement and _getFullDocumentText to return index-aligned text (where smart chips are represented by placeholders of their actual document length) instead of their rendered markdown:

  1. Update _readStructuralElement to accept a keepAlignment?: boolean flag.
  2. If keepAlignment is true, instead of rendering the markdown for person/link/date chips, return a placeholder string (e.g., spaces or \uFFFC) of length (pElement.endIndex ?? 0) - (pElement.startIndex ?? 0) (which is typically 1).
  3. Pass keepAlignment: true when calling _getFullDocumentText from _generateReplacementRequests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant