@aigne/doc-smith 0.9.6-beta → 0.9.6-beta.2
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/CHANGELOG.md +15 -0
- package/agents/create/document-structure-tools/delete-document.mjs +53 -9
- package/agents/create/update-document-structure.yaml +1 -1
- package/agents/create/user-add-document/add-documents-to-structure.mjs +96 -0
- package/agents/create/user-add-document/find-documents-to-add-links.yaml +47 -0
- package/agents/create/user-add-document/index.yaml +46 -0
- package/agents/create/user-add-document/prepare-documents-to-translate.mjs +22 -0
- package/agents/create/user-add-document/print-add-document-summary.mjs +63 -0
- package/agents/create/user-add-document/review-documents-with-new-links.mjs +110 -0
- package/agents/create/user-remove-document/find-documents-with-invalid-links.mjs +78 -0
- package/agents/create/user-remove-document/index.yaml +41 -0
- package/agents/create/user-remove-document/prepare-documents-to-translate.mjs +22 -0
- package/agents/create/user-remove-document/print-remove-document-summary.mjs +53 -0
- package/agents/create/user-remove-document/remove-documents-from-structure.mjs +99 -0
- package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +119 -0
- package/agents/create/user-review-document-structure.mjs +1 -40
- package/agents/create/utils/init-current-content.mjs +38 -0
- package/agents/init/index.mjs +3 -4
- package/agents/update/document-tools/update-document-content.mjs +12 -12
- package/agents/update/update-document-detail.yaml +5 -1
- package/agents/update/update-single/update-single-document-detail.mjs +21 -6
- package/agents/update/user-review-document.mjs +10 -13
- package/agents/utils/add-translates-to-structure.mjs +29 -0
- package/agents/utils/{analyze-feedback-intent.yaml → analyze-document-feedback-intent.yaml} +5 -2
- package/agents/utils/analyze-structure-feedback-intent.yaml +29 -0
- package/agents/utils/check-detail-result.mjs +2 -14
- package/agents/utils/load-sources.mjs +36 -46
- package/aigne.yaml +10 -1
- package/package.json +1 -1
- package/prompts/detail/custom/custom-components/x-cards-usage-rules.md +18 -10
- package/prompts/structure/find-documents-to-add-links.md +52 -0
- package/prompts/utils/analyze-document-feedback-intent.md +54 -0
- package/prompts/utils/analyze-structure-feedback-intent.md +43 -0
- package/types/document-schema.mjs +2 -0
- package/types/document-structure-schema.mjs +6 -2
- package/utils/docs-finder-utils.mjs +161 -0
- package/utils/file-utils.mjs +9 -7
- package/utils/load-config.mjs +21 -4
- package/utils/markdown-checker.mjs +50 -5
- package/utils/utils.mjs +103 -0
- package/prompts/utils/analyze-feedback-intent.md +0 -55
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Print summary of removed documents and documents with invalid links
|
|
5
|
+
*/
|
|
6
|
+
export default async function printRemoveDocumentSummary({
|
|
7
|
+
deletedDocuments = [],
|
|
8
|
+
documentsWithInvalidLinks = [],
|
|
9
|
+
}) {
|
|
10
|
+
let message = `\n---\n`;
|
|
11
|
+
message += `${chalk.bold.cyan("📊 Summary")}\n\n`;
|
|
12
|
+
|
|
13
|
+
// Display removed documents
|
|
14
|
+
if (deletedDocuments && deletedDocuments.length > 0) {
|
|
15
|
+
message += `🗑️ Removed Documents:\n`;
|
|
16
|
+
message += ` Total: ${deletedDocuments.length} document(s)\n\n`;
|
|
17
|
+
deletedDocuments.forEach((doc, index) => {
|
|
18
|
+
message += ` ${chalk.cyan(`${index + 1}. ${doc.path}`)}`;
|
|
19
|
+
if (doc.title && doc.title !== doc.path) {
|
|
20
|
+
message += ` - ${chalk.yellow(doc.title)}`;
|
|
21
|
+
}
|
|
22
|
+
message += `\n\n`;
|
|
23
|
+
});
|
|
24
|
+
} else {
|
|
25
|
+
message += `🗑️ Removed Documents:\n`;
|
|
26
|
+
message += `${chalk.gray(" No documents were removed.\n\n")}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Display documents with invalid links
|
|
30
|
+
if (documentsWithInvalidLinks && documentsWithInvalidLinks.length > 0) {
|
|
31
|
+
message += `✅ Documents fixed (Removed invalid links):\n`;
|
|
32
|
+
message += ` Total: ${documentsWithInvalidLinks.length} document(s)\n\n`;
|
|
33
|
+
documentsWithInvalidLinks.forEach((doc, index) => {
|
|
34
|
+
message += ` ${chalk.cyan(`${index + 1}. ${doc.path}`)}`;
|
|
35
|
+
if (doc.title && doc.title !== doc.path) {
|
|
36
|
+
message += ` - ${chalk.yellow(doc.title)}`;
|
|
37
|
+
}
|
|
38
|
+
message += `\n`;
|
|
39
|
+
if (doc.invalidLinks && doc.invalidLinks.length > 0) {
|
|
40
|
+
message += ` Invalid links fixed: ${chalk.gray(doc.invalidLinks.join(", "))}\n`;
|
|
41
|
+
}
|
|
42
|
+
message += `\n`;
|
|
43
|
+
});
|
|
44
|
+
} else {
|
|
45
|
+
message += `✅ Documents fixed (Removed invalid links):\n`;
|
|
46
|
+
message += `${chalk.gray(" No documents needed to be fixed.\n\n")}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { message };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
printRemoveDocumentSummary.taskTitle = "Print remove document summary";
|
|
53
|
+
printRemoveDocumentSummary.description = "Display summary of removed documents";
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import deleteDocument from "../document-structure-tools/delete-document.mjs";
|
|
2
|
+
import { buildDocumentTree, buildChoicesFromTree } from "../../../utils/docs-finder-utils.mjs";
|
|
3
|
+
|
|
4
|
+
export default async function removeDocumentsFromStructure(input = {}, options = {}) {
|
|
5
|
+
const { originalDocumentStructure, locale = "en", docsDir } = input;
|
|
6
|
+
|
|
7
|
+
if (!Array.isArray(originalDocumentStructure) || originalDocumentStructure.length === 0) {
|
|
8
|
+
console.warn(
|
|
9
|
+
"🗑️ Remove Documents\n • No document structure found. Please generate documents first.",
|
|
10
|
+
);
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Initialize currentStructure in userContext
|
|
15
|
+
options.context.userContext.currentStructure = [...originalDocumentStructure];
|
|
16
|
+
|
|
17
|
+
// Build tree structure
|
|
18
|
+
const { rootNodes } = buildDocumentTree(originalDocumentStructure);
|
|
19
|
+
|
|
20
|
+
// Build choices with tree structure visualization
|
|
21
|
+
const choices = await buildChoicesFromTree(rootNodes, "", 0, { locale, docsDir });
|
|
22
|
+
|
|
23
|
+
// Let user select documents to delete
|
|
24
|
+
let selectedPaths = [];
|
|
25
|
+
try {
|
|
26
|
+
selectedPaths = await options.prompts.checkbox({
|
|
27
|
+
message: "Select documents to remove (Press Enter with no selection to finish):",
|
|
28
|
+
choices,
|
|
29
|
+
});
|
|
30
|
+
} catch {
|
|
31
|
+
// User cancelled or no selection made
|
|
32
|
+
console.log("No documents were removed.");
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// If no documents selected, exit
|
|
37
|
+
if (!selectedPaths || selectedPaths.length === 0) {
|
|
38
|
+
console.log("No documents were removed.");
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Delete each selected document with cascade deletion
|
|
43
|
+
const deletedDocuments = [];
|
|
44
|
+
const errors = [];
|
|
45
|
+
|
|
46
|
+
for (const path of selectedPaths) {
|
|
47
|
+
try {
|
|
48
|
+
const deleteResult = await deleteDocument(
|
|
49
|
+
{
|
|
50
|
+
path,
|
|
51
|
+
recursive: true,
|
|
52
|
+
},
|
|
53
|
+
options,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (deleteResult.error) {
|
|
57
|
+
errors.push({
|
|
58
|
+
path,
|
|
59
|
+
error: deleteResult.error.message,
|
|
60
|
+
});
|
|
61
|
+
} else {
|
|
62
|
+
deletedDocuments.push(...deleteResult.deletedDocuments);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
errors.push({
|
|
66
|
+
path,
|
|
67
|
+
error: error.message,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check if there are errors
|
|
73
|
+
if (errors.length > 0) {
|
|
74
|
+
console.warn(
|
|
75
|
+
`🗑️ Remove Documents\n • Failed to remove documents:\n${errors
|
|
76
|
+
.map((e) => ` - ${e.path}: ${e.error}`)
|
|
77
|
+
.join("\n")}`,
|
|
78
|
+
);
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (deletedDocuments.length === 0) {
|
|
83
|
+
console.log("No documents were removed.");
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Get final updated document structure
|
|
88
|
+
const updatedStructure = options.context.userContext.currentStructure;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
documentStructure: updatedStructure,
|
|
92
|
+
originalDocumentStructure: JSON.parse(JSON.stringify(updatedStructure)),
|
|
93
|
+
deletedDocuments,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
removeDocumentsFromStructure.taskTitle = "Remove documents from structure";
|
|
98
|
+
removeDocumentsFromStructure.description =
|
|
99
|
+
"Select and remove documents from the documentation structure";
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildAllowedLinksFromStructure,
|
|
3
|
+
generateFileName,
|
|
4
|
+
pathToFlatName,
|
|
5
|
+
} from "../../../utils/docs-finder-utils.mjs";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generate feedback message for fixing invalid links in a document
|
|
9
|
+
*/
|
|
10
|
+
function generateInvalidLinksFeedback(invalidLinks, documentPath, documentExecutionStructure) {
|
|
11
|
+
const invalidLinksList = invalidLinks.map((link) => `- ${link}`).join("\n");
|
|
12
|
+
|
|
13
|
+
// Build allowed links from document structure for replacement suggestions
|
|
14
|
+
const allowedLinks = buildAllowedLinksFromStructure(documentExecutionStructure);
|
|
15
|
+
const allowedLinksArray = Array.from(allowedLinks)
|
|
16
|
+
.filter((link) => link !== documentPath) // Exclude current document path
|
|
17
|
+
.sort();
|
|
18
|
+
|
|
19
|
+
const allowedLinksList =
|
|
20
|
+
allowedLinksArray.length > 0
|
|
21
|
+
? allowedLinksArray.map((link) => `- ${link}`).join("\n")
|
|
22
|
+
: "(No available links)";
|
|
23
|
+
|
|
24
|
+
return `This document contains invalid links that need to be fixed. Please handle them according to the following instructions:
|
|
25
|
+
|
|
26
|
+
**Invalid Links Found:**
|
|
27
|
+
${invalidLinksList}
|
|
28
|
+
|
|
29
|
+
**Available Valid Links:**
|
|
30
|
+
${allowedLinksList}
|
|
31
|
+
|
|
32
|
+
**Instructions for fixing invalid links:**
|
|
33
|
+
|
|
34
|
+
1. For each invalid link found in the document:
|
|
35
|
+
- Using the document context and the list of available valid links, try to find a suitable replacement link from the available valid links.
|
|
36
|
+
- When choosing a replacement, exclude the current document path (${documentPath}); linking to the current document is not logical.
|
|
37
|
+
- **Do not consider the original invalid link or its related text**; they are outdated and should be replaced.
|
|
38
|
+
|
|
39
|
+
2. If a suitable replacement link is found:
|
|
40
|
+
- Update **all related fields** associated with the invalid link (e.g., link URL, link text, surrounding context) according to the matched link from the available valid links.
|
|
41
|
+
- Ensure that after updating the link, the surrounding content remains consistent and natural. If there is a mismatch, update the corresponding content to keep everything aligned.
|
|
42
|
+
|
|
43
|
+
3. If no suitable replacement link can be found:
|
|
44
|
+
- Remove the invalid link completely, including the link text and any associated content that only makes sense with that link.
|
|
45
|
+
- **Do not affect other unrelated content** in the document; only remove content that is directly tied to the invalid link.
|
|
46
|
+
|
|
47
|
+
4. Ensure the document remains coherent and readable after the changes.`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default async function reviewDocumentsWithInvalidLinks(input = {}, options = {}) {
|
|
51
|
+
const { documentsWithInvalidLinks = [], documentExecutionStructure = [], locale = "en" } = input;
|
|
52
|
+
|
|
53
|
+
// If no documents with invalid links, return empty array
|
|
54
|
+
if (!Array.isArray(documentsWithInvalidLinks) || documentsWithInvalidLinks.length === 0) {
|
|
55
|
+
return {
|
|
56
|
+
documentsWithInvalidLinks: [],
|
|
57
|
+
documentsToUpdate: [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Create choices for user selection, default all checked
|
|
62
|
+
const choices = documentsWithInvalidLinks.map((doc) => {
|
|
63
|
+
const flatName = pathToFlatName(doc.path);
|
|
64
|
+
const filename = generateFileName(flatName, locale);
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
name: `${doc.title} (${filename})`,
|
|
68
|
+
value: doc.path,
|
|
69
|
+
checked: true, // Default all selected
|
|
70
|
+
description: `Invalid Links(${doc.invalidLinks?.length || 0}): ${doc.invalidLinks?.join(", ")}`,
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Let user select documents (default all selected)
|
|
75
|
+
const selectedPaths = await options.prompts.checkbox({
|
|
76
|
+
message:
|
|
77
|
+
"Select documents with invalid links to fix (all selected by default, press Enter to confirm, or unselect all to skip):",
|
|
78
|
+
choices,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Filter documents based on user selection
|
|
82
|
+
const selectedPathsSet = new Set(selectedPaths);
|
|
83
|
+
const filteredDocs = documentsWithInvalidLinks.filter((doc) => selectedPathsSet.has(doc.path));
|
|
84
|
+
|
|
85
|
+
if (filteredDocs.length === 0) {
|
|
86
|
+
return {
|
|
87
|
+
documentsWithInvalidLinks: [],
|
|
88
|
+
documentsToUpdate: [],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Prepare documents: add necessary fields for update (without content)
|
|
93
|
+
const preparedDocs = [];
|
|
94
|
+
|
|
95
|
+
for (const doc of filteredDocs) {
|
|
96
|
+
if (!doc.path) continue;
|
|
97
|
+
|
|
98
|
+
// Find corresponding document in documentStructure to get additional fields
|
|
99
|
+
const structureDoc = documentExecutionStructure.find((item) => item.path === doc.path);
|
|
100
|
+
|
|
101
|
+
// Generate feedback message for fixing invalid links
|
|
102
|
+
const feedback = generateInvalidLinksFeedback(
|
|
103
|
+
doc.invalidLinks,
|
|
104
|
+
doc.path,
|
|
105
|
+
documentExecutionStructure,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
preparedDocs.push({
|
|
109
|
+
...structureDoc,
|
|
110
|
+
feedback,
|
|
111
|
+
invalidLinks: doc.invalidLinks,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
documentsWithInvalidLinks: preparedDocs, // for print summary
|
|
117
|
+
documentsToUpdate: JSON.parse(JSON.stringify(preparedDocs)), // for batch update
|
|
118
|
+
};
|
|
119
|
+
}
|
|
@@ -1,47 +1,8 @@
|
|
|
1
1
|
import { getActiveRulesForScope } from "../../utils/preferences-utils.mjs";
|
|
2
2
|
import { recordUpdate } from "../../utils/history-utils.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { printDocumentStructure } from "../../utils/docs-finder-utils.mjs";
|
|
4
4
|
import equal from "fast-deep-equal";
|
|
5
5
|
|
|
6
|
-
function formatDocumentStructure(structure) {
|
|
7
|
-
const { rootNodes } = buildDocumentTree(structure);
|
|
8
|
-
|
|
9
|
-
function printNode(node, depth = 0) {
|
|
10
|
-
const INDENT_SPACES = " ";
|
|
11
|
-
const FOLDER_ICON = " 📁";
|
|
12
|
-
const FILE_ICON = " 📄";
|
|
13
|
-
const indent = INDENT_SPACES.repeat(depth);
|
|
14
|
-
const prefix = depth === 0 ? FOLDER_ICON : FILE_ICON;
|
|
15
|
-
|
|
16
|
-
console.log(`${indent}${prefix} ${node.title}`);
|
|
17
|
-
|
|
18
|
-
if (node.children && node.children.length > 0) {
|
|
19
|
-
node.children.forEach((child) => {
|
|
20
|
-
printNode(child, depth + 1);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return { rootNodes, printNode };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function printDocumentStructure(structure) {
|
|
29
|
-
console.log(`\n ${"-".repeat(50)}`);
|
|
30
|
-
console.log(" Current Documentation Structure");
|
|
31
|
-
console.log(` ${"-".repeat(50)}`);
|
|
32
|
-
|
|
33
|
-
const { rootNodes, printNode } = formatDocumentStructure(structure);
|
|
34
|
-
|
|
35
|
-
if (rootNodes.length === 0) {
|
|
36
|
-
console.log(" No documentation structure found.");
|
|
37
|
-
} else {
|
|
38
|
-
rootNodes.forEach((node) => {
|
|
39
|
-
printNode(node);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
console.log();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
6
|
export default async function userReviewDocumentStructure({ documentStructure, ...rest }, options) {
|
|
46
7
|
// Check if documentation structure exists
|
|
47
8
|
if (!documentStructure || !Array.isArray(documentStructure) || documentStructure.length === 0) {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateFileName,
|
|
3
|
+
pathToFlatName,
|
|
4
|
+
readFileContent,
|
|
5
|
+
} from "../../../utils/docs-finder-utils.mjs";
|
|
6
|
+
import { userContextAt } from "../../../utils/utils.mjs";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initialize currentContents in userContext for document update
|
|
10
|
+
* Reads document content from file system and sets it in userContext
|
|
11
|
+
*/
|
|
12
|
+
export default async function initCurrentContent(input, options) {
|
|
13
|
+
const { path, docsDir, locale = "en" } = input;
|
|
14
|
+
|
|
15
|
+
if (!path) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Generate filename from document path
|
|
20
|
+
const flatName = pathToFlatName(path);
|
|
21
|
+
const fileName = generateFileName(flatName, locale);
|
|
22
|
+
|
|
23
|
+
// Read document content
|
|
24
|
+
const content = docsDir ? await readFileContent(docsDir, fileName) : null;
|
|
25
|
+
|
|
26
|
+
if (!content) {
|
|
27
|
+
console.warn(`⚠️ Could not read content from ${fileName}`);
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Initialize currentContents[path] in userContext
|
|
32
|
+
const contentContext = userContextAt(options, `currentContents.${path}`);
|
|
33
|
+
contentContext.set(content);
|
|
34
|
+
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
initCurrentContent.task_render_mode = "hide";
|
package/agents/init/index.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
SUPPORTED_LANGUAGES,
|
|
15
15
|
TARGET_AUDIENCES,
|
|
16
16
|
} from "../../utils/constants/index.mjs";
|
|
17
|
+
import { isRemoteFile } from "../../utils/file-utils.mjs";
|
|
17
18
|
import loadConfig from "../../utils/load-config.mjs";
|
|
18
19
|
import {
|
|
19
20
|
detectSystemLanguage,
|
|
@@ -22,9 +23,8 @@ import {
|
|
|
22
23
|
isGlobPattern,
|
|
23
24
|
validatePath,
|
|
24
25
|
} from "../../utils/utils.mjs";
|
|
25
|
-
import { isRemoteFile } from "../../utils/file-utils.mjs";
|
|
26
|
-
import { validateDocDir } from "./validate.mjs";
|
|
27
26
|
import mapReasoningEffortLevel from "../utils/map-reasoning-effort-level.mjs";
|
|
27
|
+
import { validateDocDir } from "./validate.mjs";
|
|
28
28
|
|
|
29
29
|
const _PRESS_ENTER_TO_FINISH = "Press Enter to finish";
|
|
30
30
|
|
|
@@ -362,8 +362,7 @@ async function _init(
|
|
|
362
362
|
continue;
|
|
363
363
|
}
|
|
364
364
|
sourcePaths.push(trimmedPath);
|
|
365
|
-
}
|
|
366
|
-
if (isGlobPatternResult) {
|
|
365
|
+
} else if (isGlobPatternResult) {
|
|
367
366
|
// For glob patterns, just add them without validation
|
|
368
367
|
if (sourcePaths.includes(trimmedPath)) {
|
|
369
368
|
console.log(`⚠️ Pattern already exists: ${trimmedPath}`);
|
|
@@ -4,15 +4,9 @@ import {
|
|
|
4
4
|
getUpdateDocumentContentOutputJsonSchema,
|
|
5
5
|
validateUpdateDocumentContentInput,
|
|
6
6
|
} from "../../../types/document-schema.mjs";
|
|
7
|
+
import { userContextAt } from "../../../utils/utils.mjs";
|
|
7
8
|
|
|
8
9
|
export default async function updateDocumentContent(input, options) {
|
|
9
|
-
// Get originalContent from shared context, fallback to input
|
|
10
|
-
let originalContent = options?.context?.userContext?.currentContent;
|
|
11
|
-
|
|
12
|
-
if (!originalContent) {
|
|
13
|
-
originalContent = input.originalContent;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
10
|
// Validate input using Zod schema
|
|
17
11
|
const validation = validateUpdateDocumentContentInput(input);
|
|
18
12
|
if (!validation.success) {
|
|
@@ -22,7 +16,15 @@ export default async function updateDocumentContent(input, options) {
|
|
|
22
16
|
};
|
|
23
17
|
}
|
|
24
18
|
|
|
25
|
-
const { diffPatch } = validation.data;
|
|
19
|
+
const { diffPatch, path } = validation.data;
|
|
20
|
+
|
|
21
|
+
// Get originalContent from shared context using path, fallback to input
|
|
22
|
+
const contentContext = userContextAt(options, `currentContents.${path}`);
|
|
23
|
+
let originalContent = contentContext.get();
|
|
24
|
+
|
|
25
|
+
if (!originalContent) {
|
|
26
|
+
originalContent = input.originalContent;
|
|
27
|
+
}
|
|
26
28
|
|
|
27
29
|
try {
|
|
28
30
|
// Parse and validate diff patch
|
|
@@ -56,10 +58,8 @@ export default async function updateDocumentContent(input, options) {
|
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
// Update shared context with new content
|
|
60
|
-
|
|
61
|
-
options.context.userContext.currentContent = result;
|
|
62
|
-
}
|
|
61
|
+
// Update shared context with new content using path
|
|
62
|
+
contentContext.set(result);
|
|
63
63
|
|
|
64
64
|
return {
|
|
65
65
|
success: true,
|
|
@@ -3,7 +3,7 @@ name: updateDocumentDetail
|
|
|
3
3
|
description: Update and optimize document content based on user feedback using diff patches
|
|
4
4
|
task_render_mode: collapse
|
|
5
5
|
skills:
|
|
6
|
-
- url: ../utils/analyze-feedback-intent.yaml
|
|
6
|
+
- url: ../utils/analyze-document-feedback-intent.yaml
|
|
7
7
|
- type: ai
|
|
8
8
|
instructions:
|
|
9
9
|
- role: system
|
|
@@ -48,9 +48,13 @@ skills:
|
|
|
48
48
|
needDataSources:
|
|
49
49
|
type: boolean
|
|
50
50
|
description: Whether data sources are needed for content modifications
|
|
51
|
+
path:
|
|
52
|
+
type: string
|
|
53
|
+
description: Document path
|
|
51
54
|
required:
|
|
52
55
|
- originalContent
|
|
53
56
|
- feedback
|
|
57
|
+
- path
|
|
54
58
|
output_key: message
|
|
55
59
|
afs:
|
|
56
60
|
modules:
|
|
@@ -2,6 +2,7 @@ import { AIAgent } from "@aigne/core";
|
|
|
2
2
|
import { pick } from "@aigne/core/utils/type-utils.js";
|
|
3
3
|
import z from "zod";
|
|
4
4
|
import { DIAGRAM_PLACEHOLDER, replacePlaceholder } from "../../../utils/d2-utils.mjs";
|
|
5
|
+
import { userContextAt } from "../../../utils/utils.mjs";
|
|
5
6
|
|
|
6
7
|
async function getIntentType(input, options) {
|
|
7
8
|
const instructions = `<role>
|
|
@@ -47,19 +48,24 @@ async function saveDoc(input, options, { content }) {
|
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
async function addDiagram(input, options) {
|
|
51
|
+
const contentContext = userContextAt(options, `currentContents.${input.path}`);
|
|
52
|
+
const currentContent = contentContext.get();
|
|
50
53
|
const generateDiagramAgent = options.context.agents["checkGenerateDiagram"];
|
|
51
54
|
const generateDiagramResult = await options.context.invoke(generateDiagramAgent, {
|
|
52
55
|
...pick(input, ["locale", "path", "diagramming", "feedback"]),
|
|
53
|
-
documentContent:
|
|
56
|
+
documentContent: currentContent,
|
|
54
57
|
});
|
|
55
58
|
const content = generateDiagramResult.content;
|
|
59
|
+
contentContext.set(content);
|
|
56
60
|
await saveDoc(input, options, { content });
|
|
57
61
|
return { content };
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
async function updateDiagram(input, options) {
|
|
65
|
+
const contentContext = userContextAt(options, `currentContents.${input.path}`);
|
|
66
|
+
const currentContent = contentContext.get();
|
|
61
67
|
let [content, previousDiagramContent] = replacePlaceholder({
|
|
62
|
-
content:
|
|
68
|
+
content: currentContent,
|
|
63
69
|
});
|
|
64
70
|
const generateAgent = options.context?.agents?.["generateDiagram"];
|
|
65
71
|
const { diagramSourceCode } = await options.context.invoke(generateAgent, {
|
|
@@ -69,13 +75,16 @@ async function updateDiagram(input, options) {
|
|
|
69
75
|
feedback: input.feedback,
|
|
70
76
|
});
|
|
71
77
|
content = content.replace(DIAGRAM_PLACEHOLDER, diagramSourceCode);
|
|
78
|
+
contentContext.set(content);
|
|
72
79
|
await saveDoc(input, options, { content });
|
|
73
80
|
return { content };
|
|
74
81
|
}
|
|
75
82
|
|
|
76
83
|
async function deleteDiagram(input, options) {
|
|
84
|
+
const contentContext = userContextAt(options, `currentContents.${input.path}`);
|
|
85
|
+
const currentContent = contentContext.get();
|
|
77
86
|
const [documentContent] = replacePlaceholder({
|
|
78
|
-
content:
|
|
87
|
+
content: currentContent,
|
|
79
88
|
});
|
|
80
89
|
const instructions = `<role>
|
|
81
90
|
Your task is to remove ${DIAGRAM_PLACEHOLDER} and adjust the document context (based on the user's feedback) to make it easier to understand.
|
|
@@ -103,22 +112,28 @@ Your task is to remove ${DIAGRAM_PLACEHOLDER} and adjust the document context (b
|
|
|
103
112
|
documentContent,
|
|
104
113
|
feedback: input.feedback,
|
|
105
114
|
});
|
|
115
|
+
contentContext.set(content);
|
|
106
116
|
await saveDoc(input, options, { content });
|
|
107
117
|
|
|
108
118
|
return { content };
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
async function updateDocument(input, options) {
|
|
122
|
+
const contentContext = userContextAt(options, `currentContents.${input.path}`);
|
|
123
|
+
const currentContent = contentContext.get();
|
|
112
124
|
const updateAgent = options.context.agents["updateDocumentDetail"];
|
|
113
125
|
const updateResult = await options.context.invoke(updateAgent, {
|
|
114
126
|
...input,
|
|
115
|
-
originalContent:
|
|
127
|
+
originalContent: currentContent,
|
|
116
128
|
});
|
|
117
129
|
if (updateResult.message === "success") {
|
|
118
|
-
|
|
130
|
+
const updatedContent = contentContext.get();
|
|
131
|
+
|
|
132
|
+
contentContext.set(updatedContent);
|
|
133
|
+
await saveDoc(input, options, { content: updatedContent });
|
|
119
134
|
}
|
|
120
135
|
return {
|
|
121
|
-
content:
|
|
136
|
+
content: contentContext.get(),
|
|
122
137
|
};
|
|
123
138
|
}
|
|
124
139
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { marked } from "marked";
|
|
2
2
|
import markedTerminal from "marked-terminal";
|
|
3
3
|
import { getActiveRulesForScope } from "../../utils/preferences-utils.mjs";
|
|
4
|
+
import { userContextAt } from "../../utils/utils.mjs";
|
|
4
5
|
|
|
5
6
|
function extractMarkdownHeadings(content) {
|
|
6
7
|
if (!content || typeof content !== "string") {
|
|
@@ -136,8 +137,9 @@ export default async function userReviewDocument({ content, description, ...rest
|
|
|
136
137
|
printDocumentHeadings(content, title || "Untitled Document");
|
|
137
138
|
}
|
|
138
139
|
|
|
139
|
-
// Initialize shared context with current content
|
|
140
|
-
|
|
140
|
+
// Initialize shared context with current content using path
|
|
141
|
+
const contentContext = userContextAt(options, `currentContents.${rest.path}`);
|
|
142
|
+
contentContext.set(content);
|
|
141
143
|
|
|
142
144
|
const MAX_ITERATIONS = 100;
|
|
143
145
|
const feedbacks = [];
|
|
@@ -174,10 +176,7 @@ export default async function userReviewDocument({ content, description, ...rest
|
|
|
174
176
|
if (action === "finish") {
|
|
175
177
|
break;
|
|
176
178
|
} else if (action === "view") {
|
|
177
|
-
await showDocumentDetail(
|
|
178
|
-
options.context.userContext.currentContent,
|
|
179
|
-
title || "Untitled Document",
|
|
180
|
-
);
|
|
179
|
+
await showDocumentDetail(contentContext.get(), title || "Untitled Document");
|
|
181
180
|
}
|
|
182
181
|
|
|
183
182
|
// Ask for feedback
|
|
@@ -218,14 +217,15 @@ export default async function userReviewDocument({ content, description, ...rest
|
|
|
218
217
|
|
|
219
218
|
try {
|
|
220
219
|
// Call updateDocument agent with feedback
|
|
220
|
+
const currentContent = contentContext.get();
|
|
221
221
|
const result = await options.context.invoke(updateAgent, {
|
|
222
222
|
...rest,
|
|
223
|
-
originalContent:
|
|
223
|
+
originalContent: currentContent,
|
|
224
224
|
feedback: feedback.trim(),
|
|
225
225
|
userPreferences,
|
|
226
226
|
title,
|
|
227
227
|
});
|
|
228
|
-
|
|
228
|
+
contentContext.set(result.content);
|
|
229
229
|
|
|
230
230
|
// Check if feedback should be saved as user preference
|
|
231
231
|
const feedbackRefinerAgent = options.context.agents["checkFeedbackRefiner"];
|
|
@@ -242,10 +242,7 @@ export default async function userReviewDocument({ content, description, ...rest
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
// Print updated document headings structure
|
|
245
|
-
printDocumentHeadings(
|
|
246
|
-
options.context.userContext.currentContent,
|
|
247
|
-
title || "Untitled Document",
|
|
248
|
-
);
|
|
245
|
+
printDocumentHeadings(contentContext.get(), title || "Untitled Document");
|
|
249
246
|
|
|
250
247
|
if (rest.isChat) {
|
|
251
248
|
break;
|
|
@@ -267,7 +264,7 @@ export default async function userReviewDocument({ content, description, ...rest
|
|
|
267
264
|
title,
|
|
268
265
|
description,
|
|
269
266
|
...rest,
|
|
270
|
-
content:
|
|
267
|
+
content: contentContext.get(),
|
|
271
268
|
feedback: feedbacks.join(". "),
|
|
272
269
|
};
|
|
273
270
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default function addTranslatesToStructure({
|
|
2
|
+
originalDocumentStructure = [],
|
|
3
|
+
translateLanguages = [],
|
|
4
|
+
}) {
|
|
5
|
+
const documentExecutionStructure = (originalDocumentStructure || []).map((item) => ({
|
|
6
|
+
...item,
|
|
7
|
+
translates: (translateLanguages || []).map((lang) => ({ language: lang })),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
documentExecutionStructure,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
addTranslatesToStructure.inputSchema = {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
originalDocumentStructure: { type: "array", items: { type: "object" } },
|
|
19
|
+
translateLanguages: { type: "array", items: { type: "string" } },
|
|
20
|
+
},
|
|
21
|
+
required: ["originalDocumentStructure", "translateLanguages"],
|
|
22
|
+
};
|
|
23
|
+
addTranslatesToStructure.outputSchema = {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
documentExecutionStructure: { type: "array" },
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
addTranslatesToStructure.task_render_mode = "hide";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: analyzeDocumentFeedbackIntent
|
|
2
2
|
description: Analyze user feedback to determine if data sources are needed for content modifications
|
|
3
3
|
task_render_mode: hide
|
|
4
4
|
instructions:
|
|
5
|
-
url: ../../prompts/utils/analyze-feedback-intent.md
|
|
5
|
+
url: ../../prompts/utils/analyze-document-feedback-intent.md
|
|
6
6
|
input_schema:
|
|
7
7
|
type: object
|
|
8
8
|
properties:
|
|
@@ -23,6 +23,9 @@ output_schema:
|
|
|
23
23
|
reason:
|
|
24
24
|
type: string
|
|
25
25
|
description: Explanation of why data sources are or aren't needed
|
|
26
|
+
error:
|
|
27
|
+
type: boolean
|
|
28
|
+
description: If an error occurs during the analysis process
|
|
26
29
|
required:
|
|
27
30
|
- needDataSources
|
|
28
31
|
- intentType
|