Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2f4cbf2
feat(sdk): update tool definitions for efficient multi-block workflows
tupizz Apr 6, 2026
039a036
feat(evals,sdk): add efficient workflow patterns to all agent touchpo…
tupizz Apr 6, 2026
dc427eb
feat(evals): enable tool search to reduce token overhead
tupizz Apr 6, 2026
091da29
docs(ai): add markdown insert pattern and formatting guidance
tupizz Apr 6, 2026
2c94377
docs(ai): add efficient patterns to MCP how-to-use guide
tupizz Apr 6, 2026
9f65e2c
fix(evals): remove debug console.log that dumped every SDK message
tupizz Apr 6, 2026
13ba3a6
feat(document-api): add alignment field to StyleApplyStep and StyleAp…
tupizz Apr 6, 2026
b67b909
fix(document-api): keep inline required on StyleApplyInput, guard opt…
tupizz Apr 6, 2026
98a1609
feat(document-api): add alignment to format.apply step JSON schema
tupizz Apr 6, 2026
69f45cf
feat(super-editor): support alignment in format.apply mutation step
tupizz Apr 6, 2026
9aa655b
docs(sdk): update tool descriptions to show alignment inside format.a…
tupizz Apr 6, 2026
145693d
feat(document-api): add scope: block to format.apply for full-paragra…
tupizz Apr 6, 2026
64cab87
feat(document-api): allow placement and BlockNodeAddress target for m…
tupizz Apr 6, 2026
c3395d6
chore: regenerate SDK artifacts and docs from updated contract
tupizz Apr 6, 2026
1e4e294
feat(evals): add new NDA documents and implement interactive DOCX out…
tupizz Apr 6, 2026
4c04ebd
fix: address PR review — minProperties, RichContentInsertInput type, …
tupizz Apr 6, 2026
ee17a46
Revert "fix: address PR review — minProperties, RichContentInsertInpu…
tupizz Apr 6, 2026
e95f430
fix(document-api): add minProperties, type export, shared alignment c…
tupizz Apr 6, 2026
16d6a52
docs(sdk): require fontSize on headings after markdown insert
tupizz Apr 6, 2026
8da40b0
docs(sdk): context-driven formatting guidance for markdown inserts
tupizz Apr 6, 2026
e61a515
docs(sdk): only set properties explicitly present in document blocks
tupizz Apr 6, 2026
f39f127
feat(super-editor): resolve default fontSize in get_content blocks re…
tupizz Apr 6, 2026
739a18f
fix(super-editor): fallback to 10pt default when styles omit fontSize
tupizz Apr 6, 2026
20a1341
fix(super-editor): resolve fontSize per-block via style chain in get_…
tupizz Apr 6, 2026
e0b7e23
test(super-editor): add fontSize style chain resolution tests for blo…
tupizz Apr 6, 2026
c5a322f
docs(sdk): guide agents to match uppercase title conventions
tupizz Apr 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions apps/docs/ai/agents/best-practices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ Instruct the LLM to plan all edits before calling tools. A well-structured promp

Batch multiple changes only when atomic execution is genuinely helpful — use `superdoc_mutations` for that.

## Prefer markdown insert for multi-block creation

When you need to create multiple headings and paragraphs in one operation, use `superdoc_edit` with `type: "markdown"` instead of calling `superdoc_create` once per block. A single markdown insert produces the entire structure in one call.

```json
{
"tool": "superdoc_edit",
"intent": "insert",
"target": { "type": "end" },
"content": {
"type": "markdown",
"value": "## Executive Summary\n\nThis agreement governs the terms of service.\n\n## Key Provisions\n\nThe following provisions apply to all parties."
}
}
```

After inserting, apply formatting in a single `superdoc_mutations` batch using `format.apply` steps — one step per block or range. This reduces a workflow that might otherwise take 40+ calls down to 4: read, search, insert, format.

## Use focused tools; `superdoc_mutations` is an escape hatch

For straightforward edits, use the focused intent tools (`superdoc_edit`, `superdoc_format`, `superdoc_create`, `superdoc_list`, `superdoc_comment`). They validate arguments, give clear errors, and are easier for models to call correctly.
Expand All @@ -90,6 +108,27 @@ try {
}
```

## Choose formatting values from the document

Don't hardcode formatting values. Read them from the document's existing content and match what's already there.

**Body text:** Read `fontFamily`, `fontSize`, and `color` from non-empty paragraphs with `alignment: "justify"` or `alignment: "left"`. Set `bold: false` for body paragraphs.

Many DOCX documents report `underline: true` on all blocks due to style inheritance. This is a DOCX artifact — not intentional formatting. Do not carry it forward when inserting new paragraphs.

**Headings:** Read from existing heading blocks in the document. Scale `fontSize` up relative to body text. Headings are typically bold and sometimes centered — confirm against what's already in the document rather than assuming.

```typescript
// Get content first, find a representative body paragraph
const content = await superdoc.getContent();
const bodyParagraph = content.blocks.find(
(b) => b.type === 'paragraph' && b.text?.trim().length > 0
);
const { fontFamily, fontSize, color } = bodyParagraph?.formatting ?? {};

