This release includes 3 breaking changes for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Topics
+7 more
Affected surfaces
Summary
AI summaryBroad release touches Known limitations, Patch Changes, Toolkit, and Spec specs/live-agent-chat.md.
Full changelog
Minor Changes
-
6094eaf: Built-in agent panel + chat primitives + expanded toolkit so consumers can plug a streaming AI agent into the editor in ~50 lines. See
docs/agents.md.Agent panel
<DocxEditor agentPanel={{ render }}>— controllable right-hand dock with toolbar toggle, drag-to-resize, persisted width, animated open/close. Render-prop receives{ close }; controlled mode (open+onOpenChange) lets a parent drive it.- New
agent-sparkleicon and i18n keys across en / de / pl / pt-BR.
Chat primitives (opinionated, optional)
<AgentChatLog>,<AgentComposer>,<AgentSuggestionChip>,<AgentTimeline>— Google-Docs-style UI for message list, composer, starter chips, and a collapsible tool-call timeline (per-row spinner while streaming, auto-collapses to "N steps" on done).- New types:
AgentMessage,AgentToolCall.
Toolkit (
@eigenpal/docx-editor-agents)- Four new tools:
apply_formatting,set_paragraph_style,read_page,read_pages. useDocxAgentToolshook withinclude/excludefilters;executeToolCallenforces them.AgentToolDefinition.displayNamefor friendly UI labels.- New subpath exports — package stays runtime-agnostic, AI SDK helpers are opt-in:
/server—getToolSchemas,executeToolCall,getToolDisplayName(OpenAI function-calling format)/react—useDocxAgentTools/ai-sdk/server—getAiSdkTools()returningstreamText({ tools })shape/ai-sdk/react—toAgentMessages()adaptinguseChat'sUIMessage[]toAgentMessage[]
WordCompatBridgeparity contract — compile-time assertion thatEditorBridgecoversRange.font.*andParagraphFormat.style.
Bug fixes
- Rapid sequential
addCommentcalls now all persist. The unifiedsetCommentssetter read a stalecommentsRef.currentfor every call; a 30-comment burst kept only the last. Now assignscommentsRef.currentsynchronously in uncontrolled mode.
Spec / Word-API hardening
paraIdallocator — newParaIdAllocatorExtensionassigns fresh 8-char hexw14:paraIds on Enter / paste / split. Without this the agent's anchors silently drifted whenever the user typed Enter. MarkedaddToHistory: false.apply_formattingvalidatesunderline.styleagainst ECMA-376 §17.3.2.40ST_Underlineandhighlightagainst §17.3.2.15ST_HighlightColor. Out-of-spec values return a structured error instead of round-tripping invalid OOXML.set_paragraph_stylereturnsfalsefor ids not instyles.xml— matches Word'sItemNotFoundbehavior.
Public API additions
@eigenpal/docx-js-editor:<AgentPanel>,<AgentChatLog>,<AgentComposer>,<AgentSuggestionChip>,<AgentTimeline>, matching prop types,AgentMessage,AgentToolCall.DocxEditorRefgainsapplyFormatting,setParagraphStyle,getPageContent.@eigenpal/docx-editor-agents: new/ai-sdk/serverand/ai-sdk/reactsubpaths (peer depai, optional)./serverand/reactunchanged.displayNameonAgentToolDefinition.Known limitations (v1.1)
- Missing Word
Range.font.*properties:superscript,subscript,allCaps,smallCaps,doubleStrikeThrough,colorThemetint/shade. - No paragraph-level mutators (
alignment,lineSpacing,spaceBefore,spaceAfter) wired through the toolkit yet.
-
9c0721b: Add
disableFindReplaceShortcutstoDocxEditorso host apps can let the browser handle native Cmd/Ctrl+F and Cmd/Ctrl+H shortcuts. -
c81fdd3: # Live agent chat + server-side MCP support
A Word-API-style bridge that lets an AI agent read a DOCX, comment on it, suggest tracked changes, and scroll the view — live in a running editor, or server-side against a parsed file. Same tool catalog, same shape, two transports.
The pattern
Locate, then mutate. The agent calls a locate tool (
read_document,read_selection,find_text) which returns paragraphs tagged with their stable Wordw14:paraId. It passes those paraIds to mutate tools. paraIds survive concurrent edits and tool-loop iterations; ordinal indices don't.Ten agent tools
OpenAI function-calling format (also accepted by Anthropic / Vercel AI SDK):
- Locate —
read_document,read_selection,find_text,read_comments,read_changes - Mutate —
add_comment,suggest_change(one tool, three modes via empty-string semantics: replacement / deletion / insertion at paragraph end),reply_comment,resolve_comment - Navigate —
scroll
Exported from
@eigenpal/docx-editor-agentsasagentTools,getToolSchemas(),executeToolCall(name, args, bridge).Two bridges, same interface
Everything wires into an
EditorBridgeinterface. Two implementations ship:// Live editor in a browser import { useAgentChat } from '@eigenpal/docx-editor-agents/bridge'; const { executeToolCall, toolSchemas } = useAgentChat({ editorRef, author: 'AI' }); // Server-side, against a parsed DOCX import { DocxReviewer, createReviewerBridge } from '@eigenpal/docx-editor-agents'; const reviewer = await DocxReviewer.fromBuffer(buffer, 'AI'); const bridge = createReviewerBridge(reviewer); const result = executeToolCall('add_comment', { paraId, text }, bridge);Both expose the same 10 tools to the agent. The bridge layer abstracts the transport.
MCP server (built-in, spec 2025-06-18)
import { McpServer, createReviewerBridge, DocxReviewer } from '@eigenpal/docx-editor-agents'; import { McpServer as _ } from '@eigenpal/docx-editor-agents/mcp'; const server = new McpServer(bridge, { name: 'my-saas', version: '1.0.0' }); const reply = server.handle(jsonRpcMessage); // sync, transport-free, never throws- Transport-agnostic core: wire
server.handle()to HTTP-SSE, WebSocket, your queue worker, or a managed stdio process. The library does not pick a transport. - stdio adapter for customers who want to run the server inside a worker pool:
runStdioServer(bridge)(Node-only). - Spec compliance:
initialize/tools/list/tools/call/ping. Tool failures use the spec's{isError: true, content: [...]}envelope inside a successful JSON-RPC response; JSON-RPC errors are reserved for protocol-level problems. Includes UTF-8-safe chunk decoding (multi-byte codepoints don't break across stdio chunks) and a buffer cap to prevent memory DoS.
A local-install stdio bin was prototyped and removed: one-document-per-config is the wrong shape for a contract-review product. The right deployment is a hosted MCP service the customer operates with their own auth + storage.
Events
bridge.onContentChange(listener)andbridge.onSelectionChange(listener)(both return unsubscribe functions) let host apps and MCP servers react to edits without owning the single React callback prop.ContentChangeEventships{ commentCount, changeCount, comments, changes }.SelectionChangeEventships the currentSelectionInfoornull. (Reviewer bridge: never fires — no caret in headless mode.)
New on
DocxEditorRefaddComment({ paraId, text, author, search? }) → number | null replyToComment(commentId, text, author) → number | null resolveComment(commentId) → void proposeChange({ paraId, search, replaceWith, author }) → boolean findInDocument(query, { caseSensitive?, limit? }) → FoundMatch[] getSelectionInfo() → SelectionInfo | null getComments() → Comment[] onContentChange(listener) → () => void onSelectionChange(listener) → () => voidscrollToParaIdwas already public.New on
@eigenpal/docx-corefindParagraphByParaId(doc, paraId)returns the PM range for a paragraph by paraId.Word JS API parity contract
WordCompatBridge(exported type from the package root) formally documents every Office.js Word API method we mirror. A compile-time static assertion enforces thatEditorBridgesatisfies it. If we drop or change a method that's part of the public Word-API mirror, typecheck breaks.Demos
examples/agent-use-demo(roast-my-doc) — server-side demo of the canonical "build your own MCP-shaped agent server" pattern: parse →createReviewerBridge→agentTools→ tool-call loop withexecuteToolCall→toBuffer(). The route's preamble shows the one-line diff to convert it to a real MCP server.examples/agent-chat-demo(chat with your doc) — live editor + chat panel. DemonstratesuseAgentChatagainst a running<DocxEditor>.
Both demos support
ALLOWED_ORIGINSenv var for production deployments (open by default for local dev), forward clientAbortSignalto OpenAI calls, and cap upload size.Hardening
proposeChangerefuses to layer onto an existing tracked-change run (would produce invalid OOXML).- Ambiguous
searcharguments return an error instead of silently mistargeting. scrolldoes not steal the user's caret.- Comment IDs and tracked-change revisionIds use the shared monotonic counter to avoid collisions in OOXML.
- Mark guards if a host StarterKit omits
comment/insertion/deletionextensions.
Spec
specs/live-agent-chat.md. - Locate —
-
8dba7e8: # Word-style split button for text + highlight color (issue #130)
Closes #130.
The font-color and highlight-color toolbar buttons are now Word-style split buttons. Two halves:
- Apply half (icon + swatch): click to re-apply the last color you picked. No dropdown.
- Arrow half (▾): click to open the full color picker (theme grid, standard colors, custom hex, "no color").
Pick a color once, then for every subsequent occurrence just click the swatch — one click instead of three.
API surface (consolidated)
The package previously shipped two color pickers — a simple
ColorPickerand a fullerAdvancedColorPicker. The two have been merged into a singleColorPickerwith two new props:splitButton?: boolean— defaulttrue. Setfalseto render a legacy single-button shape.defaultColor?: ColorValue | string— initial "last picked" color used by the apply half before the user picks anything. Defaults: text → red, highlight → yellow, border → black.
The "last picked" memory is independent of the current selection's color (matches Word). Picking "Automatic" / "No color" does NOT update it.
Breaking changes
-
The legacy
ColorPicker(the simpler grid picker that ran inline, not via dropdown) has been removed. Its typesColorOptionand the oldColorPickerPropsshape are no longer exported. -
AdvancedColorPickerhas been renamed toColorPicker. Update imports:- import { AdvancedColorPicker } from '@eigenpal/docx-js-editor'; + import { ColorPicker } from '@eigenpal/docx-js-editor';The exported
ColorPickerPropsandColorPickerModetypes now correspond to the renamed component (formerlyAdvancedColorPickerProps/AdvancedColorPickerMode). -
CSS class names changed from
docx-advanced-color-picker-*→docx-color-picker-*. If you targeted these in user CSS overrides, update the selectors.
Migration
No changes needed inside the library — text-color, highlight-color, table-cell-fill, and table-border-color buttons all use the new
ColorPickerautomatically. If you importAdvancedColorPickerdirectly, switch toColorPicker. If you used the legacy simplerColorPicker, the newColorPickeris a drop-in for any case that benefits from the fuller picker; otherwise build a small custom picker — the legacy one was thin enough to inline.
Patch Changes
-
71a1836: Replace hardcoded
816page-width literals inDocxEditorwith the existing
DEFAULT_PAGE_WIDTHconstant exported fromPagedEditor, and fold the two
duplicatedpageWidthfallback expressions into a singlepageWidthPxvalue
shared byUnifiedSidebarandCommentMarginMarkers. -
f31fd5a: Fix document outline overlap and ruler behavior
- Outline panel no longer sits on top of the page. On wide viewports the
page stays where it was (centered, or translated left by the comments
sidebar) — only the layout's min-width grows so the centered page never
overlaps the panel. On narrow viewports the page + outline scroll
horizontally as a unit instead. - Outline panel header lines up with the doc's top margin and uses a
transparent background so the page's left-side shadow stays visible when
the viewport is squeezed. - Vertical ruler stays pinned to the viewport's left edge during horizontal
scroll instead of scrolling out of view. - Horizontal ruler is now sticky inside the scroll container, so it scrolls
horizontally with the doc and stays put on vertical scroll. Padding tracks
the outline (right shift) and comments sidebar (left shift) so the ruler
centers against the same axis as the page. - Editor surround uses
--doc-bguniformly so the over-scroll/rubber-band
area matches the gutter.
- Outline panel no longer sits on top of the page. On wide viewports the
-
6a0b9a9: Fix crash when accepting a tracked replacement.
The
paragraphChangeTrackerplugin walkedtr.stepsusing each step's raw
from/to/posagainsttr.doc(the final doc after every step has been
applied). Those coords are valid only in the doc as it was when that step
ran, so a later doc-shrinking step could leave the earlier step's coords
past the final doc end and crashFragment.nodesBetweenon
undefined.nodeSize.Concretely:
acceptChangeemits[RemoveMarkStep, ReplaceStep]when the
range contains both aninsertionmark and adeletion(a tracked
replace). The replace shrinks the doc, the mark step'stobecomes
invalid intr.doc, and the editor crashes.Remap each step's coords through
tr.mapping.slice(stepIndex + 1)before
using them withtr.doc, and skip steps whose range was fully consumed by
a later deletion. Adds a regression test reproducing the
accept-tracked-replacement crash shape. -
95f8df1: Add Brazilian Portuguese (pt-BR) locale support with 100% translation coverage.
This PR introduces:
- New
packages/react/i18n/pt-BR.jsonfile - 619 translated UI strings (100% coverage)
- Proper locale structure following existing patterns
- All keys in sync with en.json source
The translation covers core UI elements including:
- Common actions (cancel, save, edit, etc.)
- Toolbar and formatting controls
- Color picker and dialog interfaces
- Table operations and context menus
- Error messages and status indicators
- New
Breaking Changes
- Removed legacy `ColorPicker` component and its types (`ColorOption`, old `ColorPickerProps`).
- Renamed `AdvancedColorPicker` to `ColorPicker`; update imports accordingly.
- CSS class names changed from `docx-advanced-color-picker-*` to `docx-color-picker-*`.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About Docx Editor
All releases →Related context
Related tools
Earlier breaking changes
- v@eigenpal/[email protected] Shared i18n package extracted into @eigenpal/docx-editor-i18n.
- v@eigenpal/[email protected] `showPrintButton` prop removed from `<DocxEditor>` and toolbar components.
- v@eigenpal/[email protected] Toolbar naming unified across React and Vue adapters; classic toolbar removed.
- v@eigenpal/[email protected] Agent UI components relocated to new agent packages and API changed.
- v@eigenpal/[email protected] Shared i18n package extracted from adapters into dedicated locale bundle.
Beta — feedback welcome: [email protected]