@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.
Files changed (41) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/agents/create/document-structure-tools/delete-document.mjs +53 -9
  3. package/agents/create/update-document-structure.yaml +1 -1
  4. package/agents/create/user-add-document/add-documents-to-structure.mjs +96 -0
  5. package/agents/create/user-add-document/find-documents-to-add-links.yaml +47 -0
  6. package/agents/create/user-add-document/index.yaml +46 -0
  7. package/agents/create/user-add-document/prepare-documents-to-translate.mjs +22 -0
  8. package/agents/create/user-add-document/print-add-document-summary.mjs +63 -0
  9. package/agents/create/user-add-document/review-documents-with-new-links.mjs +110 -0
  10. package/agents/create/user-remove-document/find-documents-with-invalid-links.mjs +78 -0
  11. package/agents/create/user-remove-document/index.yaml +41 -0
  12. package/agents/create/user-remove-document/prepare-documents-to-translate.mjs +22 -0
  13. package/agents/create/user-remove-document/print-remove-document-summary.mjs +53 -0
  14. package/agents/create/user-remove-document/remove-documents-from-structure.mjs +99 -0
  15. package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +119 -0
  16. package/agents/create/user-review-document-structure.mjs +1 -40
  17. package/agents/create/utils/init-current-content.mjs +38 -0
  18. package/agents/init/index.mjs +3 -4
  19. package/agents/update/document-tools/update-document-content.mjs +12 -12
  20. package/agents/update/update-document-detail.yaml +5 -1
  21. package/agents/update/update-single/update-single-document-detail.mjs +21 -6
  22. package/agents/update/user-review-document.mjs +10 -13
  23. package/agents/utils/add-translates-to-structure.mjs +29 -0
  24. package/agents/utils/{analyze-feedback-intent.yaml → analyze-document-feedback-intent.yaml} +5 -2
  25. package/agents/utils/analyze-structure-feedback-intent.yaml +29 -0
  26. package/agents/utils/check-detail-result.mjs +2 -14
  27. package/agents/utils/load-sources.mjs +36 -46
  28. package/aigne.yaml +10 -1
  29. package/package.json +1 -1
  30. package/prompts/detail/custom/custom-components/x-cards-usage-rules.md +18 -10
  31. package/prompts/structure/find-documents-to-add-links.md +52 -0
  32. package/prompts/utils/analyze-document-feedback-intent.md +54 -0
  33. package/prompts/utils/analyze-structure-feedback-intent.md +43 -0
  34. package/types/document-schema.mjs +2 -0
  35. package/types/document-structure-schema.mjs +6 -2
  36. package/utils/docs-finder-utils.mjs +161 -0
  37. package/utils/file-utils.mjs +9 -7
  38. package/utils/load-config.mjs +21 -4
  39. package/utils/markdown-checker.mjs +50 -5
  40. package/utils/utils.mjs +103 -0
  41. 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 { buildDocumentTree } from "../../utils/docs-finder-utils.mjs";
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";
@@ -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 if options is provided
60
- if (options?.context?.userContext) {
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: options.context.userContext.currentContent,
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: options.context.userContext.currentContent,
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: options.context.userContext.currentContent,
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: options.context.userContext.currentContent,
127
+ originalContent: currentContent,
116
128
  });
117
129
  if (updateResult.message === "success") {
118
- await saveDoc(input, options, { content: options.context.userContext.currentContent });
130
+ const updatedContent = contentContext.get();
131
+
132
+ contentContext.set(updatedContent);
133
+ await saveDoc(input, options, { content: updatedContent });
119
134
  }
120
135
  return {
121
- content: options.context.userContext.currentContent,
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
- options.context.userContext.currentContent = content;
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: options.context.userContext.currentContent,
223
+ originalContent: currentContent,
224
224
  feedback: feedback.trim(),
225
225
  userPreferences,
226
226
  title,
227
227
  });
228
- options.context.userContext.currentContent = result.content;
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: options.context.userContext.currentContent,
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: analyzeFeedbackIntent
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