// Use those values when formatting inserted content
```

## Add examples for repeatable workflows

If the same kind of edit runs across many documents (e.g., always rewriting a specific clause, always adding a comment to a section), include a concrete tool call example in your system prompt. Models that see a working example of the exact tool invocation produce correct calls more reliably than models that only see the schema.
Expand Down
61 changes: 58 additions & 3 deletions apps/docs/ai/mcp/how-to-use.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,71 @@ superdoc_open → superdoc_get_content / superdoc_search → intent tools → su
4. `superdoc_save` writes changes to disk
5. `superdoc_close` releases the session

## Efficient patterns

### Create multiple sections at once

Use `superdoc_edit` with `type: "markdown"` to insert structured content in a single call. It parses markdown into proper document nodes — headings, paragraphs, bold, italic, and lists.

```
superdoc_edit({
session_id,
action: "insert",
type: "markdown",
placement: "end",
content: "# Background\n\nThis section covers the project history.\n\n# Next steps\n\n1. Review the proposal\n2. Assign owners\n3. Set a deadline"
})
```

Markdown syntax maps to document styles:

| Markdown | Document node |
|----------|--------------|
| `# Heading` | Heading 1 |
| `## Heading` | Heading 2 |
| `**text**` | Bold |
| `*text*` | Italic |
| `- item` | Bullet list |
| `1. item` | Numbered list |

### Format multiple items at once

Use `superdoc_mutations` with `format.apply` steps to apply formatting across the document in one atomic call.

```
superdoc_mutations({session_id, action: "apply", atomic: true, changeMode: "direct", steps: [
{id: "f1", op: "format.apply", where: {by: "node", select: {type: "node", nodeType: "heading", level: 1}}, args: {inline: {bold: true}}, require: "all"},
{id: "f2", op: "format.apply", where: {by: "node", select: {type: "node", nodeType: "heading", level: 2}}, args: {inline: {italic: true}}, require: "all"}
]})
```

<Warning>
Format targets must exist before the batch runs. Node selectors resolve at step execution time using the current document state. If a required target is missing, the step fails and — with `atomic: true` — the entire batch rolls back.
</Warning>

### When to use which tool

| Task | Best tool |
|------|-----------|
| Insert one paragraph or heading | `superdoc_create` |
| Insert multiple sections with structure | `superdoc_edit` with `type: "markdown"` |
| Replace text across the whole document | `superdoc_search` + `superdoc_edit` |
| Rewrite a whole paragraph | `superdoc_get_content` + `superdoc_edit` with block ref |
| Apply formatting to known text | `superdoc_search` + `superdoc_format` |
| Apply formatting to all nodes of a type | `superdoc_mutations` with `format.apply` |
| Multiple text changes that must succeed together | `superdoc_mutations` with `atomic: true` |
| Review or resolve tracked changes | `superdoc_track_changes` |

## Targeting

Every editing tool needs a **target** telling the API *where* to apply the change. There are three ways to get one:

- **From blocks data**: Each block has a `ref` (pass to `superdoc_edit` or `superdoc_format`) and a `nodeId` (for building `at` positions with `superdoc_create`).
- **From `superdoc_search`**: Returns `handle.ref` covering the matched text. Use search when you need to find text patterns, not when you already know which block to target.
- **From `superdoc_create`**: Returns `nodeId` for chaining creates and building block targets. Re-fetch blocks after create to get a fresh ref before formatting.
- **From `superdoc_create`**: Returns `nodeId` and `ref` for the new node. For creating multiple sections or blocks at once, prefer `superdoc_edit` with `type: "markdown"` instead of multiple `superdoc_create` calls. Re-fetch blocks after create to get a fresh ref before formatting.

<Warning>
**Refs expire after any mutation.** Always re-search or re-read blocks before the next operation.
**Refs expire after any mutation.** Always re-search or re-read blocks before the next operation. Within a `superdoc_mutations` batch, node selectors resolve automatically at step execution time, so re-fetching between steps is not required.
</Warning>

