@aigne/doc-smith 0.9.5 → 0.9.6-beta.1

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 (43) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/agents/create/document-structure-tools/delete-document.mjs +32 -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 +56 -0
  9. package/agents/create/user-add-document/review-documents-with-new-links.mjs +73 -0
  10. package/agents/create/user-remove-document/find-documents-with-invalid-links.mjs +67 -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 +56 -0
  14. package/agents/create/user-remove-document/remove-documents-from-structure.mjs +96 -0
  15. package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +116 -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/check.mjs +1 -1
  19. package/agents/update/check-generate-diagram.mjs +4 -3
  20. package/agents/update/document-tools/update-document-content.mjs +12 -12
  21. package/agents/update/update-document-detail.yaml +5 -1
  22. package/agents/update/update-single/update-single-document-detail.mjs +155 -0
  23. package/agents/update/user-review-document.mjs +11 -14
  24. package/agents/utils/add-translates-to-structure.mjs +29 -0
  25. package/agents/utils/{analyze-feedback-intent.yaml → analyze-document-feedback-intent.yaml} +5 -2
  26. package/agents/utils/analyze-structure-feedback-intent.yaml +29 -0
  27. package/agents/utils/check-detail-result.mjs +2 -14
  28. package/aigne.yaml +11 -1
  29. package/package.json +1 -1
  30. package/prompts/detail/diagram/user-prompt.md +17 -0
  31. package/prompts/detail/generate/system-prompt.md +0 -1
  32. package/prompts/detail/update/system-prompt.md +40 -32
  33. package/prompts/structure/find-documents-to-add-links.md +52 -0
  34. package/prompts/utils/analyze-document-feedback-intent.md +54 -0
  35. package/prompts/utils/analyze-structure-feedback-intent.md +43 -0
  36. package/types/document-schema.mjs +2 -0
  37. package/types/document-structure-schema.mjs +6 -2
  38. package/utils/auth-utils.mjs +32 -16
  39. package/utils/d2-utils.mjs +13 -0
  40. package/utils/docs-finder-utils.mjs +82 -0
  41. package/utils/markdown-checker.mjs +50 -5
  42. package/utils/utils.mjs +103 -0
  43. package/prompts/utils/analyze-feedback-intent.md +0 -55
