Skip to content

fix(agents): resolve paraId-less paragraphs by ordinal index in headless bridge#648

Open
jacobjove wants to merge 1 commit into
eigenpal:mainfrom
jacobjove:fix/headless-paraid-fallback
Open

fix(agents): resolve paraId-less paragraphs by ordinal index in headless bridge#648
jacobjove wants to merge 1 commit into
eigenpal:mainfrom
jacobjove:fix/headless-paraid-fallback

Conversation

@jacobjove
Copy link
Copy Markdown

@jacobjove jacobjove commented May 31, 2026

What & why

In the headless agent bridge, read_document (via formatContentForLLM) labels a paragraph that has no w14:paraId by its ordinal index[0], [1], … — because Word doesn't always emit paraIds. But buildParaIdMap only registered paragraphs that carried a paraId. So for a document without paraIds, every id read_document handed the agent was rejected by every paraId-anchored op — addComment, proposeChange, applyFormatting, setParagraphStyle, scrollTo (all five share the same map().get(paraId) lookup) — leaving the document effectively read-only through the bridge.

Fix

Key paraId-less paragraphs by String(index), mirroring the label formatContentForLLM already emits. The index space is identical to getContent (same paragraph/table/other counting), so the registered key and the advertised id always match. A real w14:paraId still takes precedence when present. The change is strictly additive: paraId-bearing paragraphs key exactly as before; paraId-less ones gain an entry that previously didn't exist.

No collision risk: generated paraIds are 8-char zero-padded hex (generateHexId) and Word's w14:paraId is ST_LongHexNumber (8 hex digits), so a real paraId is never equal to a 1–2 digit ordinal string.

find_text keeps its own !para.paraId guard (it deliberately only anchors paraId-bearing paragraphs) — surfacing paraId-less matches there is a separate follow-up, noted in the test.

Changes

  • packages/agents/src/reviewerBridge.tsbuildParaIdMap registers paraId ?? String(index).
  • packages/agents/src/__tests__/reviewerBridge.test.ts — 6 cases: ordinal addComment / proposeChange / applyFormatting resolve, real paraId still wins, ordinal counts across a table, unknown id still returns null.

Verification

bun run typecheck clean; bun test packages/agents/src/ → 247 pass / 0 fail. Changeset added (patch).

@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

Someone is attempting to deploy a commit to the EigenPal Team on Vercel.

A member of the Team first needs to authorize it.

@eigenpal-release-pal
Copy link
Copy Markdown
Contributor

eigenpal-release-pal Bot commented May 31, 2026

All contributors have signed the CLA ✍️ ✅

Posted by the CLA bot.

…ess bridge

`read_document` (formatContentForLLM) labels a paragraph with no w14:paraId by
its ordinal index — `[0]`, `[1]`, … — but `buildParaIdMap` only registered
paragraphs that carried a paraId. So for a document without paraIds (Word does
not always emit them) every id read_document handed the agent was rejected by
every paraId-anchored bridge op — addComment, proposeChange, applyFormatting,
setParagraphStyle, scrollTo — leaving the doc read-only through the bridge.

Key paraId-less paragraphs by `String(index)`, mirroring the label. The index
space is identical to getContent, so the key and the advertised id match, and a
real paraId still takes precedence when present. All five map consumers share
the same lookup, so the fix applies uniformly. find_text keeps its own
paraId-only guard by design — a separate follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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