## Common operations
Expand Down Expand Up @@ -75,7 +130,7 @@ superdoc_list({session_id, action: "create", mode: "fromParagraphs", preset: "di

### Batch edits atomically

Use `superdoc_mutations` when you need multiple text changes that must succeed or fail together:
Use `superdoc_mutations` when you need multiple changes that must succeed or fail together. Supported step types include `text.rewrite`, `text.delete`, `format.apply`, `create.heading`, `create.paragraph`, and `create.table`.

```
superdoc_mutations({session_id, action: "apply", atomic: true, changeMode: "direct", steps: [
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/document-api/reference/_generated-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1016,5 +1016,5 @@
}
],
"marker": "{/* GENERATED FILE: DO NOT EDIT. Regenerate via `pnpm run docapi:sync`. */}",
"sourceHash": "4a3601ee0f28a73c712fbe06e8b4913a9ae882a71152f9f6e892ea51137fc5e8"
"sourceHash": "a77f6a56704f39dcdc2d65ef8192ea4fffc0c8fb797bf13f516a949557d6e0ec"
}
21 changes: 18 additions & 3 deletions apps/docs/document-api/reference/mutations/apply.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,16 @@ The runtime capability snapshot also exposes this allowlist at `planEngine.suppo
"args": {
"additionalProperties": false,
"properties": {
"alignment": {
"description": "Set paragraph alignment on the target block(s). Can be combined with inline formatting in the same step.",
"enum": [
"left",
"center",
"right",
"justify"
],
"type": "string"
},
"inline": {
"additionalProperties": false,
"minProperties": 1,
Expand Down Expand Up @@ -1754,11 +1764,16 @@ The runtime capability snapshot also exposes this allowlist at `planEngine.suppo
}
},
"type": "object"
},
"scope": {
"description": "When \"block\", inline formatting expands to cover the entire parent paragraph(s), not just the matched text. Use \"block\" after markdown inserts to format whole paragraphs with a short identifying pattern. Default: \"match\".",
"enum": [
"match",
"block"
],
"type": "string"
}
},
"required": [
"inline"
],
"type": "object"
},
"id": {
Expand Down
21 changes: 18 additions & 3 deletions apps/docs/document-api/reference/mutations/preview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,16 @@ The runtime capability snapshot also exposes this allowlist at `planEngine.suppo
"args": {
"additionalProperties": false,
"properties": {
"alignment": {
"description": "Set paragraph alignment on the target block(s). Can be combined with inline formatting in the same step.",
"enum": [
"left",
"center",
"right",
"justify"
],
"type": "string"
},
"inline": {
"additionalProperties": false,
"minProperties": 1,
Expand Down Expand Up @@ -1740,11 +1750,16 @@ The runtime capability snapshot also exposes this allowlist at `planEngine.suppo
}
},
"type": "object"
},
"scope": {
"description": "When \"block\", inline formatting expands to cover the entire parent paragraph(s), not just the matched text. Use \"block\" after markdown inserts to format whole paragraphs with a short identifying pattern. Default: \"match\".",
"enum": [
"match",
"block"
],
"type": "string"
}
},
"required": [
"inline"
],
"type": "object"
},
"id": {
Expand Down
Binary file added evals/fixtures/claude-orlov-gs-nda.docx
Binary file not shown.
Binary file added evals/fixtures/codex-orlov-gs-nda-codex.docx
Binary file not shown.
Binary file added evals/fixtures/codex-orlov-gs-nda.docx
Binary file not shown.
36 changes: 28 additions & 8 deletions evals/providers/claude-code-agent.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,32 @@ const SUPERDOC_SYSTEM_PROMPT = `You have a SuperDoc MCP server connected with to

IMPORTANT: You MUST use the SuperDoc MCP tools for ALL .docx operations. Do NOT use Bash with unzip, python-docx, mammoth, or manual XML parsing.

Workflow:
1. superdoc_open(path) → returns session_id
2. Use superdoc_get_content, superdoc_search, superdoc_edit, superdoc_format, superdoc_create, superdoc_comment, superdoc_track_changes, superdoc_mutations with the session_id
3. superdoc_save(session_id) to persist changes
4. superdoc_close(session_id) when done
## Efficient workflows

These tools handle OOXML format correctly and preserve document structure. Raw XML manipulation will corrupt the document.`;
### Creating multiple headings and paragraphs

Use superdoc_edit with type "markdown" to create ALL structure in one call:

superdoc_edit({action: "insert", type: "markdown", placement: "end", value: "# Heading 1\\n\\nParagraph text...\\n\\n# Heading 2\\n\\nMore text..."})
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 Use a valid placement literal in benchmark agent guidance

The prompt example hard-codes placement: "end", but insert validation only accepts before, after, insideStart, or insideEnd; "end" is rejected as INVALID_INPUT. When the benchmark agent follows this example (and the same one in evals/providers/codex-agent.mjs), its first markdown insert fails and burns turns/cost for recoverable errors.

Useful? React with 👍 / 👎.


This creates proper Heading styles from # markers, bold from **text**, italic from *text*, and lists. One call replaces many superdoc_create calls.

### Applying formatting to multiple items at once

Use superdoc_mutations with format.apply and require "all" to batch formatting:

superdoc_mutations({action: "apply", steps: [{id: "f1", op: "format.apply", where: {by: "select", select: {type: "node", nodeType: "heading"}, require: "all"}, args: {inline: {color: "#FF0000"}}}]})

This formats every heading at once instead of formatting one at a time.

### Standard workflow

1. superdoc_open(path) → session_id
2. For reading: superdoc_get_content
3. For creating structure: superdoc_edit with type "markdown" (preferred for multiple blocks) or superdoc_create (for a single block at a specific position)
4. For formatting: superdoc_mutations with format.apply steps (preferred for multiple items) or superdoc_format (for a single item)
5. For text edits: superdoc_edit (single) or superdoc_mutations (batch)
6. superdoc_save then superdoc_close`;

const SUPERDOC_CLI_AGENTS_MD = `# AGENTS.md

Expand Down Expand Up @@ -150,6 +169,7 @@ export default class ClaudeCodeBenchmarkProvider {

try {
const env = { ...process.env };
env.ENABLE_TOOL_SEARCH = 'auto:5';
if (!this.config.superdocOnPath) {
env.PATH = env.PATH.split(':')
.filter(p => !p.includes('superdoc'))
Expand Down Expand Up @@ -188,7 +208,7 @@ export default class ClaudeCodeBenchmarkProvider {
model,
allowedTools: this.config.allowedTools || ['Bash', 'Read', 'Write', 'Edit', 'Glob', 'Grep'],
disallowedTools: this.config.disallowedTools,
maxTurns: this.config.maxTurns || 20,
maxTurns: this.config.maxTurns || 35,
permissionMode: 'bypassPermissions',
allowDangerouslySkipPermissions: true,
settingSources: [], // SDK isolation mode: don't load user MCP servers (Linear, Excalidraw, etc.)
Expand Down Expand Up @@ -229,7 +249,7 @@ export default class ClaudeCodeBenchmarkProvider {
prompt: fullPrompt,
options: queryOptions,
})) {
console.log('message', message);
console.log(message);

if (message.type === 'assistant' && message.message?.content) {
for (const block of message.message.content) {
Expand Down
30 changes: 28 additions & 2 deletions evals/providers/codex-agent.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,34 @@ const SUPERDOC_MCP_AGENTS_MD = `# AGENTS.md
You have a SuperDoc MCP server available. Use it for ALL .docx file operations.

**Do NOT** use unzip, python-docx, mammoth, sed, or manual XML editing on .docx files.
**Do** use the superdoc_* MCP tools: superdoc_open → superdoc_get_content/search/edit → superdoc_save → superdoc_close.

The SuperDoc tools handle OOXML format correctly and preserve document structure.
## Efficient workflows

### Creating multiple headings and paragraphs

Use superdoc_edit with type "markdown" to create ALL structure in one call:

\`\`\`
superdoc_edit({action: "insert", type: "markdown", placement: "end", value: "# Heading\\n\\nParagraph...\\n\\n# Heading 2\\n\\nMore text..."})
\`\`\`

This creates proper Heading styles from # markers, bold from **text**, italic from *text*. One call replaces many superdoc_create calls.

### Applying formatting to multiple items at once

Use superdoc_mutations with format.apply and require "all":

\`\`\`
superdoc_mutations({action: "apply", steps: [{id: "f1", op: "format.apply", where: {by: "select", select: {type: "node", nodeType: "heading"}, require: "all"}, args: {inline: {color: "#FF0000"}}}]})
\`\`\`

### Standard workflow

1. superdoc_open → session_id
2. Create structure: superdoc_edit with type "markdown" (multiple blocks) or superdoc_create (single block)
3. Format: superdoc_mutations format.apply (batch) or superdoc_format (single item)
4. Text edits: superdoc_edit or superdoc_mutations
5. superdoc_save → superdoc_close
`;

const SUPERDOC_CLI_AGENTS_MD = `# AGENTS.md
Expand Down Expand Up @@ -146,6 +171,7 @@ export default class CodexBenchmarkProvider {
NODE_ENV: 'production',
FORCE_COLOR: '0',
NO_COLOR: '1',
ENABLE_TOOL_SEARCH: 'auto:5',
};

// Install vendor DOCX skill (Anthropic's docx skill) as AGENTS.md
Expand Down
Loading
Loading