@@ -0,0 +1,96 @@
1
+ import chooseDocs from "../../utils/choose-docs.mjs";
2
+ import deleteDocument from "../document-structure-tools/delete-document.mjs";
3
+ import { DOC_ACTION } from "../../../utils/constants/index.mjs";
4
+ import addTranslatesToStructure from "../../utils/add-translates-to-structure.mjs";
5
+
6
+ export default async function removeDocumentsFromStructure(input = {}, options = {}) {
7
+ const { docsDir, locale = "en", translateLanguages = [], originalDocumentStructure } = input;
8
+
9
+ if (!Array.isArray(originalDocumentStructure) || originalDocumentStructure.length === 0) {
10
+ console.warn(
11
+ "🗑️ Remove Documents\n • No document structure found. Please generate documents first.",
12
+ );
13
+ process.exit(0);
14
+ }
15
+
16
+ const { documentExecutionStructure } = addTranslatesToStructure({
17
+ originalDocumentStructure,
18
+ translateLanguages,
19
+ });
20
+
21
+ // Initialize currentStructure in userContext
22
+ options.context.userContext.currentStructure = [...originalDocumentStructure];
23
+
24
+ // Use chooseDocs to select documents to delete
25
+ const chooseResult = await chooseDocs(
26
+ {
27
+ docs: [],
28
+ documentExecutionStructure,
29
+ docsDir,
30
+ locale,
31
+ isTranslate: false,
32
+ feedback: "no feedback",
33
+ requiredFeedback: false,
34
+ action: DOC_ACTION.clear,
35
+ },
36
+ options,
37
+ );
38
+
39
+ if (!chooseResult?.selectedDocs || chooseResult.selectedDocs.length === 0) {
40
+ console.log("No documents selected for removal.");
41
+ process.exit(0);
42
+ }
43
+
44
+ // Delete each selected document
45
+ const deletedDocuments = [];
46
+ const errors = [];
47
+
48
+ for (const selectedDoc of chooseResult.selectedDocs) {
49
+ try {
50
+ const deleteResult = await deleteDocument(
51
+ {
52
+ path: selectedDoc.path,
53
+ recursive: true,
54
+ },
55
+ options,
56
+ );
57
+
58
+ if (deleteResult.error) {
59
+ errors.push({
60
+ path: selectedDoc.path,
61
+ error: deleteResult.error.message,
62
+ });
63
+ } else {
64
+ // deletedDocuments is now always an array
65
+ deletedDocuments.push(...deleteResult.deletedDocuments);
66
+ }
67
+ } catch (error) {
68
+ errors.push({
69
+ path: selectedDoc.path,
70
+ error: error.message,
71
+ });
72
+ }
73
+ }
74
+
75
+ if (errors.length > 0) {
76
+ console.warn(
77
+ `🗑️ Remove Documents\n • Failed to remove documents:\n${errors
78
+ .map((e) => ` - ${e.path}: ${e.error}`)
79
+ .join("\n")}`,
80
+ );
81
+ process.exit(0);
82
+ }
83
+
84
+ // Get updated document structure
85
+ const updatedStructure = options.context.userContext.currentStructure;
86
+
87
+ return {
88
+ documentStructure: updatedStructure,
89
+ originalDocumentStructure: JSON.parse(JSON.stringify(updatedStructure)),
90
+ deletedDocuments,
91
+ };
92
+ }
93
+
94
+ removeDocumentsFromStructure.taskTitle = "Remove documents from structure";
95
+ removeDocumentsFromStructure.description =
96
+ "Select and remove documents from the documentation structure";
@@ -0,0 +1,116 @@
1
+ import { buildAllowedLinksFromStructure } from "../../../utils/docs-finder-utils.mjs";
2
+
3
+ /**
4
+ * Generate feedback message for fixing invalid links in a document
5
+ */
6
+ function generateInvalidLinksFeedback(invalidLinks, documentPath, documentExecutionStructure) {
7
+ const invalidLinksList = invalidLinks.map((link) => `- ${link}`).join("\n");
8
+
9
+ // Build allowed links from document structure for replacement suggestions
10
+ const allowedLinks = buildAllowedLinksFromStructure(documentExecutionStructure);
11
+ const allowedLinksArray = Array.from(allowedLinks)
12
+ .filter((link) => link !== documentPath) // Exclude current document path
13
+ .sort();
14
+
15
+ const allowedLinksList =
16
+ allowedLinksArray.length > 0
17
+ ? allowedLinksArray.map((link) => `- ${link}`).join("\n")
18
+ : "(No available links)";
19
+
20
+ return `This document contains invalid links that need to be fixed. Please handle them according to the following instructions:
21
+
22
+ **Invalid Links Found:**
23
+ ${invalidLinksList}
24
+
25
+ **Available Valid Links:**
26
+ ${allowedLinksList}
27
+
28
+ **Instructions for fixing invalid links:**
29
+
30
+ 1. For each invalid link found in the document:
31
+ - Using the document context and the list of available valid links, try to find a suitable replacement link from the available valid links.
32
+ - When choosing a replacement, exclude the current document path (${documentPath}); linking to the current document is not logical.
33
+ - **Do not consider the original invalid link or its related text**; they are outdated and should be replaced.
34
+
35
+ 2. If a suitable replacement link is found:
36
+ - 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.
37
+ - 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.
38
+
39
+ 3. If no suitable replacement link can be found:
40
+ - Remove the invalid link completely, including the link text and any associated content that only makes sense with that link.
41
+ - **Do not affect other unrelated content** in the document; only remove content that is directly tied to the invalid link.
42
+
43
+ 4. Ensure the document remains coherent and readable after the changes.`;
44
+ }
45
+
46
+ export default async function reviewDocumentsWithInvalidLinks(input = {}, options = {}) {
47
+ const { documentsWithInvalidLinks = [], documentExecutionStructure = [] } = input;
48
+
49
+ // If no documents with invalid links, return empty array
50
+ if (!Array.isArray(documentsWithInvalidLinks) || documentsWithInvalidLinks.length === 0) {
51
+ return {
52
+ documentsWithInvalidLinks: [],
53
+ };
54
+ }
55
+
56
+ // Create choices for user selection, default all checked
57
+ const choices = documentsWithInvalidLinks.map((doc) => {
58
+ const invalidLinksText =
59
+ doc.invalidLinks && doc.invalidLinks.length > 0
60
+ ? ` (${doc.invalidLinks.length} invalid link${doc.invalidLinks.length > 1 ? "s" : ""})`
61
+ : "";
62
+
63
+ return {
64
+ name: `${doc.title || doc.path}${invalidLinksText}`,
65
+ value: doc.path,
66
+ checked: true, // Default all selected
67
+ description: `Invalid Links: ${doc.invalidLinks.join(", ")}`,
68
+ };
69
+ });
70
+
71
+ // Let user select documents (default all selected)
72
+ const selectedPaths = await options.prompts.checkbox({
73
+ message:
74
+ "Select documents with invalid links to fix (all selected by default, press Enter to confirm, or unselect all to skip):",
75
+ choices,
76
+ });
77
+
78
+ // Filter documents based on user selection
79
+ const selectedPathsSet = new Set(selectedPaths);
80
+ const filteredDocs = documentsWithInvalidLinks.filter((doc) => selectedPathsSet.has(doc.path));
81
+
82
+ if (filteredDocs.length === 0) {
83
+ return {
84
+ documentsWithInvalidLinks: [],
85
+ documentsToUpdate: [],
86
+ };
87
+ }
88
+
89
+ // Prepare documents: add necessary fields for update (without content)
90
+ const preparedDocs = [];
91
+
92
+ for (const doc of filteredDocs) {
93
+ if (!doc.path) continue;
94
+
95
+ // Find corresponding document in documentStructure to get additional fields
96
+ const structureDoc = documentExecutionStructure.find((item) => item.path === doc.path);
97
+
98
+ // Generate feedback message for fixing invalid links
99
+ const feedback = generateInvalidLinksFeedback(
100
+ doc.invalidLinks,
101
+ doc.path,
102
+ documentExecutionStructure,
103
+ );
104
+
105
+ preparedDocs.push({
106
+ ...structureDoc,
107
+ feedback,
108
+ invalidLinks: doc.invalidLinks,
109
+ });
110
+ }
111
+
112
+ return {
113
+ documentsWithInvalidLinks: preparedDocs, // for print summary
114
+ documentsToUpdate: JSON.parse(JSON.stringify(preparedDocs)), // for batch update
115
+ };
116
+ }
@@ -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";
@@ -11,6 +11,6 @@ export default async function checkNeedGenerate({ docsDir, locale, documentExecu
11
11
  process.exit(0);
12
12
  }
13
13
  return {
14
- message: 'Documents found in the docs directory, skipping "generate" step',
14
+ message: 'Documents found in the docs directory, skipping "create" step',
15
15
  };
16
16
  }
