@superdoc/sdk 2.10.0-next.7 → 2.10.0-next.9
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/README.md +45 -0
- package/dist/action-primitives/doc-index.cjs +6 -4
- package/dist/action-primitives/doc-index.js +6 -4
- package/dist/action-primitives/engine.cjs +6 -2
- package/dist/action-primitives/engine.js +6 -2
- package/dist/action-primitives/receipt.d.ts +4 -0
- package/dist/action-primitives/tools/structure-insert.d.ts +1 -1
- package/dist/agent/actions.cjs +203 -223
- package/dist/agent/actions.d.ts +5 -0
- package/dist/agent/actions.js +203 -223
- package/dist/agent/catalog.cjs +15 -0
- package/dist/agent/catalog.js +15 -0
- package/dist/agent/doc-snapshot.cjs +22 -46
- package/dist/agent/doc-snapshot.js +22 -46
- package/dist/agent/execution-context.cjs +385 -0
- package/dist/agent/execution-context.d.ts +97 -0
- package/dist/agent/execution-context.js +376 -0
- package/dist/agent/runtime.cjs +116 -158
- package/dist/agent/runtime.d.ts +3 -0
- package/dist/agent/runtime.js +117 -159
- package/dist/agent/v2-preset-compat.cjs +5 -1
- package/dist/agent/v2-preset-compat.js +4 -1
- package/dist/embedded-tools.generated.cjs +5 -5
- package/dist/embedded-tools.generated.js +5 -5
- package/dist/generated/client.cjs +2 -0
- package/dist/generated/client.d.ts +47 -0
- package/dist/generated/client.js +2 -0
- package/dist/generated/contract.cjs +1605 -1297
- package/dist/generated/contract.js +1605 -1297
- package/dist/index.cjs +11 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +11 -0
- package/dist/presets/core.cjs +1 -1
- package/dist/presets/core.js +1 -1
- package/dist/runtime/document-evidence.cjs +40 -0
- package/dist/runtime/document-evidence.d.ts +13 -0
- package/dist/runtime/document-evidence.js +30 -0
- package/dist/runtime/host.cjs +30 -2
- package/dist/runtime/host.d.ts +2 -0
- package/dist/runtime/host.js +30 -2
- package/dist/runtime/process.cjs +6 -0
- package/dist/runtime/process.d.ts +2 -0
- package/dist/runtime/process.js +6 -0
- package/dist/runtime/sdk-version.generated.cjs +1 -1
- package/dist/runtime/sdk-version.generated.d.ts +1 -1
- package/dist/runtime/sdk-version.generated.js +1 -1
- package/package.json +10 -9
- package/tools/catalog.json +35 -0
- package/tools/tools-policy.json +1 -1
- package/tools/tools.anthropic.json +35 -0
- package/tools/tools.generic.json +35 -0
- package/tools/tools.openai.json +35 -0
- package/tools/tools.vercel.json +35 -0
package/dist/agent/actions.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var executionContext = require('./execution-context.cjs');
|
|
3
4
|
var errors = require('../runtime/errors.cjs');
|
|
4
5
|
var listTransform = require('../action-primitives/tools/list-transform.cjs');
|
|
5
6
|
var structureInsert = require('../action-primitives/tools/structure-insert.cjs');
|
|
@@ -170,18 +171,18 @@ const ACTION_GROUPS = [
|
|
|
170
171
|
* action at compile time.
|
|
171
172
|
*/
|
|
172
173
|
const ACTION_ARGS = {
|
|
173
|
-
insert_paragraphs: ['text', 'texts', 'headingLevel', 'placement', 'changeMode'],
|
|
174
|
+
insert_paragraphs: ['text', 'texts', 'headingLevel', 'placement', 'changeMode', 'evidence'],
|
|
174
175
|
insert_heading: ['text', 'level', 'placement', 'changeMode'],
|
|
175
176
|
replace_text: ['edits', 'selector', 'caseSensitive', 'changeMode'],
|
|
176
177
|
delete_text: ['finds', 'selector', 'caseSensitive', 'changeMode'],
|
|
177
178
|
delete_blocks: ['selectors', 'selector', 'changeMode'],
|
|
178
179
|
append_list: ['items', 'kind', 'headingText', 'headingLevel', 'placement', 'changeMode'],
|
|
179
|
-
create_table: ['rows', 'columns', 'cellTexts', 'placement', 'changeMode'],
|
|
180
|
+
create_table: ['rows', 'columns', 'cellTexts', 'placement', 'changeMode', 'evidence'],
|
|
180
181
|
comment_paragraphs: ['commentText', 'scope', 'excludeBlockQuotes'],
|
|
181
182
|
add_comments: ['commentText', 'selector', 'selectors'],
|
|
182
183
|
resolve_comments: ['anchorText', 'reopen'],
|
|
183
184
|
reply_to_comment: ['commentText', 'anchorText', 'commentId'],
|
|
184
|
-
rewrite_block: ['text', 'selector', 'changeMode'],
|
|
185
|
+
rewrite_block: ['text', 'selector', 'changeMode', 'evidence'],
|
|
185
186
|
accept_tracked_changes: ['author', 'changeType'],
|
|
186
187
|
reject_tracked_changes: ['author', 'changeType'],
|
|
187
188
|
normalize_body_font_size: ['fontSize', 'changeMode'],
|
|
@@ -216,7 +217,7 @@ const ACTION_ARGS = {
|
|
|
216
217
|
'changeMode',
|
|
217
218
|
],
|
|
218
219
|
apply_style: ['selector', 'styleId', 'headingLevel', 'likeText'],
|
|
219
|
-
format_paragraph: ['selector', 'alignment', 'changeMode'],
|
|
220
|
+
format_paragraph: ['selector', 'alignment', 'changeMode', 'evidence'],
|
|
220
221
|
move_text: ['text', 'afterText', 'changeMode'],
|
|
221
222
|
style_table: ['tableOrdinal', 'accentColor'],
|
|
222
223
|
move_table: ['tableOrdinal', 'placement'],
|
|
@@ -319,10 +320,6 @@ function findSnapshotTextByNodeId(snapshot, nodeId) {
|
|
|
319
320
|
}
|
|
320
321
|
return null;
|
|
321
322
|
}
|
|
322
|
-
function lastBlock(snapshot) {
|
|
323
|
-
const block = snapshot.blocks[snapshot.blocks.length - 1];
|
|
324
|
-
return block ? { nodeId: block.nodeId, nodeType: block.nodeType } : null;
|
|
325
|
-
}
|
|
326
323
|
function createdBlockTarget(result) {
|
|
327
324
|
const rec = asRecord(result);
|
|
328
325
|
const paragraph = asRecord(rec?.paragraph);
|
|
@@ -860,7 +857,7 @@ forceDirectFill = false) {
|
|
|
860
857
|
});
|
|
861
858
|
}
|
|
862
859
|
const extracted = asRecord(await extractFn({}));
|
|
863
|
-
const blocks = (Array.isArray(extracted?.blocks) ? extracted
|
|
860
|
+
const blocks = (Array.isArray(extracted?.blocks) ? extracted.blocks : [])
|
|
864
861
|
.map((block) => asRecord(block))
|
|
865
862
|
.filter((block) => block != null)
|
|
866
863
|
.flatMap((block) => {
|
|
@@ -1049,95 +1046,68 @@ async function styleTableCells(doc, cells, changeMode) {
|
|
|
1049
1046
|
await applyItemStyling(doc, nodeIds, specs, changeMode);
|
|
1050
1047
|
return styled.length;
|
|
1051
1048
|
}
|
|
1052
|
-
async function runInsertParagraphs(doc, args) {
|
|
1053
|
-
const
|
|
1054
|
-
? await docSnapshot.buildMutationSnapshot(doc, { includeDomains: ['blocks'] })
|
|
1055
|
-
: await docSnapshot.buildDocumentSnapshot(doc, { includeDomains: ['blocks'] });
|
|
1049
|
+
async function runInsertParagraphs(doc, args, formatArgs) {
|
|
1050
|
+
const context = new executionContext.ExecutionContext(doc, { evidence: args.evidence, selectors: placementSelectors(args.placement) });
|
|
1056
1051
|
try {
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
const
|
|
1060
|
-
const
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
// For subsequent items: append after the previously inserted block by
|
|
1068
|
-
// using `documentEnd` (the SDK keeps blocks contiguous) so order is
|
|
1069
|
-
// preserved.
|
|
1052
|
+
const pre = await context.start();
|
|
1053
|
+
const placement = await resolveFactPlacement(args.placement, pre);
|
|
1054
|
+
const isNewDocument = (await pre.count()) <= 1;
|
|
1055
|
+
const anchor = placement.kind === 'before' || placement.kind === 'after'
|
|
1056
|
+
? await pre.block(placement.target.nodeId)
|
|
1057
|
+
: await pre.target({
|
|
1058
|
+
kind: 'placement',
|
|
1059
|
+
at: placement.kind === 'documentStart' ? 'document_start' : 'document_end',
|
|
1060
|
+
});
|
|
1061
|
+
const preRows = pre.complete ? await listBlockRows(doc) : anchor ? [anchor] : [];
|
|
1070
1062
|
let currentPlacement = placement;
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
return
|
|
1063
|
+
const nodeIds = [];
|
|
1064
|
+
const specs = [];
|
|
1065
|
+
const advance = async (result) => {
|
|
1066
|
+
const target = createdBlockTarget(result);
|
|
1067
|
+
if (target) {
|
|
1068
|
+
currentPlacement = {
|
|
1069
|
+
kind: 'after',
|
|
1070
|
+
target: { kind: 'block', nodeType: target.nodeType, nodeId: target.nodeId },
|
|
1071
|
+
};
|
|
1072
|
+
return target.nodeId;
|
|
1081
1073
|
}
|
|
1082
|
-
const
|
|
1083
|
-
const last =
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1074
|
+
const current = await context.finishRevision();
|
|
1075
|
+
const last = await current.target({ kind: 'placement', at: 'document_end' });
|
|
1076
|
+
if (!last)
|
|
1077
|
+
throw new Error('Created paragraph identity is unavailable.');
|
|
1078
|
+
currentPlacement = { kind: 'after', target: { kind: 'block', nodeType: last.nodeType, nodeId: last.nodeId } };
|
|
1079
|
+
return last.nodeId;
|
|
1087
1080
|
};
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
currentPlacement = await advanceAfter(result);
|
|
1111
|
-
// New-document drafts get a blank paragraph after each item for spacing;
|
|
1112
|
-
// inserts into an existing document do not (would scatter blank lines).
|
|
1113
|
-
if (isNewDocument) {
|
|
1114
|
-
const spacer = await executeCreateParagraph(doc, '', currentPlacement, args.changeMode);
|
|
1115
|
-
executedOperations.push({ operationId: 'doc.create.paragraph', result: spacer, rationale: 'spacing' });
|
|
1116
|
-
currentPlacement = await advanceAfter(spacer);
|
|
1081
|
+
const texts = args.texts ?? (args.text ? [args.text] : []);
|
|
1082
|
+
for (let i = 0; i < texts.length; i++) {
|
|
1083
|
+
const result = i === 0 && args.headingLevel
|
|
1084
|
+
? await executeCreateHeading(context.document, texts[i], args.headingLevel, currentPlacement, args.changeMode)
|
|
1085
|
+
: await executeCreateParagraph(context.document, texts[i], currentPlacement, args.changeMode);
|
|
1086
|
+
const id = await advance(result);
|
|
1087
|
+
nodeIds.push(id);
|
|
1088
|
+
specs.push({ ...args.textSpecs?.[i], text: texts[i] });
|
|
1089
|
+
if (isNewDocument)
|
|
1090
|
+
await advance(await executeCreateParagraph(context.document, '', currentPlacement, args.changeMode));
|
|
1091
|
+
}
|
|
1092
|
+
if (specs.some((spec) => spec.runs?.length || spec.marks))
|
|
1093
|
+
await applyItemStyling(context.document, nodeIds, specs, args.changeMode);
|
|
1094
|
+
let post = await context.finishRevision();
|
|
1095
|
+
let formatted;
|
|
1096
|
+
if (formatArgs) {
|
|
1097
|
+
let localRows;
|
|
1098
|
+
if (!pre.complete) {
|
|
1099
|
+
const created = await post.page({ nodeIds, limit: Math.max(nodeIds.length, 1) });
|
|
1100
|
+
localRows = [...(anchor ? [anchor] : []), ...created].sort((a, b) => a.ordinal - b.ordinal);
|
|
1117
1101
|
}
|
|
1102
|
+
const count = context.executedOperations.length;
|
|
1103
|
+
formatted = await matchInsertedBlockFormatting(context.document, preRows, context.receipt('insert_paragraphs', []), formatArgs, localRows);
|
|
1104
|
+
if (context.executedOperations.length !== count)
|
|
1105
|
+
post = await context.finishRevision();
|
|
1118
1106
|
}
|
|
1119
|
-
|
|
1120
|
-
const styling = await applyItemStyling(doc, styledNodeIds, styledSpecs, args.changeMode);
|
|
1121
|
-
executedOperations.push({
|
|
1122
|
-
operationId: 'doc.format.apply',
|
|
1123
|
-
result: styling,
|
|
1124
|
-
rationale: `Styled ${styledNodeIds.length} inserted paragraph(s)`,
|
|
1125
|
-
});
|
|
1126
|
-
}
|
|
1127
|
-
const postIdentity = await readDocumentIdentity(doc);
|
|
1128
|
-
const verification = [revisionVerification(pre.revision, postIdentity.revision, true)];
|
|
1129
|
-
return {
|
|
1130
|
-
status: verification.every((v) => v.passed) ? 'ok' : 'failed',
|
|
1131
|
-
intent: 'insert_paragraphs',
|
|
1132
|
-
preSnapshot: { revision: pre.revision, counts: pre.counts },
|
|
1133
|
-
postSnapshot: postIdentity,
|
|
1134
|
-
selectedTargets: [],
|
|
1135
|
-
executedOperations,
|
|
1136
|
-
verification,
|
|
1137
|
-
};
|
|
1107
|
+
return context.receipt('insert_paragraphs', await executionContext.evaluateFactChecks(pre, post, [{ kind: 'revision-changed' }]), formatted?.contextualFormatting ? { contextualFormatting: formatted.contextualFormatting } : {});
|
|
1138
1108
|
}
|
|
1139
|
-
catch (
|
|
1140
|
-
return
|
|
1109
|
+
catch (error) {
|
|
1110
|
+
return context.failure('insert_paragraphs', error);
|
|
1141
1111
|
}
|
|
1142
1112
|
}
|
|
1143
1113
|
async function runInsertHeading(doc, args) {
|
|
@@ -2254,52 +2224,75 @@ async function runSplitList(doc, args) {
|
|
|
2254
2224
|
return failedReceipt('split_list', err, pre);
|
|
2255
2225
|
}
|
|
2256
2226
|
}
|
|
2227
|
+
async function resolveFactPlacement(placement, facts) {
|
|
2228
|
+
if (!placement || placement.at === 'document_end')
|
|
2229
|
+
return { kind: 'documentEnd' };
|
|
2230
|
+
if (placement.at === 'document_start')
|
|
2231
|
+
return { kind: 'documentStart' };
|
|
2232
|
+
const target = await facts.target(placement.selector);
|
|
2233
|
+
if (!target)
|
|
2234
|
+
throw new errors.SuperDocCliError('placement selector did not resolve to a unique body block', {
|
|
2235
|
+
code: 'INVALID_ARGUMENT',
|
|
2236
|
+
});
|
|
2237
|
+
return { kind: placement.at, target: { kind: 'block', nodeType: target.nodeType, nodeId: target.nodeId } };
|
|
2238
|
+
}
|
|
2239
|
+
function placementSelectors(placement) {
|
|
2240
|
+
return placement?.at === 'before' || placement?.at === 'after' ? [placement.selector] : [];
|
|
2241
|
+
}
|
|
2257
2242
|
async function runCreateTable(doc, args) {
|
|
2258
|
-
const
|
|
2243
|
+
const checks = [
|
|
2244
|
+
{ kind: 'revision-changed' },
|
|
2245
|
+
{ kind: 'block-count-delta', nodeType: 'table', delta: 1 },
|
|
2246
|
+
];
|
|
2247
|
+
const context = new executionContext.ExecutionContext(doc, {
|
|
2248
|
+
evidence: args.evidence,
|
|
2249
|
+
selectors: placementSelectors(args.placement),
|
|
2250
|
+
checks,
|
|
2251
|
+
});
|
|
2259
2252
|
try {
|
|
2260
|
-
if (!Number.isInteger(args.rows) || args.rows < 1 || !Number.isInteger(args.columns) || args.columns < 1)
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
const placement =
|
|
2264
|
-
const
|
|
2265
|
-
const
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
const appliedCells = await applyTableCellTexts(doc, createdTableNodeId, insertedTableOrdinal, flattenCellTexts(args.cellTexts), args.changeMode);
|
|
2272
|
-
if (appliedCells.length > 0) {
|
|
2273
|
-
executedOperations.push({
|
|
2274
|
-
operationId: 'doc.mutations.apply',
|
|
2275
|
-
rationale: `Populated ${appliedCells.length} table cells.`,
|
|
2276
|
-
});
|
|
2253
|
+
if (!Number.isInteger(args.rows) || args.rows < 1 || !Number.isInteger(args.columns) || args.columns < 1)
|
|
2254
|
+
throw new Error('rows and columns must be positive integers');
|
|
2255
|
+
const pre = await context.start();
|
|
2256
|
+
const placement = await resolveFactPlacement(args.placement, pre);
|
|
2257
|
+
const result = await executeCreateTable(context.document, args, placement);
|
|
2258
|
+
const tableNodeId = asString(asRecord(asRecord(result)?.table)?.nodeId);
|
|
2259
|
+
if (args.cellTexts && tableNodeId) {
|
|
2260
|
+
const cells = flattenCellTexts(args.cellTexts).filter((cell) => cell.text.trim());
|
|
2261
|
+
if (pre.complete) {
|
|
2262
|
+
const applied = await applyTableCellTexts(context.document, tableNodeId, estimateInsertedTableOrdinal(pre.complete, placement), cells, args.changeMode);
|
|
2263
|
+
await styleTableCells(context.document, applied, args.changeMode);
|
|
2277
2264
|
}
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2265
|
+
else {
|
|
2266
|
+
for (const cell of cells)
|
|
2267
|
+
await context.document.tables.setCellText({
|
|
2268
|
+
target: { kind: 'block', nodeType: 'table', nodeId: tableNodeId },
|
|
2269
|
+
rowIndex: cell.rowIndex,
|
|
2270
|
+
columnIndex: cell.columnIndex,
|
|
2271
|
+
text: cell.text,
|
|
2272
|
+
changeMode: args.changeMode,
|
|
2273
|
+
});
|
|
2274
|
+
const styled = cells.filter((cell) => cell.runs?.length || cell.marks);
|
|
2275
|
+
if (styled.length) {
|
|
2276
|
+
const identities = await doc.tables.getCells({ nodeId: tableNodeId });
|
|
2277
|
+
const resolved = styled.map((cell) => {
|
|
2278
|
+
const identity = identities.cells.find((item) => item.rowIndex === cell.rowIndex &&
|
|
2279
|
+
item.columnIndex <= cell.columnIndex &&
|
|
2280
|
+
item.columnIndex + item.colspan > cell.columnIndex);
|
|
2281
|
+
if (!identity?.firstParagraphNodeId)
|
|
2282
|
+
throw new Error('Required cell paragraph identity is unavailable.');
|
|
2283
|
+
return { ...cell, nodeId: identity.firstParagraphNodeId };
|
|
2284
|
+
});
|
|
2285
|
+
const styling = await applyItemStyling(context.document, resolved.map((cell) => cell.nodeId), resolved, args.changeMode);
|
|
2286
|
+
if (styling.skipped)
|
|
2287
|
+
throw new Error(`Requested cell styling failed: ${styling.skipped}`);
|
|
2288
|
+
}
|
|
2284
2289
|
}
|
|
2285
2290
|
}
|
|
2286
|
-
const post = await
|
|
2287
|
-
|
|
2288
|
-
{ kind: 'revision-changed' },
|
|
2289
|
-
{ kind: 'block-count-delta', nodeType: 'table', delta: 1 },
|
|
2290
|
-
]);
|
|
2291
|
-
return {
|
|
2292
|
-
status: verification.every((v) => v.passed) ? 'ok' : 'failed',
|
|
2293
|
-
intent: 'create_table',
|
|
2294
|
-
preSnapshot: { revision: pre.revision, counts: pre.counts },
|
|
2295
|
-
postSnapshot: { revision: post.revision, counts: post.counts },
|
|
2296
|
-
selectedTargets: [],
|
|
2297
|
-
executedOperations,
|
|
2298
|
-
verification,
|
|
2299
|
-
};
|
|
2291
|
+
const post = await context.finish();
|
|
2292
|
+
return context.receipt('create_table', await executionContext.evaluateFactChecks(pre, post, checks));
|
|
2300
2293
|
}
|
|
2301
|
-
catch (
|
|
2302
|
-
return
|
|
2294
|
+
catch (error) {
|
|
2295
|
+
return context.failure('create_table', error);
|
|
2303
2296
|
}
|
|
2304
2297
|
}
|
|
2305
2298
|
async function runCommentParagraphs(doc, args) {
|
|
@@ -2582,67 +2575,39 @@ async function runReplyToComment(doc, args) {
|
|
|
2582
2575
|
}
|
|
2583
2576
|
}
|
|
2584
2577
|
async function runRewriteBlock(doc, args) {
|
|
2585
|
-
const
|
|
2578
|
+
const context = new executionContext.ExecutionContext(doc, { evidence: args.evidence, selectors: [args.selector] });
|
|
2586
2579
|
try {
|
|
2587
|
-
const
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
// it can be re-applied over the unchanged prefix/suffix afterward.
|
|
2596
|
-
const preRuns = await captureBlockRuns(doc, target.nodeId, target.text);
|
|
2597
|
-
const steps = [
|
|
2580
|
+
const pre = await context.start();
|
|
2581
|
+
const target = await pre.target(args.selector);
|
|
2582
|
+
if (!target)
|
|
2583
|
+
throw new Error('selector did not resolve to a body block');
|
|
2584
|
+
context.selectedTargets.push({ selector: args.selector, matched: [target.nodeId] });
|
|
2585
|
+
const text = normalizeTitleLikeRewriteText(target.text, args.text);
|
|
2586
|
+
const runs = await captureBlockRuns(doc, target.nodeId, target.text);
|
|
2587
|
+
await executeMutations(context.document, [
|
|
2598
2588
|
{
|
|
2599
2589
|
id: 'rewrite-block-1',
|
|
2600
2590
|
op: 'text.rewrite',
|
|
2601
2591
|
where: { by: 'block', nodeType: target.nodeType, nodeId: target.nodeId },
|
|
2602
|
-
args: {
|
|
2603
|
-
replacement: { text: normalizedText },
|
|
2604
|
-
style: preserveRewriteStyle(),
|
|
2605
|
-
},
|
|
2592
|
+
args: { replacement: { text }, style: preserveRewriteStyle() },
|
|
2606
2593
|
},
|
|
2607
|
-
];
|
|
2608
|
-
|
|
2609
|
-
const
|
|
2610
|
-
const
|
|
2611
|
-
const rewrittenBlock = findSnapshotTextByNodeId(post, target.nodeId);
|
|
2594
|
+
], args.changeMode, pre.revision);
|
|
2595
|
+
await preserveRunPatternAfterRewrite(context.document, target.nodeId, target.text, runs, text);
|
|
2596
|
+
const post = await context.finish();
|
|
2597
|
+
const rewritten = await post.block(target.nodeId);
|
|
2612
2598
|
const verification = [
|
|
2613
2599
|
revisionVerification(pre.revision, post.revision, true),
|
|
2614
2600
|
{
|
|
2615
|
-
check: { kind: 'block-text-contains', nodeId: target.nodeId, text
|
|
2616
|
-
passed: !!
|
|
2601
|
+
check: { kind: 'block-text-contains', nodeId: target.nodeId, text },
|
|
2602
|
+
passed: !!rewritten && verifyRewrittenBlockText(rewritten.text, text, args.changeMode),
|
|
2617
2603
|
},
|
|
2618
2604
|
];
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
status: changed && rewritten ? 'ok' : 'failed',
|
|
2623
|
-
intent: 'rewrite_block',
|
|
2624
|
-
preSnapshot: { revision: pre.revision, counts: pre.counts },
|
|
2625
|
-
postSnapshot: { revision: post.revision, counts: post.counts },
|
|
2626
|
-
selectedTargets: [{ selector: args.selector, matched: [target.nodeId] }],
|
|
2627
|
-
executedOperations: [
|
|
2628
|
-
{ operationId: 'doc.mutations.apply', result },
|
|
2629
|
-
...(preservation ? [{ operationId: 'doc.format.apply', result: preservation }] : []),
|
|
2630
|
-
],
|
|
2631
|
-
verification,
|
|
2632
|
-
errors: changed && rewritten
|
|
2633
|
-
? undefined
|
|
2634
|
-
: [
|
|
2635
|
-
{
|
|
2636
|
-
code: 'ACTION_FAILED',
|
|
2637
|
-
message: changed
|
|
2638
|
-
? 'rewrite_block did not produce the requested rewritten text for the selected block'
|
|
2639
|
-
: 'rewrite_block produced no change for the selected block; keep the same target and provide a changed rewrite',
|
|
2640
|
-
},
|
|
2641
|
-
],
|
|
2642
|
-
};
|
|
2605
|
+
return context.receipt('rewrite_block', verification, verification.every((check) => check.passed)
|
|
2606
|
+
? {}
|
|
2607
|
+
: { errors: [{ code: 'ACTION_FAILED', message: 'rewrite_block did not produce the requested changed text' }] });
|
|
2643
2608
|
}
|
|
2644
|
-
catch (
|
|
2645
|
-
return
|
|
2609
|
+
catch (error) {
|
|
2610
|
+
return context.failure('rewrite_block', error);
|
|
2646
2611
|
}
|
|
2647
2612
|
}
|
|
2648
2613
|
const RUN_BOOL_MARKS = ['bold', 'italic', 'underline', 'strike'];
|
|
@@ -3293,43 +3258,30 @@ async function runApplyStyle(doc, args) {
|
|
|
3293
3258
|
* escape to superdoc_execute_code and apply the alignment untracked (no pPrChange).
|
|
3294
3259
|
*/
|
|
3295
3260
|
async function runFormatParagraph(doc, args) {
|
|
3296
|
-
const
|
|
3261
|
+
const context = new executionContext.ExecutionContext(doc, { evidence: args.evidence, selectors: [args.selector] });
|
|
3297
3262
|
try {
|
|
3298
|
-
const target = selectorToBlockTarget(args.selector, pre);
|
|
3299
|
-
if (!target) {
|
|
3300
|
-
return failedReceipt('format_paragraph', new Error('selector did not resolve to a unique body block'), pre);
|
|
3301
|
-
}
|
|
3302
3263
|
const alignment = typeof args.alignment === 'string' ? args.alignment.trim().toLowerCase() : '';
|
|
3303
|
-
const
|
|
3304
|
-
if (!['left', 'center', 'right', 'justify'].includes(
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
const
|
|
3264
|
+
const normalized = alignment === 'both' ? 'justify' : alignment;
|
|
3265
|
+
if (!['left', 'center', 'right', 'justify'].includes(normalized))
|
|
3266
|
+
throw new Error('format_paragraph requires alignment: left | center | right | justify');
|
|
3267
|
+
const pre = await context.start();
|
|
3268
|
+
const target = await pre.target(args.selector);
|
|
3269
|
+
if (!target)
|
|
3270
|
+
throw new Error('selector did not resolve to a unique body block');
|
|
3271
|
+
context.selectedTargets.push({ selector: args.selector, matched: [target.nodeId] });
|
|
3272
|
+
await executeMutations(context.document, [
|
|
3308
3273
|
{
|
|
3309
3274
|
id: 'format-paragraph-1',
|
|
3310
3275
|
op: 'format.apply',
|
|
3311
3276
|
where: { by: 'block', nodeType: target.nodeType, nodeId: target.nodeId },
|
|
3312
|
-
args: { alignment:
|
|
3277
|
+
args: { alignment: normalized, scope: 'block' },
|
|
3313
3278
|
},
|
|
3314
|
-
];
|
|
3315
|
-
const
|
|
3316
|
-
|
|
3317
|
-
const verification = evaluateChecks(pre, post, [{ kind: 'revision-changed' }]);
|
|
3318
|
-
return {
|
|
3319
|
-
status: verification.every((v) => v.passed) ? 'ok' : 'failed',
|
|
3320
|
-
intent: `format_paragraph: ${normalizedAlignment}`,
|
|
3321
|
-
preSnapshot: { revision: pre.revision, counts: pre.counts },
|
|
3322
|
-
postSnapshot: { revision: post.revision, counts: post.counts },
|
|
3323
|
-
selectedTargets: [{ selector: args.selector, matched: [target.nodeId] }],
|
|
3324
|
-
applied: { alignment: normalizedAlignment },
|
|
3325
|
-
executedOperations: [
|
|
3326
|
-
{ operationId: 'doc.mutations.apply', result: compactOpResult(result), rationale: `align ${target.nodeId}` },
|
|
3327
|
-
],
|
|
3328
|
-
verification,
|
|
3329
|
-
};
|
|
3279
|
+
], args.changeMode, pre.revision);
|
|
3280
|
+
const post = await context.finish();
|
|
3281
|
+
return context.receipt(`format_paragraph: ${normalized}`, await executionContext.evaluateFactChecks(pre, post, [{ kind: 'revision-changed' }]), { applied: { alignment: normalized } });
|
|
3330
3282
|
}
|
|
3331
|
-
catch (
|
|
3332
|
-
return
|
|
3283
|
+
catch (error) {
|
|
3284
|
+
return context.failure('format_paragraph', error);
|
|
3333
3285
|
}
|
|
3334
3286
|
}
|
|
3335
3287
|
/**
|
|
@@ -5985,8 +5937,9 @@ async function matchOneBlock(doc, postBlocks, preIds, created, createdIndex, anc
|
|
|
5985
5937
|
const formatApplyFn = maybeMethod(doc, ['format', 'apply']);
|
|
5986
5938
|
if (formatApplyFn) {
|
|
5987
5939
|
const textLength = (created.textPreview ?? '').length;
|
|
5988
|
-
const
|
|
5989
|
-
|
|
5940
|
+
const full = createdText ||
|
|
5941
|
+
(await doc.blocks.list({ nodeIds: [created.nodeId], limit: 1, includeText: true })).blocks.find((block) => block.nodeId === created.nodeId)?.text ||
|
|
5942
|
+
'';
|
|
5990
5943
|
await formatApplyFn({
|
|
5991
5944
|
blockId: created.nodeId,
|
|
5992
5945
|
start: 0,
|
|
@@ -6183,11 +6136,11 @@ async function matchBlockRunPattern(doc, reference, created, createdText) {
|
|
|
6183
6136
|
}
|
|
6184
6137
|
return Object.keys(applied).length > 0 ? { matchedSibling: reference.nodeId, ...applied } : null;
|
|
6185
6138
|
}
|
|
6186
|
-
async function matchInsertedBlockFormatting(doc, preBlocks, receipt, args) {
|
|
6139
|
+
async function matchInsertedBlockFormatting(doc, preBlocks, receipt, args, availableRows) {
|
|
6187
6140
|
if (receipt.status !== 'ok')
|
|
6188
6141
|
return receipt;
|
|
6189
6142
|
try {
|
|
6190
|
-
const postBlocks = await listBlockRows(doc);
|
|
6143
|
+
const postBlocks = availableRows ?? (await listBlockRows(doc));
|
|
6191
6144
|
const preIds = new Set(preBlocks.map((b) => b.nodeId));
|
|
6192
6145
|
const createdRows = postBlocks
|
|
6193
6146
|
.map((b, i) => ({ row: b, index: i }))
|
|
@@ -6478,9 +6431,9 @@ async function dispatchSuperdocPerformAction(doc, args) {
|
|
|
6478
6431
|
});
|
|
6479
6432
|
}
|
|
6480
6433
|
const headingLevel = asNumber(args.headingLevel);
|
|
6481
|
-
|
|
6482
|
-
const receipt = await runInsertParagraphs(doc, {
|
|
6434
|
+
return runInsertParagraphs(doc, {
|
|
6483
6435
|
action,
|
|
6436
|
+
evidence: args.evidence,
|
|
6484
6437
|
texts,
|
|
6485
6438
|
textSpecs,
|
|
6486
6439
|
placement: parsePlacement(args.placement),
|
|
@@ -6488,8 +6441,7 @@ async function dispatchSuperdocPerformAction(doc, args) {
|
|
|
6488
6441
|
headingLevel: headingLevel != null && Number.isInteger(headingLevel) && headingLevel >= 1 && headingLevel <= 6
|
|
6489
6442
|
? headingLevel
|
|
6490
6443
|
: undefined,
|
|
6491
|
-
});
|
|
6492
|
-
return matchInsertedBlockFormatting(doc, preRows, receipt, args);
|
|
6444
|
+
}, args);
|
|
6493
6445
|
}
|
|
6494
6446
|
case 'insert_heading': {
|
|
6495
6447
|
const text = asString(args.text);
|
|
@@ -6613,6 +6565,7 @@ async function dispatchSuperdocPerformAction(doc, args) {
|
|
|
6613
6565
|
}
|
|
6614
6566
|
return runCreateTable(doc, {
|
|
6615
6567
|
action,
|
|
6568
|
+
evidence: args.evidence,
|
|
6616
6569
|
rows,
|
|
6617
6570
|
columns,
|
|
6618
6571
|
cellTexts: parseCellTexts(args.cellTexts),
|
|
@@ -6636,16 +6589,41 @@ async function dispatchSuperdocPerformAction(doc, args) {
|
|
|
6636
6589
|
}
|
|
6637
6590
|
case 'add_comments': {
|
|
6638
6591
|
const commentText = asString(args.commentText);
|
|
6639
|
-
|
|
6640
|
-
const selectors = Array.isArray(args.selectors)
|
|
6641
|
-
? args.selectors.map((s) => parseSelector(s)).filter((s) => Boolean(s))
|
|
6642
|
-
: undefined;
|
|
6643
|
-
if (!commentText || (!selector && !(selectors && selectors.length))) {
|
|
6592
|
+
if (!commentText) {
|
|
6644
6593
|
throw new errors.SuperDocCliError('add_comments requires "commentText" and a "selector" or non-empty "selectors" array', {
|
|
6645
6594
|
code: 'INVALID_ARGUMENT',
|
|
6646
6595
|
});
|
|
6647
6596
|
}
|
|
6648
|
-
|
|
6597
|
+
const hasSelector = args.selector != null;
|
|
6598
|
+
const hasSelectors = args.selectors != null;
|
|
6599
|
+
if (hasSelector && hasSelectors) {
|
|
6600
|
+
throw new errors.SuperDocCliError('add_comments requires either "selector" or "selectors", not both', {
|
|
6601
|
+
code: 'INVALID_ARGUMENT',
|
|
6602
|
+
});
|
|
6603
|
+
}
|
|
6604
|
+
if (hasSelectors) {
|
|
6605
|
+
if (!Array.isArray(args.selectors) || args.selectors.length === 0) {
|
|
6606
|
+
throw new errors.SuperDocCliError('add_comments requires "selectors" to be a non-empty array', {
|
|
6607
|
+
code: 'INVALID_ARGUMENT',
|
|
6608
|
+
});
|
|
6609
|
+
}
|
|
6610
|
+
// Parse the complete batch before mutation. Filtering an invalid entry
|
|
6611
|
+
// would make the receipt report success for only part of the request.
|
|
6612
|
+
const selectors = [];
|
|
6613
|
+
for (const [index, raw] of args.selectors.entries()) {
|
|
6614
|
+
const parsed = parseSelector(raw);
|
|
6615
|
+
if (!parsed) {
|
|
6616
|
+
throw new errors.SuperDocCliError(`add_comments selectors[${index}] is not a valid selector; no comments were added`, { code: 'INVALID_ARGUMENT' });
|
|
6617
|
+
}
|
|
6618
|
+
selectors.push(parsed);
|
|
6619
|
+
}
|
|
6620
|
+
return runAddComments(doc, { action, commentText, selectors });
|
|
6621
|
+
}
|
|
6622
|
+
const selector = parseSelector(args.selector);
|
|
6623
|
+
if (!selector) {
|
|
6624
|
+
throw new errors.SuperDocCliError('add_comments requires "selector" to be valid or "selectors" to be a non-empty array', { code: 'INVALID_ARGUMENT' });
|
|
6625
|
+
}
|
|
6626
|
+
return runAddComments(doc, { action, commentText, selector });
|
|
6649
6627
|
}
|
|
6650
6628
|
case 'resolve_comments':
|
|
6651
6629
|
return runResolveComments(doc, {
|
|
@@ -6674,6 +6652,7 @@ async function dispatchSuperdocPerformAction(doc, args) {
|
|
|
6674
6652
|
}
|
|
6675
6653
|
return runRewriteBlock(doc, {
|
|
6676
6654
|
action,
|
|
6655
|
+
evidence: args.evidence,
|
|
6677
6656
|
text,
|
|
6678
6657
|
selector,
|
|
6679
6658
|
changeMode: parseChangeMode(args.changeMode),
|
|
@@ -6925,6 +6904,7 @@ async function dispatchSuperdocPerformAction(doc, args) {
|
|
|
6925
6904
|
}
|
|
6926
6905
|
return runFormatParagraph(doc, {
|
|
6927
6906
|
action,
|
|
6907
|
+
evidence: args.evidence,
|
|
6928
6908
|
selector,
|
|
6929
6909
|
alignment: asString(args.alignment) ?? '',
|
|
6930
6910
|
changeMode: parseChangeMode(args.changeMode),
|
package/dist/agent/actions.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type EvidencePolicy } from './execution-context.js';
|
|
1
2
|
/**
|
|
2
3
|
* Clean agent actions.
|
|
3
4
|
*
|
|
@@ -34,6 +35,7 @@ export type ActionPlacement = {
|
|
|
34
35
|
};
|
|
35
36
|
export type ActionArgs = InsertParagraphsArgs | InsertHeadingArgs | ReplaceTextArgs | DeleteTextArgs | DeleteBlocksArgs | AppendListArgs | AddListItemsArgs | ConvertListArgs | AttachNumberingArgs | SplitListArgs | CreateTableArgs | CommentParagraphsArgs | AddCommentsArgs | ResolveCommentsArgs | ReplyToCommentArgs | RewriteBlockArgs | FormatTextArgs | FormatParagraphArgs | ApplyStyleArgs | MoveTextArgs | UndoChangesArgs | RedoChangesArgs | AcceptTrackedChangesArgs | RejectTrackedChangesArgs | NormalizeBodyFontSizeArgs | SetFontFamilyArgs | ApplyLetterSpacingArgs | FillPlaceholdersArgs | MoveRangeArgs | InsertTocArgs | StyleTableArgs | MoveTableArgs | DeleteTableArgs | SetParagraphSpacingArgs | InsertPageBreakArgs | AddHyperlinkArgs | InsertTableRowArgs | InsertTableColumnArgs | DeleteTableRowArgs | DeleteTableColumnArgs | SplitTableArgs;
|
|
36
37
|
export type InsertParagraphsArgs = {
|
|
38
|
+
evidence?: EvidencePolicy;
|
|
37
39
|
action: 'insert_paragraphs';
|
|
38
40
|
texts?: readonly string[];
|
|
39
41
|
text?: string;
|
|
@@ -171,6 +173,7 @@ export type AddListItemsArgs = {
|
|
|
171
173
|
changeMode?: AgentChangeMode;
|
|
172
174
|
};
|
|
173
175
|
export type CreateTableArgs = {
|
|
176
|
+
evidence?: EvidencePolicy;
|
|
174
177
|
action: 'create_table';
|
|
175
178
|
rows: number;
|
|
176
179
|
columns: number;
|
|
@@ -214,6 +217,7 @@ export type SetFontFamilyArgs = {
|
|
|
214
217
|
changeMode?: AgentChangeMode;
|
|
215
218
|
};
|
|
216
219
|
export type RewriteBlockArgs = {
|
|
220
|
+
evidence?: EvidencePolicy;
|
|
217
221
|
action: 'rewrite_block';
|
|
218
222
|
selector: AgentSelector;
|
|
219
223
|
text: string;
|
|
@@ -432,6 +436,7 @@ export type ResolveCommentsArgs = {
|
|
|
432
436
|
reopen?: boolean;
|
|
433
437
|
};
|
|
434
438
|
export type FormatParagraphArgs = {
|
|
439
|
+
evidence?: EvidencePolicy;
|
|
435
440
|
action: 'format_paragraph';
|
|
436
441
|
/** Block whose paragraph properties to change. */
|
|
437
442
|
selector: AgentSelector;
|