@pixerate/editor 0.223.3 → 0.223.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tools/skill-evals.d.cts +6 -1
- package/dist/tools/skill-evals.d.ts +6 -1
- package/package.json +1 -1
- package/skills/README.md +4 -1
- package/skills/pixerate-image-photo-correction/evals/neutralise-cast.json +2 -2
- package/skills/pixerate-image-product-photo/evals/grounding-shadow.json +1 -1
- package/skills/pixerate-rich-text/SKILL.md +8 -0
- package/skills/pixerate-rich-text-report/SKILL.md +98 -0
- package/skills/pixerate-rich-text-report/evals/heading-case.json +48 -0
- package/skills/pixerate-rich-text-report/evals/results-table.json +93 -0
- package/skills/pixerate-rich-text-report/evals/structure.json +106 -0
- package/skills/pixerate-rich-text-revise/SKILL.md +92 -0
- package/skills/pixerate-rich-text-revise/evals/fix-typos.json +57 -0
- package/skills/pixerate-rich-text-revise/evals/rename-term.json +51 -0
- package/skills/pixerate-rich-text-revise/evals/tighten-intro.json +55 -0
|
@@ -20,7 +20,7 @@ export interface SkillEvalCheck extends SkillEvalToolCall {
|
|
|
20
20
|
}
|
|
21
21
|
export interface SkillEval {
|
|
22
22
|
prompt: string;
|
|
23
|
-
fixture: SpreadsheetEvalFixture | ImageEvalFixture | VectorEvalFixture | PaintEvalFixture | VideoEvalFixture | ChartEvalFixture | DiagramEvalFixture;
|
|
23
|
+
fixture: SpreadsheetEvalFixture | ImageEvalFixture | VectorEvalFixture | PaintEvalFixture | VideoEvalFixture | ChartEvalFixture | DiagramEvalFixture | RichTextEvalFixture;
|
|
24
24
|
checks: SkillEvalCheck[];
|
|
25
25
|
solution: SkillEvalToolCall[];
|
|
26
26
|
}
|
|
@@ -77,6 +77,11 @@ export interface DiagramEvalFixture {
|
|
|
77
77
|
/** Tool calls that build the starting diagram (`load_diagram_mermaid`), run in order. */
|
|
78
78
|
setup?: SkillEvalToolCall[];
|
|
79
79
|
}
|
|
80
|
+
export interface RichTextEvalFixture {
|
|
81
|
+
editor: 'rich-text';
|
|
82
|
+
/** The starting document as HTML. */
|
|
83
|
+
html: string;
|
|
84
|
+
}
|
|
80
85
|
/** One eval file of a skill. */
|
|
81
86
|
export interface SkillEvalFile {
|
|
82
87
|
skill: string;
|
|
@@ -20,7 +20,7 @@ export interface SkillEvalCheck extends SkillEvalToolCall {
|
|
|
20
20
|
}
|
|
21
21
|
export interface SkillEval {
|
|
22
22
|
prompt: string;
|
|
23
|
-
fixture: SpreadsheetEvalFixture | ImageEvalFixture | VectorEvalFixture | PaintEvalFixture | VideoEvalFixture | ChartEvalFixture | DiagramEvalFixture;
|
|
23
|
+
fixture: SpreadsheetEvalFixture | ImageEvalFixture | VectorEvalFixture | PaintEvalFixture | VideoEvalFixture | ChartEvalFixture | DiagramEvalFixture | RichTextEvalFixture;
|
|
24
24
|
checks: SkillEvalCheck[];
|
|
25
25
|
solution: SkillEvalToolCall[];
|
|
26
26
|
}
|
|
@@ -77,6 +77,11 @@ export interface DiagramEvalFixture {
|
|
|
77
77
|
/** Tool calls that build the starting diagram (`load_diagram_mermaid`), run in order. */
|
|
78
78
|
setup?: SkillEvalToolCall[];
|
|
79
79
|
}
|
|
80
|
+
export interface RichTextEvalFixture {
|
|
81
|
+
editor: 'rich-text';
|
|
82
|
+
/** The starting document as HTML. */
|
|
83
|
+
html: string;
|
|
84
|
+
}
|
|
80
85
|
/** One eval file of a skill. */
|
|
81
86
|
export interface SkillEvalFile {
|
|
82
87
|
skill: string;
|
package/package.json
CHANGED
package/skills/README.md
CHANGED
|
@@ -59,6 +59,8 @@ request like "clean up this export" finds it.
|
|
|
59
59
|
| [`pixerate-spreadsheet-financial-model`](pixerate-spreadsheet-financial-model/SKILL.md) | Spreadsheet (`pixerate-spreadsheet`) | Inputs apart from calculations, one formula pattern per row, no hard-coded numbers, scenarios and audits. |
|
|
60
60
|
| [`pixerate-diagram-process-flow`](pixerate-diagram-process-flow/SKILL.md) | Diagram (`pixerate-diagram`) | Processes as flowcharts: terminals, verb steps, decisions with labelled exits, loops and swimlanes. |
|
|
61
61
|
| [`pixerate-diagram-architecture`](pixerate-diagram-architecture/SKILL.md) | Diagram (`pixerate-diagram`) | Systems at one level of detail, store shapes, tiers and trust boundaries, flows labelled with protocols. |
|
|
62
|
+
| [`pixerate-rich-text-report`](pixerate-rich-text-report/SKILL.md) | Rich text (`pixerate-rich-text`) | Reports with one title and a heading hierarchy, lists, tables and charts, and a consistency pass. |
|
|
63
|
+
| [`pixerate-rich-text-revise`](pixerate-rich-text-revise/SKILL.md) | Rich text (`pixerate-rich-text`) | Proofreading, renaming terms with exceptions and tightening, as minimal targeted edits. |
|
|
62
64
|
| [`pixerate-talking-head-edit`](pixerate-talking-head-edit/SKILL.md) | Video (`pixerate-video-editor`) | Talking-head cleanup by transcript: fillers, long pauses and stutters found in one pass and cut as one plan reviewed before it applies. Owns the dialogue tools. |
|
|
63
65
|
| [`pixerate-bgm-alignment`](pixerate-bgm-alignment/SKILL.md) | Video (`pixerate-video-editor`) | Background music: beats and cuts on the beat, ducking under speech, loudness in LUFS. Owns the music tools. |
|
|
64
66
|
|
|
@@ -124,7 +126,8 @@ same change.
|
|
|
124
126
|
`{ "editor": "image", "width", "height", "background", "shapes" }` or `{ "editor":
|
|
125
127
|
"vector", "width", "height", "setup" }` with commands that draw the starting art,
|
|
126
128
|
`{ "editor": "paint", "width", "height", "setup" }` `{ "editor": "video", "setup" }` or `{ "editor":
|
|
127
|
-
"chart", "setup" }`
|
|
129
|
+
"chart", "setup" }` `{ "editor": "diagram", "setup" }` with tool calls,
|
|
130
|
+
or `{ "editor": "rich-text", "html" }`), `checks` (a read-only
|
|
128
131
|
tool, or `run_command` with a read-only command such as `vector.list`, its `args`, what its result must match in `expect`, and `why`) and a `solution` (the
|
|
129
132
|
tool calls an expert would make). The test proves each eval: some check fails on the fixture,
|
|
130
133
|
and all pass after the solution. A model harness runs the same file with the model in place
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"checks": [
|
|
14
14
|
{ "why": "the grey card is neutral (cast within ±4 levels)", "tool": "measure_region", "args": { "x": 12, "y": 52, "width": 16, "height": 16 }, "expect": { "cast": { "redBlue": { "$min": -4, "$max": 4 }, "greenMagenta": { "$min": -4, "$max": 4 } } } },
|
|
15
|
-
{ "why": "the card
|
|
15
|
+
{ "why": "the card stays a mid grey, not crushed or blown (the task asks for neither brighter nor darker)", "tool": "measure_region", "args": { "x": 12, "y": 52, "width": 16, "height": 16 }, "expect": { "stats": { "luminance": { "mean": { "$min": 60, "$max": 200 } } } } },
|
|
16
16
|
{ "why": "no channel clips anywhere", "tool": "measure_region", "expect": { "clipping": { "highlightsPercent": { "red": { "$max": 0.5 }, "green": { "$max": 0.5 }, "blue": { "$max": 0.5 } }, "shadowsPercent": { "red": { "$max": 0.5 }, "green": { "$max": 0.5 }, "blue": { "$max": 0.5 } } } } },
|
|
17
|
-
{ "why": "the correction
|
|
17
|
+
{ "why": "the correction stays adjustable: an adjustment layer or the base white balance (the develop filter), not baked into the photo", "tool": "list_layers", "expect": { "$expr": "v.layers.some((l) => l.type === 'adjustment' || (l.filters || []).some((f) => f.kind === 'develop' && (f.temperature || f.tint)))" } }
|
|
18
18
|
],
|
|
19
19
|
"solution": [
|
|
20
20
|
{ "tool": "measure_region", "args": { "x": 12, "y": 52, "width": 16, "height": 16 } },
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"shapes": [{ "shape": "rect", "x": 40, "y": 25, "width": 40, "height": 40, "color": [30, 90, 160] }]
|
|
9
9
|
},
|
|
10
10
|
"checks": [
|
|
11
|
-
{ "why": "the product is on its own layer, cut to its shape", "tool": "list_layers", "expect": { "layers": { "$some": { "type": "pixel", "bounds": { "x": { "$min": 39, "$max": 41 }, "y": { "$min": 24, "$max": 26 }, "width": { "$min": 39, "$max": 42 }, "height": { "$min": 39, "$max": 42 } } } } } },
|
|
11
|
+
{ "why": "the product is on its own layer, cut to its shape: by its pixels, or by its mask (masked, not erased)", "tool": "list_layers", "expect": { "layers": { "$some": { "type": "pixel", "$in": [{ "bounds": { "x": { "$min": 39, "$max": 41 }, "y": { "$min": 24, "$max": 26 }, "width": { "$min": 39, "$max": 42 }, "height": { "$min": 39, "$max": 42 } } }, { "mask": { "paintedBounds": { "x": { "$min": 39, "$max": 41 }, "y": { "$min": 24, "$max": 26 }, "width": { "$min": 39, "$max": 42 }, "height": { "$min": 39, "$max": 42 } } } }] } } } },
|
|
12
12
|
{ "why": "a live drop shadow on that layer", "tool": "list_layers", "expect": { "layers": { "$some": { "effects": { "$expr": "v && JSON.stringify(v).includes('drop-shadow')" } } } } }
|
|
13
13
|
],
|
|
14
14
|
"solution": [
|
|
@@ -21,6 +21,14 @@ Errors, namespacing (`doc-1__find_text`) and `run_commands` batching are covered
|
|
|
21
21
|
`pixerate-agent-tools` skill. Chart type, axis and colour choices are covered by
|
|
22
22
|
`pixerate-chart`; the same spec fields apply to charts in a document.
|
|
23
23
|
|
|
24
|
+
## Workflow skills
|
|
25
|
+
|
|
26
|
+
For these jobs, load the workflow skill too: it has the method, the checks between steps and
|
|
27
|
+
the pitfalls, and uses the tools below.
|
|
28
|
+
|
|
29
|
+
- `pixerate-rich-text-report`: a title and heading hierarchy, lists, tables, charts and a consistency pass.
|
|
30
|
+
- `pixerate-rich-text-revise`: proofreading, renaming terms with exceptions, tightening, minimal edits.
|
|
31
|
+
|
|
24
32
|
## Working method
|
|
25
33
|
|
|
26
34
|
1. **Read.** `get_text` (`format: "markdown"` shows headings, lists and tables compactly;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixerate-rich-text-report
|
|
3
|
+
description: The report and structured document workflow in the Pixerate rich text editor - outlining before writing, one title and a heading hierarchy, consistent heading case, short paragraphs, lists for steps and items, tables for comparisons, charts in the document, and a final read-through for structure and consistency. Use when asked to write, structure, format, outline or tidy a report, memo, proposal, brief, article, documentation page or meeting notes, add headings, lists or a table, or make a document consistent, or when get_text, set_block_type, edit_table or insert_chart are available. Load with pixerate-rich-text, which lists every tool.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
reference: pixerate-rich-text
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Structuring a report
|
|
10
|
+
|
|
11
|
+
A report is read by skimming first: the title, the headings and the first lines decide whether
|
|
12
|
+
anyone reads the rest. So the structure carries the message: one title, sections with headings
|
|
13
|
+
one level below, steps and items as lists, comparisons as tables, figures as charts. Get the
|
|
14
|
+
structure right, then the words, then check consistency.
|
|
15
|
+
|
|
16
|
+
This skill is the method. `pixerate-rich-text` has the full tool reference; positions come from
|
|
17
|
+
`get_text` with `blocks: true` or from `find_text`, never from counting characters.
|
|
18
|
+
|
|
19
|
+
## Goal and quality bar
|
|
20
|
+
|
|
21
|
+
- One `heading` level 1 for the title; sections at level 2, subsections at level 3; no skipped
|
|
22
|
+
levels.
|
|
23
|
+
- Headings consistent in case (sentence case unless the house style says otherwise) and short.
|
|
24
|
+
- Steps as an ordered list, items as a bulleted list; comparisons with more than two attributes
|
|
25
|
+
as a table with a header row; numbers that show a trend as a chart.
|
|
26
|
+
- Short paragraphs, each with one point; the summary first.
|
|
27
|
+
- Nothing the author wrote is lost unless they asked for it to go.
|
|
28
|
+
|
|
29
|
+
## Inputs to confirm
|
|
30
|
+
|
|
31
|
+
- **Purpose and reader:** what decision or knowledge the document serves.
|
|
32
|
+
- **Sections** the user expects, or a template.
|
|
33
|
+
- **House style:** heading case, numbering, how dates and numbers are written.
|
|
34
|
+
|
|
35
|
+
## Working method
|
|
36
|
+
|
|
37
|
+
1. **Read.** `get_text` with `blocks: true`: every block's `type`, `from`, `to` and `text`.
|
|
38
|
+
**Check:** you can name the title, the sections and the body of each.
|
|
39
|
+
2. **Outline.** Decide the heading hierarchy and which runs of paragraphs are really lists or
|
|
40
|
+
tables before changing anything.
|
|
41
|
+
3. **Set the structure** with `set_block_type` on each block's range: `heading` with `level`,
|
|
42
|
+
`"bullet_list"`, `"ordered_list"`. Work from the blocks you read; positions shift when block types
|
|
43
|
+
change, so re-read (`get_text` `blocks`) after changes that add or remove wrapping.
|
|
44
|
+
**Check:** `get_text` `format: "html"` shows `<h1>`, `<h2>`, `<ul>` where you meant.
|
|
45
|
+
4. **Tables.** `edit_table` `insertTable` (`at` the end of the paragraph it follows, `rows`,
|
|
46
|
+
`cols`, `withHeaderRow`), then `insert_text` into each cell from the last cell to the first so
|
|
47
|
+
earlier positions stay valid (cell positions from `get_text` `blocks`).
|
|
48
|
+
**Check:** the HTML has the header cells and rows in order.
|
|
49
|
+
5. **Charts** for figures: `insert_chart` with the data; edit with `update_chart_in_document`.
|
|
50
|
+
6. **Consistency pass.** Heading case, terms, numbers and dates written one way:
|
|
51
|
+
`find_text` to find variants, `replace_text` to fix them (see
|
|
52
|
+
`pixerate-rich-text-revise`).
|
|
53
|
+
**Check:** `find_text` for the old variants returns no matches.
|
|
54
|
+
7. **Read it through** once as the reader would (`get_text`), and report what changed.
|
|
55
|
+
|
|
56
|
+
## Decision table
|
|
57
|
+
|
|
58
|
+
| Content | Block |
|
|
59
|
+
| --- | --- |
|
|
60
|
+
| Document title | `heading` level 1 (once) |
|
|
61
|
+
| Section, subsection | `heading` level 2, 3 |
|
|
62
|
+
| Steps in order | `"ordered_list"` |
|
|
63
|
+
| Items, options, takeaways | `"bullet_list"` |
|
|
64
|
+
| Things compared on several attributes | A table with a header row |
|
|
65
|
+
| A trend or comparison of numbers | `insert_chart` |
|
|
66
|
+
| A quotation | `blockquote` |
|
|
67
|
+
| Code or commands | `"code_block"` |
|
|
68
|
+
|
|
69
|
+
## Recipes
|
|
70
|
+
|
|
71
|
+
**Structure a draft.** `get_text` `blocks` → `set_block_type` title `heading` level 1 → each
|
|
72
|
+
section line `heading` level 2 → each run of item lines `"bullet_list"` (one call over the run's
|
|
73
|
+
range).
|
|
74
|
+
|
|
75
|
+
**A two-column table.** `edit_table` `{ operation: "insertTable", at, rows: 3, cols: 2,
|
|
76
|
+
withHeaderRow: true }` → `get_text` `blocks` for the empty cells → `insert_text` into each cell,
|
|
77
|
+
last first.
|
|
78
|
+
|
|
79
|
+
## Pitfalls
|
|
80
|
+
|
|
81
|
+
- **Positions from the plain text** are wrong: block boundaries count. Use `blocks` or
|
|
82
|
+
`find_text`.
|
|
83
|
+
- **Stale positions** after a change that adds a list or table; re-read before the next edit.
|
|
84
|
+
- **Several level-1 headings** flatten the outline; one title only.
|
|
85
|
+
- **Bold paragraphs as headings** do not appear in the outline or navigation; use headings.
|
|
86
|
+
- **Tables for prose** or one-column tables; use paragraphs or lists.
|
|
87
|
+
- **Rewriting the author's words** while restructuring; change structure, not content, unless
|
|
88
|
+
asked.
|
|
89
|
+
|
|
90
|
+
## Tools used
|
|
91
|
+
|
|
92
|
+
- `get_text`, `find_text`: read the document, its blocks and positions
|
|
93
|
+
- `set_block_type`, `set_text_align`: headings, lists and alignment
|
|
94
|
+
- `format_text`: emphasis and links
|
|
95
|
+
- `edit_table`: insert and shape tables
|
|
96
|
+
- `insert_text`, `replace_range`, `replace_text`: fill cells, write and fix text
|
|
97
|
+
- `insert_chart`, `update_chart_in_document`, `list_document_charts`: charts in the document
|
|
98
|
+
- `undo_rich_text`: take back a step
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "The section headings are inconsistent. Make them all sentence case (first word capitalised, the rest lower case unless they are names).",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "rich-text",
|
|
5
|
+
"html": "<h1>Annual review</h1><h2>RESULTS AND Findings</h2><p>Revenue grew.</p><h2>Next Steps For Acme</h2><p>Plan the launch.</p>"
|
|
6
|
+
},
|
|
7
|
+
"checks": [
|
|
8
|
+
{
|
|
9
|
+
"why": "headings in sentence case, keeping the name Acme",
|
|
10
|
+
"tool": "get_text",
|
|
11
|
+
"args": {
|
|
12
|
+
"format": "html"
|
|
13
|
+
},
|
|
14
|
+
"expect": {
|
|
15
|
+
"content": {
|
|
16
|
+
"$expr": "/<h2[^>]*>Results and findings<\\/h2>/.test(v) && /<h2[^>]*>Next steps for Acme<\\/h2>/.test(v)"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"why": "the body and title are unchanged",
|
|
22
|
+
"tool": "get_text",
|
|
23
|
+
"expect": {
|
|
24
|
+
"content": {
|
|
25
|
+
"$expr": "v.startsWith('Annual review') && v.includes('Revenue grew.') && v.includes('Plan the launch.')"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"solution": [
|
|
31
|
+
{
|
|
32
|
+
"tool": "replace_text",
|
|
33
|
+
"args": {
|
|
34
|
+
"find": "RESULTS AND Findings",
|
|
35
|
+
"replace": "Results and findings",
|
|
36
|
+
"matchCase": true
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"tool": "replace_text",
|
|
41
|
+
"args": {
|
|
42
|
+
"find": "Next Steps For Acme",
|
|
43
|
+
"replace": "Next steps for Acme",
|
|
44
|
+
"matchCase": true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Under 'Sales by region:', add a table with a header row (Region, Sales) and two rows: North 120 and South 95.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "rich-text",
|
|
5
|
+
"html": "<h2>Results</h2><p>Sales by region:</p><h2>Next steps</h2>"
|
|
6
|
+
},
|
|
7
|
+
"checks": [
|
|
8
|
+
{
|
|
9
|
+
"why": "a table with a header row and the two regions",
|
|
10
|
+
"tool": "get_text",
|
|
11
|
+
"args": {
|
|
12
|
+
"format": "html"
|
|
13
|
+
},
|
|
14
|
+
"expect": {
|
|
15
|
+
"content": {
|
|
16
|
+
"$match": "<table[^>]*>.*<th[^>]*><p>Region</p></th><th[^>]*><p>Sales</p></th>.*<td[^>]*><p>North</p></td><td[^>]*><p>120</p></td>.*<td[^>]*><p>South</p></td><td[^>]*><p>95</p></td>.*</table>"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"why": "placed after 'Sales by region:' and before the next section",
|
|
22
|
+
"tool": "get_text",
|
|
23
|
+
"args": {
|
|
24
|
+
"format": "html"
|
|
25
|
+
},
|
|
26
|
+
"expect": {
|
|
27
|
+
"content": {
|
|
28
|
+
"$match": "Sales by region:</p><table.*</table><h2[^>]*>Next steps"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"solution": [
|
|
34
|
+
{
|
|
35
|
+
"tool": "get_text",
|
|
36
|
+
"args": {
|
|
37
|
+
"blocks": true
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"tool": "edit_table",
|
|
42
|
+
"args": {
|
|
43
|
+
"operation": "insertTable",
|
|
44
|
+
"at": 26,
|
|
45
|
+
"rows": 3,
|
|
46
|
+
"cols": 2,
|
|
47
|
+
"withHeaderRow": true
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"tool": "insert_text",
|
|
52
|
+
"args": {
|
|
53
|
+
"text": "95",
|
|
54
|
+
"at": 55
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"tool": "insert_text",
|
|
59
|
+
"args": {
|
|
60
|
+
"text": "South",
|
|
61
|
+
"at": 51
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"tool": "insert_text",
|
|
66
|
+
"args": {
|
|
67
|
+
"text": "120",
|
|
68
|
+
"at": 45
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"tool": "insert_text",
|
|
73
|
+
"args": {
|
|
74
|
+
"text": "North",
|
|
75
|
+
"at": 41
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"tool": "insert_text",
|
|
80
|
+
"args": {
|
|
81
|
+
"text": "Sales",
|
|
82
|
+
"at": 35
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"tool": "insert_text",
|
|
87
|
+
"args": {
|
|
88
|
+
"text": "Region",
|
|
89
|
+
"at": 31
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Turn this into a properly structured report: the first line is the title, 'Summary', 'Results' and 'Next steps' are section headings, and the next steps should be a bulleted list.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "rich-text",
|
|
5
|
+
"html": "<p>Quarterly report</p><p>Summary</p><p>Sales grew in every region.</p><p>Results</p><p>North led with 120 orders.</p><p>Next steps</p><p>Hire two engineers</p><p>Launch in May</p>"
|
|
6
|
+
},
|
|
7
|
+
"checks": [
|
|
8
|
+
{
|
|
9
|
+
"why": "the title is the top heading",
|
|
10
|
+
"tool": "get_text",
|
|
11
|
+
"args": {
|
|
12
|
+
"format": "html"
|
|
13
|
+
},
|
|
14
|
+
"expect": {
|
|
15
|
+
"content": {
|
|
16
|
+
"$match": "^<h1[^>]*>Quarterly report</h1>"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"why": "the three sections are headings one level below",
|
|
22
|
+
"tool": "get_text",
|
|
23
|
+
"args": {
|
|
24
|
+
"format": "html"
|
|
25
|
+
},
|
|
26
|
+
"expect": {
|
|
27
|
+
"content": {
|
|
28
|
+
"$expr": "['Summary', 'Results', 'Next steps'].every((t) => new RegExp('<h2[^>]*>' + t + '</h2>').test(v))"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"why": "the next steps are a bulleted list",
|
|
34
|
+
"tool": "get_text",
|
|
35
|
+
"args": {
|
|
36
|
+
"format": "html"
|
|
37
|
+
},
|
|
38
|
+
"expect": {
|
|
39
|
+
"content": {
|
|
40
|
+
"$match": "<ul[^>]*><li[^>]*><p>Hire two engineers</p></li><li[^>]*><p>Launch in May</p></li></ul>"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"why": "the body text is kept",
|
|
46
|
+
"tool": "get_text",
|
|
47
|
+
"expect": {
|
|
48
|
+
"content": {
|
|
49
|
+
"$expr": "v.includes('Sales grew in every region.') && v.includes('North led with 120 orders.')"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"solution": [
|
|
55
|
+
{
|
|
56
|
+
"tool": "get_text",
|
|
57
|
+
"args": {
|
|
58
|
+
"blocks": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"tool": "set_block_type",
|
|
63
|
+
"args": {
|
|
64
|
+
"from": 1,
|
|
65
|
+
"to": 17,
|
|
66
|
+
"type": "heading",
|
|
67
|
+
"level": 1
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"tool": "set_block_type",
|
|
72
|
+
"args": {
|
|
73
|
+
"from": 19,
|
|
74
|
+
"to": 26,
|
|
75
|
+
"type": "heading",
|
|
76
|
+
"level": 2
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"tool": "set_block_type",
|
|
81
|
+
"args": {
|
|
82
|
+
"from": 56,
|
|
83
|
+
"to": 63,
|
|
84
|
+
"type": "heading",
|
|
85
|
+
"level": 2
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"tool": "set_block_type",
|
|
90
|
+
"args": {
|
|
91
|
+
"from": 93,
|
|
92
|
+
"to": 103,
|
|
93
|
+
"type": "heading",
|
|
94
|
+
"level": 2
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"tool": "set_block_type",
|
|
99
|
+
"args": {
|
|
100
|
+
"from": 105,
|
|
101
|
+
"to": 134,
|
|
102
|
+
"type": "bullet_list"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixerate-rich-text-revise
|
|
3
|
+
description: The revision workflow in the Pixerate rich text editor - proofreading for spelling and grammar, renaming a term consistently while leaving quotations and names alone, tightening wordy passages, unifying how numbers, dates and terms are written, and making minimal, targeted edits that keep the author's formatting and voice, with a check that nothing else changed. Use when asked to proofread, copy-edit, revise, tighten, shorten, fix typos, rename or replace a term throughout, make wording consistent or polish a document, or when find_text, replace_text and replace_range are available. Load with pixerate-rich-text, which lists every tool.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
reference: pixerate-rich-text
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Revising a document
|
|
10
|
+
|
|
11
|
+
Revision changes as little as possible to make the document right: each fix is a targeted
|
|
12
|
+
replacement of the words that are wrong, so formatting, links and the author's voice survive.
|
|
13
|
+
Find before replacing, decide which matches should change (a quotation, a name or a published
|
|
14
|
+
title often should not), and check afterwards that only what you meant changed.
|
|
15
|
+
|
|
16
|
+
This skill is the method. `pixerate-rich-text` has the full tool reference.
|
|
17
|
+
|
|
18
|
+
## Goal and quality bar
|
|
19
|
+
|
|
20
|
+
- Every error the user asked about is fixed (`find_text` for it returns no matches).
|
|
21
|
+
- Only the intended text changed: the rest of the document reads exactly as before.
|
|
22
|
+
- Replacements respect case (`Teh` becomes `The`), whole words (`teh` but not `tehran`) and
|
|
23
|
+
exceptions (quotations, names, titles of published works).
|
|
24
|
+
- Tightened passages keep their point and the author's voice; nothing is added that was not
|
|
25
|
+
there.
|
|
26
|
+
- Formatting (bold, links, headings, lists) is untouched by text fixes.
|
|
27
|
+
|
|
28
|
+
## Inputs to confirm
|
|
29
|
+
|
|
30
|
+
- **Scope:** spelling only, grammar and style, or a rewrite of named passages.
|
|
31
|
+
- **Exceptions:** text that must stay as written (quotes, legal text, product names, titles).
|
|
32
|
+
- **House style:** spelling variant (UK or US), how numbers and dates are written.
|
|
33
|
+
|
|
34
|
+
## Working method
|
|
35
|
+
|
|
36
|
+
1. **Read.** `get_text` (with `blocks: true` for positions).
|
|
37
|
+
**Check:** you have a list of fixes with the exact wrong text and the right text.
|
|
38
|
+
2. **Find before replacing.** `find_text` for each term (`wholeWord`, `matchCase`, or `regex`
|
|
39
|
+
for families of errors); read the matches in context and decide which change.
|
|
40
|
+
**Check:** the match count is what you expect; note the occurrences to leave alone.
|
|
41
|
+
3. **Replace in one call per fix.** `replace_text` with `find`, `replace`, `wholeWord: true`;
|
|
42
|
+
`matchCase: true` with one call per capitalisation (`teh` and `Teh`); `occurrence` for only
|
|
43
|
+
some matches, working from the last occurrence to the first so the numbering holds.
|
|
44
|
+
**Check:** `find_text` for the wrong text returns no matches (except the exceptions).
|
|
45
|
+
4. **Rewrite a passage** with `replace_range` over exactly its range (`from` / `to` of the block
|
|
46
|
+
or a `find_text` match), keeping the surrounding text.
|
|
47
|
+
**Check:** `get_text` `blocks`: the other blocks' text is unchanged.
|
|
48
|
+
5. **Consistency.** Terms, numbers and dates one way: `find_text` with a `regex` for the
|
|
49
|
+
variants, then `replace_text`.
|
|
50
|
+
6. **Report** the fixes made, the matches you left and why.
|
|
51
|
+
|
|
52
|
+
## Decision table
|
|
53
|
+
|
|
54
|
+
| Fix | Tool and settings |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| A misspelling everywhere | `replace_text`, `wholeWord: true`, one call per capitalisation with `matchCase` |
|
|
57
|
+
| Rename a term, with exceptions | `find_text`, then `replace_text` with `occurrence` per change, last first |
|
|
58
|
+
| A family of variants (e-mail, email, E-mail) | `find_text` / `replace_text` with `regex: true` |
|
|
59
|
+
| Rewrite a sentence or paragraph | `replace_range` over its exact range |
|
|
60
|
+
| Insert a missing word | `insert_text` at the position from `find_text` |
|
|
61
|
+
| Formatting only | `format_text` on the range; leave the words |
|
|
62
|
+
|
|
63
|
+
## Recipes
|
|
64
|
+
|
|
65
|
+
**Typos.** `replace_text` `{ find: "recieve", replace: "receive", wholeWord: true }`; for a word
|
|
66
|
+
that starts sentences, `{ find: "Teh", replace: "The", matchCase: true, wholeWord: true }` and
|
|
67
|
+
the same in lower case.
|
|
68
|
+
|
|
69
|
+
**Rename except a quotation.** `find_text` "Acme Cloud" lists three matches; the second is in a
|
|
70
|
+
quoted title: `replace_text` with `occurrence: 3`, then `occurrence: 1`.
|
|
71
|
+
|
|
72
|
+
**Tighten the intro.** `get_text` `blocks` → `replace_range` `{ from: blocks[0].from, to:
|
|
73
|
+
blocks[0].to, text }` with one sentence.
|
|
74
|
+
|
|
75
|
+
## Pitfalls
|
|
76
|
+
|
|
77
|
+
- **Case-insensitive replace** turns `Teh` into `the` at the start of a sentence; match case.
|
|
78
|
+
- **Partial words**: without `wholeWord`, fixing `teh` breaks words containing it.
|
|
79
|
+
- **Changing quotations, names or published titles** that must stay as written.
|
|
80
|
+
- **`occurrence` after an earlier change** counts the remaining matches; replace from the last
|
|
81
|
+
to the first.
|
|
82
|
+
- **Rewriting whole paragraphs** to fix one word loses formatting and links; replace only the
|
|
83
|
+
words.
|
|
84
|
+
- **Adding content** while tightening; keep the author's point and facts.
|
|
85
|
+
|
|
86
|
+
## Tools used
|
|
87
|
+
|
|
88
|
+
- `get_text`, `find_text`: read the text, blocks, positions and matches
|
|
89
|
+
- `replace_text`: targeted replacements, with case, whole-word, regex and occurrence
|
|
90
|
+
- `replace_range`, `insert_text`: rewrite or insert at exact positions
|
|
91
|
+
- `format_text`: formatting fixes without touching words
|
|
92
|
+
- `undo_rich_text`: take back a step
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Fix the spelling mistakes in this document without changing anything else.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "rich-text",
|
|
5
|
+
"html": "<p>We will recieve the order tomorrow. Teh team is ready.</p><p>Please recieve the parcel and check teh contents.</p>"
|
|
6
|
+
},
|
|
7
|
+
"checks": [
|
|
8
|
+
{
|
|
9
|
+
"why": "no misspellings left",
|
|
10
|
+
"tool": "find_text",
|
|
11
|
+
"args": {
|
|
12
|
+
"query": "\\b(recieve|teh)\\b",
|
|
13
|
+
"regex": true
|
|
14
|
+
},
|
|
15
|
+
"expect": {
|
|
16
|
+
"matches": {
|
|
17
|
+
"$length": 0
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"why": "the text is otherwise unchanged, capitals kept",
|
|
23
|
+
"tool": "get_text",
|
|
24
|
+
"expect": {
|
|
25
|
+
"content": "We will receive the order tomorrow. The team is ready.\nPlease receive the parcel and check the contents."
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"solution": [
|
|
30
|
+
{
|
|
31
|
+
"tool": "replace_text",
|
|
32
|
+
"args": {
|
|
33
|
+
"find": "recieve",
|
|
34
|
+
"replace": "receive",
|
|
35
|
+
"wholeWord": true
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"tool": "replace_text",
|
|
40
|
+
"args": {
|
|
41
|
+
"find": "Teh",
|
|
42
|
+
"replace": "The",
|
|
43
|
+
"matchCase": true,
|
|
44
|
+
"wholeWord": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"tool": "replace_text",
|
|
49
|
+
"args": {
|
|
50
|
+
"find": "teh",
|
|
51
|
+
"replace": "the",
|
|
52
|
+
"matchCase": true,
|
|
53
|
+
"wholeWord": true
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "We've renamed the product from 'Acme Cloud' to 'Acme Platform'. Update the document, but leave the title of the 2019 press release (in quotes) as it was published.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "rich-text",
|
|
5
|
+
"html": "<p>Acme Cloud now supports teams.</p><p>Our 2019 press release, \u201cIntroducing Acme Cloud\u201d, launched the product.</p><p>Try Acme Cloud today.</p>"
|
|
6
|
+
},
|
|
7
|
+
"checks": [
|
|
8
|
+
{
|
|
9
|
+
"why": "renamed in the running text",
|
|
10
|
+
"tool": "get_text",
|
|
11
|
+
"expect": {
|
|
12
|
+
"content": {
|
|
13
|
+
"$expr": "v.startsWith('Acme Platform now supports teams.') && v.endsWith('Try Acme Platform today.')"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"why": "the published title is unchanged",
|
|
19
|
+
"tool": "get_text",
|
|
20
|
+
"expect": {
|
|
21
|
+
"content": {
|
|
22
|
+
"$match": "\u201cIntroducing Acme Cloud\u201d"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"solution": [
|
|
28
|
+
{
|
|
29
|
+
"tool": "find_text",
|
|
30
|
+
"args": {
|
|
31
|
+
"query": "Acme Cloud"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"tool": "replace_text",
|
|
36
|
+
"args": {
|
|
37
|
+
"find": "Acme Cloud",
|
|
38
|
+
"replace": "Acme Platform",
|
|
39
|
+
"occurrence": 3
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"tool": "replace_text",
|
|
44
|
+
"args": {
|
|
45
|
+
"find": "Acme Cloud",
|
|
46
|
+
"replace": "Acme Platform",
|
|
47
|
+
"occurrence": 1
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "The introduction (the first paragraph) rambles. Cut it down to one clear sentence that keeps its point, and don't touch the rest.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "rich-text",
|
|
5
|
+
"html": "<p>This report, which we have put together over the last few weeks, looks at our sales. It covers every region. It is meant to help us plan next year, which is important.</p><p>North led with 120 orders.</p><p>South followed with 95.</p>"
|
|
6
|
+
},
|
|
7
|
+
"checks": [
|
|
8
|
+
{
|
|
9
|
+
"why": "the introduction is one sentence about sales and planning",
|
|
10
|
+
"tool": "get_text",
|
|
11
|
+
"args": {
|
|
12
|
+
"blocks": true
|
|
13
|
+
},
|
|
14
|
+
"expect": {
|
|
15
|
+
"blocks": {
|
|
16
|
+
"$expr": "(() => { const t = v[0].text.trim(); return (t.match(/[.!?](\\s|$)/g) || []).length === 1 && t.length < 120 && /sales/i.test(t) && /plan/i.test(t); })()"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"why": "the rest is unchanged",
|
|
22
|
+
"tool": "get_text",
|
|
23
|
+
"args": {
|
|
24
|
+
"blocks": true
|
|
25
|
+
},
|
|
26
|
+
"expect": {
|
|
27
|
+
"blocks": {
|
|
28
|
+
"$expr": "v.length === 3 && v[1].text === 'North led with 120 orders.' && v[2].text === 'South followed with 95.'"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"solution": [
|
|
34
|
+
{
|
|
35
|
+
"tool": "get_text",
|
|
36
|
+
"args": {
|
|
37
|
+
"blocks": true
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"tool": "replace_range",
|
|
42
|
+
"args": {
|
|
43
|
+
"from": 1,
|
|
44
|
+
"to": {
|
|
45
|
+
"$read": "get_text",
|
|
46
|
+
"args": {
|
|
47
|
+
"blocks": true
|
|
48
|
+
},
|
|
49
|
+
"path": "blocks.0.to"
|
|
50
|
+
},
|
|
51
|
+
"text": "This report reviews sales in every region to help us plan next year."
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|