Live editor bridge

Reference for the live-editor agent bridge: useDocxAgentTools, useAgentBridge, createEditorBridge, the agentPanel prop, chat UI, and paraId anchors.

Reference for wiring model tool calls to a running <DocxEditor>. For a complete walkthrough, read the AI editing tutorial first; this page documents the APIs it uses.

useDocxAgentTools (React)

The main React hook from @eigenpal/docx-editor-agents/react. It creates the bridge to the editor and returns the tool schemas, executor, and context snapshot.

const { tools, executeToolCall, getContext } = useDocxAgentTools({
  editorRef, // React.RefObject<EditorRefLike | null>; DocxEditorRef satisfies it
  author: 'Assistant', // stamped on comments + tracked changes. Default: 'AI'
  include: ['read_document', 'find_text', 'add_comment'], // optional allow-list
  exclude: ['apply_formatting'], // optional block-list, applied after include
  tools: { my_tool: myToolDefinition }, // optional custom tools, keyed by name
});

Returns:

MemberTypePurpose
toolsOpenAI function-calling schemasPass to your provider (streamText({ tools }), OpenAI tools, Anthropic tools)
executeToolCall(name, args) => AgentToolResultThe executor. Hand to AI SDK's onToolCall or call it from your own loop
getContext() => AgentContextSnapshotSnapshot of { selection, currentPage, totalPages } for system-prompt injection

Behavior worth knowing:

  • include / exclude filter built-in tools both in the returned schemas and at execution time. A filtered tool call returns Tool 'x' is not enabled. Custom tools are not filtered by these options.
  • A custom tool with a built-in's name replaces the built-in.
  • Pass a stable (memoized or module-level) tools object to avoid rebuilding schemas every render.
  • Tool calls before the editor mounts return { success: false, error: 'Editor not ready.' }.

useAgentChat (React)

The minimal variant: executor plus static schemas, no filtering, no context snapshot.

import { useAgentChat } from '@eigenpal/docx-editor-agents/react';

const { executeToolCall, toolSchemas } = useAgentChat({ editorRef, author: 'Assistant' });

Use useDocxAgentTools unless you specifically want the smaller surface.

useAgentBridge (Vue)

The Vue twin, from @eigenpal/docx-editor-agents/vue:

import { ref } from 'vue';
import { useAgentBridge, type EditorRefLike } from '@eigenpal/docx-editor-agents/vue';

const editorRef = ref<EditorRefLike | null>(null);
const { executeToolCall, toolSchemas } = useAgentBridge({
  editorRef,
  author: 'Assistant', // accepts a string or a Ref<string>
});

Same EditorRefLike contract, same tool catalog, same AgentToolResult shape. As of 1.4 it matches useAgentChat (executor + schemas); the include/exclude/custom-tools options live in the React hook only, so filter toolSchemas yourself and guard names in your dispatch if you need scoping in Vue.

createEditorBridge (any host)

For hosts that are neither React nor Vue, build the bridge directly from @eigenpal/docx-editor-agents/bridge:

import { createEditorBridge, type EditorRefLike } from '@eigenpal/docx-editor-agents/bridge';
import { executeToolCall, getToolSchemas } from '@eigenpal/docx-editor-agents';

const bridge = createEditorBridge(editorHandle satisfies EditorRefLike, 'Assistant');
const result = executeToolCall('find_text', { query: 'liability' }, bridge);

EditorRefLike is the structural contract both adapters' DocxEditorRef satisfy: addComment, proposeChange, findInDocument, getSelectionInfo, applyFormatting, setParagraphStyle, scrollToParaId, getPageContent, and friends. Anything implementing it can host the toolkit. The resulting EditorBridge also satisfies the compile-time Word JS API parity contract.

The agentPanel prop (React)

<DocxEditor agentPanel={...}> mounts a right-hand panel with a header, close button, drag-resize handle, and toolbar toggle button. Three control patterns:

  • Uncontrolled: agentPanel={{ render }}. The toolbar and close buttons toggle it; width persists to localStorage.
  • Controlled: agentPanel={{ render, open, onOpenChange }}. You own open state.
  • Headless: omit agentPanel entirely and render the toolkit's output wherever you want.
<DocxEditor
  agentPanel={{
    render: ({ close }) => <MyChatUI onClose={close} />, // called only while open
    open, // optional: controlled open state
    onOpenChange: setOpen, // fires on toolbar / close button clicks
    showToolbarButton: true, // default true
    toolbarBadge: <Dot />, // optional badge on the toolbar button
    title: 'Assistant', // panel header title
    icon: <SparkIcon />, // header icon, default sparkle
    defaultWidth: 360, // px, default 360
    minWidth: 280, // drag limit, default 280
    maxWidth: 600, // drag limit, default 600
  }}
/>

The panel shell is configurable through these options; render your own chat UI inside render. In Vue the agentPanel prop does not exist yet (React-only per the parity contract); mount the AgentPanel component from @eigenpal/docx-editor-agents/vue next to the editor instead.

Chat UI components

Optional components for the inside of the panel. React: @eigenpal/docx-editor-agents/react. Vue: @eigenpal/docx-editor-agents/vue.

ComponentPurpose
AgentChatLogMessage list with streaming text and a collapsible tool-call timeline. Props: messages: AgentMessage[], loading, error, humanizeToolName (pass getToolDisplayName), emptyState
AgentComposerInput row. React props: value, onChange, onSubmit, disabled, placeholder, footnote. The Vue component uses modelValue (v-model) instead of value/onChange and has no footnote prop
AgentTimelineStandalone tool-call list (running spinner, done check), used internally by the chat log
AgentSuggestionChipPrompt-suggestion chip for empty states
AgentPanelThe panel shell itself, for hosts not using the agentPanel prop

If you drive the chat with the Vercel AI SDK, toAgentMessages(chat.messages, chat.status) from @eigenpal/docx-editor-agents/ai-sdk/react (or /ai-sdk/vue) converts useChat's UIMessage[] into the AgentMessage[] shape these components render. You can also render components from another chat UI library or your own design system.

paraId anchoring

Every locate tool returns paragraphs tagged with paraId; every mutate tool addresses by it. Details that make this reliable:

  • The id is Word's own w14:paraId attribute, read from the file and preserved through save, so anchors stay valid across the whole edit session and across reloads.
  • A ParaIdAllocatorExtension runs in the editor and assigns fresh ids when paragraphs are created or split (Enter, paste). Concurrent typing while the agent loop runs does not desync anchors.
  • Paragraphs that arrive without a paraId (Word does not always emit them) are addressed by their ordinal index as a string. Use the ids returned by locate tools when you call mutate tools.
  • Sub-paragraph anchoring uses search: an exact phrase that must occur exactly once in the paragraph. find_text returns the matched phrase precisely so it can be passed back as search.

This is also why the tool surface serializes cleanly over JSON (and MCP): an anchor is a plain { paraId, search? } value, not a live object like Office.js' Range.

Next steps

On this page