@lazyingart/agintiflow 0.20.235 → 0.20.236
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.236",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
evaluateCurrentStateText,
|
|
5
|
+
evaluateDocumentConsistency,
|
|
5
6
|
evaluatePdfPageBalance,
|
|
6
7
|
extractSupersededLiterals,
|
|
7
8
|
} from "../src/document-artifact-quality.js";
|
|
@@ -42,6 +43,41 @@ const currentDocument = evaluateCurrentStateText({
|
|
|
42
43
|
});
|
|
43
44
|
assert.equal(currentDocument.ok, true, "authoritative current-state prose was rejected");
|
|
44
45
|
|
|
46
|
+
const supersedesHistory = evaluateCurrentStateText({
|
|
47
|
+
sourceText: source,
|
|
48
|
+
outputText: "This document supersedes earlier planning notes. The current owner is Mei.",
|
|
49
|
+
currentStateRequired: true,
|
|
50
|
+
});
|
|
51
|
+
assert.equal(supersedesHistory.ok, false, "present-tense supersedes history was accepted");
|
|
52
|
+
assert(
|
|
53
|
+
supersedesHistory.defects.some((item) => item.code === "historical-transition-prose"),
|
|
54
|
+
"present-tense supersedes did not produce a historical transition defect"
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const inconsistentActions = evaluateDocumentConsistency([
|
|
58
|
+
"Three open actions remain.",
|
|
59
|
+
"Remaining Actions",
|
|
60
|
+
"Place filter order 28 August 2026",
|
|
61
|
+
"Provide wiring diagram 2 September 2026",
|
|
62
|
+
"Complete safety review 5 September 2026",
|
|
63
|
+
"Freeze checklist 10 September 2026",
|
|
64
|
+
"Budget",
|
|
65
|
+
].join("\n"));
|
|
66
|
+
assert.equal(inconsistentActions.ok, false, "declared action count contradicted by the action section was accepted");
|
|
67
|
+
assert.equal(inconsistentActions.actionSectionItemCount, 4);
|
|
68
|
+
assert.equal(inconsistentActions.defects[0]?.code, "action-count-inconsistency");
|
|
69
|
+
|
|
70
|
+
const consistentActions = evaluateDocumentConsistency([
|
|
71
|
+
"Four open actions remain.",
|
|
72
|
+
"Remaining Actions",
|
|
73
|
+
"Place filter order 28 August 2026",
|
|
74
|
+
"Provide wiring diagram 2 September 2026",
|
|
75
|
+
"Complete safety review 5 September 2026",
|
|
76
|
+
"Freeze checklist 10 September 2026",
|
|
77
|
+
"Budget",
|
|
78
|
+
].join("\n"));
|
|
79
|
+
assert.equal(consistentActions.ok, true, "matching declared and section action counts were rejected");
|
|
80
|
+
|
|
45
81
|
function page(
|
|
46
82
|
words,
|
|
47
83
|
{ height = 842, startY = 60, endY = 700, heading = "Section", wordHeight = 10 } = {}
|
|
@@ -28,8 +28,24 @@ const EXCLUDED_DIRECTORY_NAMES = new Set([
|
|
|
28
28
|
const INTENTIONAL_SPARSE_PAGE_PATTERN =
|
|
29
29
|
/^(?:appendix|approval|approvals|acknowledgements?|back cover|contact|notes|references|sign[- ]?off|signatures?)\b/i;
|
|
30
30
|
const HISTORICAL_TRANSITION_PATTERN =
|
|
31
|
-
/\b(?:formerly|no longer|previously|replac(?:ed|ing)|
|
|
31
|
+
/\b(?:formerly|no longer|previously|replac(?:ed|ing)|supersed(?:e|ed|es|ing)|used to be)\b/i;
|
|
32
32
|
const MIN_READABLE_MEDIAN_WORD_HEIGHT_PT = 8.8;
|
|
33
|
+
const COUNT_WORDS = new Map([
|
|
34
|
+
["zero", 0], ["one", 1], ["two", 2], ["three", 3], ["four", 4], ["five", 5],
|
|
35
|
+
["six", 6], ["seven", 7], ["eight", 8], ["nine", 9], ["ten", 10],
|
|
36
|
+
["eleven", 11], ["twelve", 12], ["thirteen", 13], ["fourteen", 14], ["fifteen", 15],
|
|
37
|
+
["sixteen", 16], ["seventeen", 17], ["eighteen", 18], ["nineteen", 19], ["twenty", 20],
|
|
38
|
+
]);
|
|
39
|
+
const ACTION_COUNT_PATTERN = new RegExp(
|
|
40
|
+
`\\b(\\d+|${[...COUNT_WORDS.keys()].join("|")})\\s+(?:open|remaining|outstanding|pending)\\s+(?:action items?|actions?|tasks?|items?)\\b`,
|
|
41
|
+
"gi"
|
|
42
|
+
);
|
|
43
|
+
const ACTION_SECTION_HEADING_PATTERN =
|
|
44
|
+
/^\s*(?:remaining|open|outstanding|pending)\s+(?:action items?|actions?|tasks?|items?|next steps)\s*$/i;
|
|
45
|
+
const DOCUMENT_SECTION_HEADING_PATTERN =
|
|
46
|
+
/^\s*(?:appendix|budget|current decisions?|executive summary|notes|references|risks?(?: and mitigations)?|summary)\s*$/i;
|
|
47
|
+
const HUMAN_DATE_PATTERN =
|
|
48
|
+
/\b(?:\d{4}-\d{2}-\d{2}|\d{1,2}\s+(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)(?:\s+\d{4})?|(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)\s+\d{1,2}(?:,\s*\d{4})?)\b/gi;
|
|
33
49
|
|
|
34
50
|
function portablePath(value = "") {
|
|
35
51
|
return String(value || "").replace(/\\/g, "/");
|
|
@@ -248,6 +264,47 @@ export function evaluateCurrentStateText({ sourceText = "", outputText = "", cur
|
|
|
248
264
|
return { ok: defects.length === 0, defects, supersededLiterals, presentSupersededLiterals };
|
|
249
265
|
}
|
|
250
266
|
|
|
267
|
+
function parsedCount(value = "") {
|
|
268
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
269
|
+
if (/^\d+$/.test(normalized)) return Number.parseInt(normalized, 10);
|
|
270
|
+
return COUNT_WORDS.get(normalized);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function actionSectionItemCount(outputText = "") {
|
|
274
|
+
const lines = String(outputText || "").split(/\r?\n/);
|
|
275
|
+
const headingIndex = lines.findIndex((line) => ACTION_SECTION_HEADING_PATTERN.test(line));
|
|
276
|
+
if (headingIndex < 0) return 0;
|
|
277
|
+
const section = [];
|
|
278
|
+
for (const line of lines.slice(headingIndex + 1)) {
|
|
279
|
+
if (DOCUMENT_SECTION_HEADING_PATTERN.test(line)) break;
|
|
280
|
+
section.push(line);
|
|
281
|
+
}
|
|
282
|
+
const sectionText = section.join("\n");
|
|
283
|
+
const dates = new Set(
|
|
284
|
+
[...sectionText.matchAll(HUMAN_DATE_PATTERN)].map((match) => normalizedComparableText(match[0]))
|
|
285
|
+
);
|
|
286
|
+
const bullets = section.filter((line) => /^\s*(?:[-*•]|\d+[.)])\s+\S/.test(line)).length;
|
|
287
|
+
return Math.max(dates.size, bullets);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function evaluateDocumentConsistency(outputText = "") {
|
|
291
|
+
const defects = [];
|
|
292
|
+
const sectionCount = actionSectionItemCount(outputText);
|
|
293
|
+
if (sectionCount > 0) {
|
|
294
|
+
for (const match of String(outputText || "").matchAll(ACTION_COUNT_PATTERN)) {
|
|
295
|
+
const declaredCount = parsedCount(match[1]);
|
|
296
|
+
if (Number.isInteger(declaredCount) && declaredCount !== sectionCount) {
|
|
297
|
+
defects.push({
|
|
298
|
+
code: "action-count-inconsistency",
|
|
299
|
+
message: `The document declares ${declaredCount} open action${declaredCount === 1 ? "" : "s"}, but the Remaining Actions section contains ${sectionCount} dated/listed item${sectionCount === 1 ? "" : "s"}. Reconcile the summary and action table before delivery.`,
|
|
300
|
+
});
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return { ok: defects.length === 0, defects, actionSectionItemCount: sectionCount };
|
|
306
|
+
}
|
|
307
|
+
|
|
251
308
|
async function collectSourceDocuments(commandCwd) {
|
|
252
309
|
const documents = [];
|
|
253
310
|
let totalBytes = 0;
|
|
@@ -419,6 +476,7 @@ export async function validateWordDocumentArtifacts({
|
|
|
419
476
|
if (artifact.extension === ".pdf") {
|
|
420
477
|
const extracted = await extractPdf(artifact);
|
|
421
478
|
const semantic = evaluateCurrentStateText({ sourceText, outputText: extracted.text, currentStateRequired });
|
|
479
|
+
const consistency = evaluateDocumentConsistency(extracted.text);
|
|
422
480
|
const pageBalance = evaluatePdfPageBalance(extracted.bbox);
|
|
423
481
|
if (!String(extracted.text || "").trim()) {
|
|
424
482
|
defects.push({
|
|
@@ -435,6 +493,7 @@ export async function validateWordDocumentArtifacts({
|
|
|
435
493
|
});
|
|
436
494
|
}
|
|
437
495
|
defects.push(...semantic.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
496
|
+
defects.push(...consistency.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
438
497
|
defects.push(...pageBalance.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
439
498
|
artifactReports.push({
|
|
440
499
|
path: artifact.path,
|
|
@@ -442,11 +501,13 @@ export async function validateWordDocumentArtifacts({
|
|
|
442
501
|
textChars: extracted.text.length,
|
|
443
502
|
pageCount: pageBalance.pages.length,
|
|
444
503
|
pages: pageBalance.pages,
|
|
504
|
+
actionSectionItemCount: consistency.actionSectionItemCount,
|
|
445
505
|
supersededLiterals: semantic.supersededLiterals,
|
|
446
506
|
});
|
|
447
507
|
} else {
|
|
448
508
|
const text = await extractDocxText(artifact);
|
|
449
509
|
const semantic = evaluateCurrentStateText({ sourceText, outputText: text, currentStateRequired });
|
|
510
|
+
const consistency = evaluateDocumentConsistency(text);
|
|
450
511
|
if (!String(text || "").trim()) {
|
|
451
512
|
defects.push({
|
|
452
513
|
code: "empty-docx-text",
|
|
@@ -455,10 +516,12 @@ export async function validateWordDocumentArtifacts({
|
|
|
455
516
|
});
|
|
456
517
|
}
|
|
457
518
|
defects.push(...semantic.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
519
|
+
defects.push(...consistency.defects.map((item) => ({ ...item, path: artifact.path })));
|
|
458
520
|
artifactReports.push({
|
|
459
521
|
path: artifact.path,
|
|
460
522
|
extension: artifact.extension,
|
|
461
523
|
textChars: text.length,
|
|
524
|
+
actionSectionItemCount: consistency.actionSectionItemCount,
|
|
462
525
|
supersededLiterals: semantic.supersededLiterals,
|
|
463
526
|
});
|
|
464
527
|
}
|
package/src/task-profiles.js
CHANGED
|
@@ -276,7 +276,7 @@ export const TASK_PROFILES = {
|
|
|
276
276
|
id: "word",
|
|
277
277
|
label: "Word documents",
|
|
278
278
|
prompt:
|
|
279
|
-
"Bias toward Word/docx/document workflows while still using writing, conversion, LaTeX, or scripts when useful. Preserve source material byte-for-byte and synthesize a reader-facing document from the authoritative current facts instead of concatenating notes, logs, schemas, task IDs, private paths, or delivery instructions. Reconcile conflicting or superseded source facts before drafting: values labeled corrected, replaced, earlier, old, prior, cancelled, or no longer selected identify what to discard, and those discarded literals must not appear in the final document unless the user explicitly requests history or the history is necessary to explain a live decision. Keep the reconciliation history private: a current-state handoff should say who owns the work, which value is approved, and which option is selected, not narrate who was replaced or which preliminary value is no longer used. Before finishing, extract the final text and search for every superseded literal found in the sources. Prefer mature editable-document tooling already available in the workspace, such as python-docx, pandoc, or LibreOffice, over hand-written OOXML; when direct OOXML is genuinely necessary, validate its package parts and openability. Keep one maintainable source of truth and a reproducible project-local build command. Verify the DOCX is structurally editable, compile the PDF, run pdftotext or an equivalent extraction check that rejects replacement characters and unexpected control glyphs, and verify PDF text bounding boxes remain inside a readable page margin. Render every PDF page to a separate image under an ignored build/verification directory. Inspect one rendered page per read_image call, never batch pages into one vision call, and repair orphaned headings, near-empty spill pages, awkward table or paragraph breaks, overlaps, clipping, excessive whitespace, weak hierarchy, and inconsistent number formatting before finishing. Keep normal readable body type, line spacing, and margins; never shrink typography merely to force the document onto one page. When content spans pages, move or redistribute coherent sections so each page is useful instead of leaving a short spill page. Preserve an intentionally sparse appendix, approval, signature, reference, or back-matter page when it serves a real purpose. Retain ignored verification renders as evidence; optional cleanup must never block completion. Use clear descriptive filenames, exclude caches and generated debris from commits, inspect git status/diff before committing, and
|
|
279
|
+
"Bias toward Word/docx/document workflows while still using writing, conversion, LaTeX, or scripts when useful. Preserve source material byte-for-byte and synthesize a reader-facing document from the authoritative current facts instead of concatenating notes, logs, schemas, task IDs, private paths, or delivery instructions. Reconcile conflicting or superseded source facts before drafting: values labeled corrected, replaced, earlier, old, prior, cancelled, or no longer selected identify what to discard, and those discarded literals must not appear in the final document unless the user explicitly requests history or the history is necessary to explain a live decision. Keep the reconciliation history private: a current-state handoff should say who owns the work, which value is approved, and which option is selected, not narrate who was replaced or which preliminary value is no longer used. Before finishing, extract the final text and search for every superseded literal found in the sources. Cross-check every quantitative statement against the detailed section it summarizes: counts of open actions, risks, decisions, line items, totals, dates, and owners must agree everywhere. Prefer mature editable-document tooling already available in the workspace, such as python-docx, pandoc, or LibreOffice, over hand-written OOXML; when direct OOXML is genuinely necessary, validate its package parts and openability. Keep one maintainable source of truth and a reproducible project-local build command. When reproducibility is requested, declare dependencies in project files and make the exact documented command work from a clean project shell; do not rely on inherited packages or claim that dependencies are already installed merely because the current agent container has them. Run that exact documented command, not only its inner generator. Verify the DOCX is structurally editable, compile the PDF, run pdftotext or an equivalent extraction check that rejects replacement characters and unexpected control glyphs, and verify PDF text bounding boxes remain inside a readable page margin. Render every PDF page to a separate image under an ignored build/verification directory. Inspect one rendered page per read_image call, never batch pages into one vision call, and repair orphaned headings, near-empty spill pages, awkward table or paragraph breaks, overlaps, clipping, excessive whitespace, weak hierarchy, and inconsistent number formatting before finishing. Keep normal readable body type, line spacing, and margins; never shrink typography merely to force the document onto one page. When content spans pages, move or redistribute coherent sections so each page is useful instead of leaving a short spill page. Preserve an intentionally sparse appendix, approval, signature, reference, or back-matter page when it serves a real purpose. Retain ignored verification renders as evidence; optional cleanup must never block completion. Use clear descriptive filenames, exclude caches and generated debris from commits, inspect git status/diff before committing, and honor any project instruction that requires an intentional clean commit even when the chat did not repeat it. Report success only after the editable source, reader-facing current-state content, internal consistency, visual layout, searchable text, exact documented build command, and requested artifacts all pass.",
|
|
280
280
|
tools: ["files", "shell", "canvas", "sandbox"],
|
|
281
281
|
},
|
|
282
282
|
latex: {
|