@@ -1,4 +1,5 @@
1
- const PLACEHOLDER = "DIAGRAM_PLACEHOLDER";
1
+ import { DIAGRAM_PLACEHOLDER } from "../../utils/d2-utils.mjs";
2
+
2
3
  const DEFAULT_DIAGRAMMING_EFFORT = 5;
3
4
  const MIN_DIAGRAMMING_EFFORT = 0;
4
5
  const MAX_DIAGRAMMING_EFFORT = 10;
@@ -66,8 +67,8 @@ export default async function checkGenerateDiagram(
66
67
  }
67
68
 
68
69
  if (diagramSourceCode && !skipGenerateDiagram) {
69
- if (content.includes(PLACEHOLDER)) {
70
- content = content.replace(PLACEHOLDER, diagramSourceCode);
70
+ if (content.includes(DIAGRAM_PLACEHOLDER)) {
71
+ content = content.replace(DIAGRAM_PLACEHOLDER, diagramSourceCode);
71
72
  } else {
72
73
  const mergeAgent = options.context?.agents?.["mergeDiagramToDocument"];
73
74
  ({ content } = await options.context.invoke(mergeAgent, {
@@ -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:
@@ -0,0 +1,155 @@
1
+ import { AIAgent } from "@aigne/core";
2
+ import { pick } from "@aigne/core/utils/type-utils.js";
3
+ import z from "zod";
4
+ import { DIAGRAM_PLACEHOLDER, replacePlaceholder } from "../../../utils/d2-utils.mjs";
5
+ import { userContextAt } from "../../../utils/utils.mjs";
6
+
7
+ async function getIntentType(input, options) {
8
+ const instructions = `<role>
9
+ You are a feedback intent analyzer. Your task is to determine which type of content modifications are needed based on the user's feedback.
10
+ </role>
11
+
12
+ <user_feedback>
13
+ {{feedback}}
14
+ </user_feedback>`;
15
+ const analyzeUpdateFeedbackIntentAgent = AIAgent.from({
16
+ name: "analyzeUpdateFeedbackIntent",
17
+ description:
18
+ "Analyze user feedback to determine if document are needed for content modifications",
19
+ task_render_mode: "hide",
20
+ instructions,
21
+ // TODO: can't set reasoningEffort
22
+ // modelOptions: {
23
+ // reasoningEffort: 1,
24
+ // },
25
+ inputSchema: z.object({
26
+ feedback: z.string().describe("User feedback for content modifications"),
27
+ }),
28
+ outputSchema: z.object({
29
+ intentType: z
30
+ .enum(["addDiagram", "deleteDiagram", "updateDiagram", "updateDocument"])
31
+ .describe(
32
+ "The primary type of user intention: one of addDiagram, deleteDiagram, updateDiagram, updateDocument",
33
+ ),
34
+ }),
35
+ });
36
+ const { intentType } = await options.context.invoke(analyzeUpdateFeedbackIntentAgent, {
37
+ feedback: input.feedback,
38
+ });
39
+ return intentType;
40
+ }
41
+
42
+ async function saveDoc(input, options, { content }) {
43
+ const saveAgent = options.context?.agents?.["saveDoc"];
44
+ await options.context.invoke(saveAgent, {
45
+ ...pick(input, ["path", "docsDir", "labels", "locale"]),
46
+ content,
47
+ });
48
+ }
49
+
50
+ async function addDiagram(input, options) {
51
+ const contentContext = userContextAt(options, `currentContents.${input.path}`);
52
+ const currentContent = contentContext.get();
53
+ const generateDiagramAgent = options.context.agents["checkGenerateDiagram"];
54
+ const generateDiagramResult = await options.context.invoke(generateDiagramAgent, {
55
+ ...pick(input, ["locale", "path", "diagramming", "feedback"]),
56
+ documentContent: currentContent,
57
+ });
58
+ const content = generateDiagramResult.content;
59
+ contentContext.set(content);
60
+ await saveDoc(input, options, { content });
61
+ return { content };
62
+ }
63
+
64
+ async function updateDiagram(input, options) {
65
+ const contentContext = userContextAt(options, `currentContents.${input.path}`);
66
+ const currentContent = contentContext.get();
67
+ let [content, previousDiagramContent] = replacePlaceholder({
68
+ content: currentContent,
69
+ });
70
+ const generateAgent = options.context?.agents?.["generateDiagram"];
71
+ const { diagramSourceCode } = await options.context.invoke(generateAgent, {
72
+ documentContent: content,
73
+ locale: input.locale,
74
+ previousDiagramContent,
75
+ feedback: input.feedback,
76
+ });
77
+ content = content.replace(DIAGRAM_PLACEHOLDER, diagramSourceCode);
78
+ contentContext.set(content);
79
+ await saveDoc(input, options, { content });
80
+ return { content };
81
+ }
82
+
83
+ async function deleteDiagram(input, options) {
84
+ const contentContext = userContextAt(options, `currentContents.${input.path}`);
85
+ const currentContent = contentContext.get();
86
+ const [documentContent] = replacePlaceholder({
87
+ content: currentContent,
88
+ });
89
+ const instructions = `<role>
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.
91
+ </role>
92
+
93
+ <document_content>
94
+ {{documentContent}}
95
+ </document_content>
96
+
97
+ <user_feedback>
98
+ {{feedback}}
99
+ </user_feedback>`;
100
+ const deleteAgent = AIAgent.from({
101
+ name: "deleteDiagram",
102
+ description: "Remove a diagram from the document content",
103
+ task_render_mode: "hide",
104
+ instructions,
105
+ inputSchema: z.object({
106
+ documentContent: z.string().describe("Source content of the document"),
107
+ feedback: z.string().describe("User feedback for content modifications"),
108
+ }),
109
+ outputKey: "message",
110
+ });
111
+ const { message: content } = await options.context.invoke(deleteAgent, {
112
+ documentContent,
113
+ feedback: input.feedback,
114
+ });
115
+ contentContext.set(content);
116
+ await saveDoc(input, options, { content });
117
+
118
+ return { content };
119
+ }
120
+
121
+ async function updateDocument(input, options) {
122
+ const contentContext = userContextAt(options, `currentContents.${input.path}`);
123
+ const currentContent = contentContext.get();
124
+ const updateAgent = options.context.agents["updateDocumentDetail"];
125
+ const updateResult = await options.context.invoke(updateAgent, {
126
+ ...input,
127
+ originalContent: currentContent,
128
+ });
129
+ if (updateResult.message === "success") {
130
+ const updatedContent = contentContext.get();
131
+
132
+ contentContext.set(updatedContent);
133
+ await saveDoc(input, options, { content: updatedContent });
134
+ }
135
+ return {
136
+ content: contentContext.get(),
137
+ };
138
+ }
139
+
140
+ export default async function updateSingleDocumentDetail(input, options) {
141
+ const intentType = await getIntentType(input, options);
142
+
143
+ const fnMap = {
144
+ addDiagram,
145
+ updateDiagram,
146
+ deleteDiagram,
147
+ updateDocument,
148
+ };
149
+
150
+ if (fnMap[intentType]) {
151
+ const result = await fnMap[intentType](input, options);
152
+ return result;
153
+ }
154
+ return {};
155
+ }
@@ -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
@@ -200,7 +199,7 @@ export default async function userReviewDocument({ content, description, ...rest
200
199
  }
201
200
 
202
201
  // Get the updateDocument agent
203
- const updateAgent = options.context.agents["handleDocumentUpdate"];
202
+ const updateAgent = options.context.agents["updateSingleDocumentDetail"];
204
203
  if (!updateAgent) {
205
204
  console.log(
206
205
  "We can't process your feedback right now. The document update feature is temporarily unavailable.",
@@ -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