@aigne/doc-smith 0.9.7 → 0.9.8-beta
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 +13 -0
- package/agents/create/analyze-diagram-type-llm.yaml +160 -0
- package/agents/create/analyze-diagram-type.mjs +297 -0
- package/agents/create/generate-diagram-image.yaml +60 -0
- package/agents/create/replace-d2-with-image.mjs +624 -0
- package/agents/create/utils/init-current-content.mjs +5 -9
- package/agents/evaluate/document.yaml +6 -0
- package/agents/evaluate/index.yaml +1 -0
- package/agents/init/index.mjs +16 -0
- package/agents/media/batch-generate-media-description.yaml +2 -0
- package/agents/media/generate-media-description.yaml +3 -0
- package/agents/media/load-media-description.mjs +44 -15
- package/agents/publish/publish-docs.mjs +1 -4
- package/agents/update/check-diagram-flag.mjs +116 -0
- package/agents/update/check-document.mjs +0 -1
- package/agents/update/check-generate-diagram.mjs +48 -30
- package/agents/update/check-sync-image-flag.mjs +55 -0
- package/agents/update/check-update-is-single.mjs +11 -0
- package/agents/update/generate-diagram.yaml +43 -9
- package/agents/update/generate-document.yaml +9 -0
- package/agents/update/handle-document-update.yaml +10 -8
- package/agents/update/index.yaml +16 -1
- package/agents/update/sync-images-and-exit.mjs +148 -0
- package/agents/update/update-single/update-single-document-detail.mjs +131 -17
- package/agents/utils/analyze-feedback-intent.mjs +136 -0
- package/agents/utils/choose-docs.mjs +183 -40
- package/agents/utils/generate-document-or-skip.mjs +41 -0
- package/agents/utils/handle-diagram-operations.mjs +263 -0
- package/agents/utils/load-all-document-content.mjs +30 -0
- package/agents/utils/load-sources.mjs +2 -2
- package/agents/utils/read-current-document-content.mjs +46 -0
- package/agents/utils/save-doc.mjs +42 -0
- package/agents/utils/skip-if-content-exists.mjs +27 -0
- package/aigne.yaml +6 -1
- package/assets/report-template/report.html +17 -17
- package/docs-mcp/read-doc-content.mjs +30 -1
- package/package.json +4 -4
- package/prompts/detail/diagram/generate-image-system.md +135 -0
- package/prompts/detail/diagram/generate-image-user.md +32 -0
- package/prompts/detail/generate/user-prompt.md +27 -13
- package/prompts/evaluate/document.md +23 -10
- package/prompts/media/media-description/system-prompt.md +10 -2
- package/prompts/media/media-description/user-prompt.md +9 -0
- package/utils/check-document-has-diagram.mjs +97 -0
- package/utils/constants/index.mjs +46 -0
- package/utils/d2-utils.mjs +114 -181
- package/utils/delete-diagram-images.mjs +103 -0
- package/utils/docs-finder-utils.mjs +34 -1
- package/utils/image-compress.mjs +75 -0
- package/utils/kroki-utils.mjs +2 -3
- package/utils/sync-diagram-to-translations.mjs +258 -0
- package/utils/utils.mjs +24 -0
- package/agents/create/check-diagram.mjs +0 -40
- package/agents/create/draw-diagram.yaml +0 -27
- package/agents/create/merge-diagram.yaml +0 -39
- package/agents/create/wrap-diagram-code.mjs +0 -35
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { syncDiagramToTranslations } from "../../utils/sync-diagram-to-translations.mjs";
|
|
2
|
+
import { readFileContent } from "../../utils/docs-finder-utils.mjs";
|
|
3
|
+
import { getFileName } from "../../utils/utils.mjs";
|
|
4
|
+
import { debug } from "../../utils/debug.mjs";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Sync images to translations and exit if shouldSyncImages is true
|
|
8
|
+
* Otherwise, passes through input for normal update flow
|
|
9
|
+
*
|
|
10
|
+
* This agent combines:
|
|
11
|
+
* - Image synchronization logic
|
|
12
|
+
* - Flow routing (sync vs normal update)
|
|
13
|
+
* - Early exit handling
|
|
14
|
+
*/
|
|
15
|
+
export default async function syncImagesAndExit(input, options) {
|
|
16
|
+
// If shouldSyncImages is false, pass through for normal update flow
|
|
17
|
+
if (!input.shouldSyncImages) {
|
|
18
|
+
return input;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Sync images flow
|
|
22
|
+
const { selectedDocs = [], docsDir, locale = "en" } = input;
|
|
23
|
+
|
|
24
|
+
if (!docsDir) {
|
|
25
|
+
throw new Error("docsDir is required for image sync. Please ensure config is loaded.");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!Array.isArray(selectedDocs) || selectedDocs.length === 0) {
|
|
29
|
+
const actionSuccessAgent = options.context?.agents?.["actionSuccess"];
|
|
30
|
+
if (actionSuccessAgent) {
|
|
31
|
+
await options.context.invoke(actionSuccessAgent, {
|
|
32
|
+
action: "ℹ️ No documents selected for image sync",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// Exit normally to prevent passing to next steps
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const results = {
|
|
40
|
+
updated: 0,
|
|
41
|
+
skipped: 0,
|
|
42
|
+
errors: [],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Process each document
|
|
46
|
+
for (const doc of selectedDocs) {
|
|
47
|
+
try {
|
|
48
|
+
// Use content from doc if available, otherwise read from file
|
|
49
|
+
let mainContent = doc.content;
|
|
50
|
+
if (!mainContent) {
|
|
51
|
+
const mainFileName = getFileName(doc.path, locale);
|
|
52
|
+
mainContent = await readFileContent(docsDir, mainFileName);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!mainContent) {
|
|
56
|
+
debug(`⚠️ Could not read main document: ${doc.path}`);
|
|
57
|
+
results.skipped++;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Sync images to translation documents
|
|
62
|
+
const syncResult = await syncDiagramToTranslations(mainContent, doc.path, docsDir, locale);
|
|
63
|
+
|
|
64
|
+
results.updated += syncResult.updated;
|
|
65
|
+
results.skipped += syncResult.skipped;
|
|
66
|
+
results.errors.push(...syncResult.errors);
|
|
67
|
+
|
|
68
|
+
if (syncResult.updated > 0) {
|
|
69
|
+
debug(`✅ Synced images from ${doc.path} to ${syncResult.updated} translation file(s)`);
|
|
70
|
+
} else if (syncResult.skipped > 0) {
|
|
71
|
+
debug(
|
|
72
|
+
`⏭️ No changes needed for ${doc.path} (${syncResult.skipped} translation file(s) already in sync)`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
debug(`❌ Error syncing images for ${doc.path}: ${error.message}`);
|
|
77
|
+
results.errors.push({
|
|
78
|
+
doc: doc.path,
|
|
79
|
+
error: error.message,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Generate success message
|
|
85
|
+
const message = `✅ Image sync completed: ${results.updated} translation file(s) updated, ${results.skipped} skipped${
|
|
86
|
+
results.errors.length > 0 ? `, ${results.errors.length} error(s)` : ""
|
|
87
|
+
}`;
|
|
88
|
+
|
|
89
|
+
// Show success message
|
|
90
|
+
const actionSuccessAgent = options.context?.agents?.["actionSuccess"];
|
|
91
|
+
if (actionSuccessAgent) {
|
|
92
|
+
await options.context.invoke(actionSuccessAgent, {
|
|
93
|
+
action: message,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Exit normally to prevent passing to next steps and avoid validation errors
|
|
98
|
+
// This ensures a clean exit after successful image sync
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
syncImagesAndExit.input_schema = {
|
|
103
|
+
type: "object",
|
|
104
|
+
properties: {
|
|
105
|
+
shouldSyncImages: {
|
|
106
|
+
type: "boolean",
|
|
107
|
+
description: "Whether to trigger image sync to translations",
|
|
108
|
+
},
|
|
109
|
+
selectedDocs: {
|
|
110
|
+
type: "array",
|
|
111
|
+
description: "Array of selected documents to sync images from",
|
|
112
|
+
},
|
|
113
|
+
docsDir: {
|
|
114
|
+
type: "string",
|
|
115
|
+
description: "Documentation directory where documents are stored",
|
|
116
|
+
},
|
|
117
|
+
locale: {
|
|
118
|
+
type: "string",
|
|
119
|
+
description: "Main language locale (e.g., 'en', 'zh')",
|
|
120
|
+
default: "en",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
required: ["shouldSyncImages"],
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
syncImagesAndExit.output_schema = {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
message: {
|
|
130
|
+
type: "string",
|
|
131
|
+
description: "Summary message of the sync operation",
|
|
132
|
+
},
|
|
133
|
+
updated: {
|
|
134
|
+
type: "number",
|
|
135
|
+
description: "Number of translation files successfully updated",
|
|
136
|
+
},
|
|
137
|
+
skipped: {
|
|
138
|
+
type: "number",
|
|
139
|
+
description: "Number of translation files skipped (no changes needed)",
|
|
140
|
+
},
|
|
141
|
+
errors: {
|
|
142
|
+
type: "array",
|
|
143
|
+
description: "Array of errors encountered during sync",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
syncImagesAndExit.task_render_mode = "hide";
|
|
@@ -4,18 +4,72 @@ import z from "zod";
|
|
|
4
4
|
import {
|
|
5
5
|
DIAGRAM_PLACEHOLDER,
|
|
6
6
|
replaceD2WithPlaceholder,
|
|
7
|
-
|
|
7
|
+
replaceDiagramsWithPlaceholder,
|
|
8
8
|
} from "../../../utils/d2-utils.mjs";
|
|
9
9
|
import { userContextAt } from "../../../utils/utils.mjs";
|
|
10
10
|
|
|
11
11
|
async function getIntentType(input, options) {
|
|
12
12
|
const instructions = `<role>
|
|
13
13
|
You are a feedback intent analyzer. Your task is to determine which type of content modifications are needed based on the user's feedback.
|
|
14
|
+
|
|
15
|
+
You must analyze the user's feedback and classify it into one of the following intent types:
|
|
16
|
+
- addDiagram: User wants to add a new diagram/image/chart
|
|
17
|
+
- deleteDiagram: User wants to remove/delete a diagram/image/chart
|
|
18
|
+
- updateDiagram: User wants to modify/update an existing diagram/image/chart
|
|
19
|
+
- updateDocument: User wants to update document content (text, sections, etc.) without diagram operations
|
|
14
20
|
</role>
|
|
15
21
|
|
|
22
|
+
<intent_classification_rules>
|
|
23
|
+
**deleteDiagram** - Use this when user explicitly wants to remove or delete a diagram/image/chart:
|
|
24
|
+
- Keywords: remove, delete, 删除, 移除, 去掉, 清除
|
|
25
|
+
- Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图, 架构图
|
|
26
|
+
- Examples:
|
|
27
|
+
- "Remove the diagram"
|
|
28
|
+
- "Delete the image"
|
|
29
|
+
- "删除这张图片"
|
|
30
|
+
- "Remove the second diagram"
|
|
31
|
+
- "去掉架构图"
|
|
32
|
+
- "Remove image from page 3"
|
|
33
|
+
- "Delete the chart showing the flow"
|
|
34
|
+
|
|
35
|
+
**addDiagram** - Use this when user wants to add a new diagram:
|
|
36
|
+
- Keywords: add, create, insert, 添加, 创建, 插入
|
|
37
|
+
- Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图
|
|
38
|
+
- Examples:
|
|
39
|
+
- "Add a diagram showing the architecture"
|
|
40
|
+
- "Create a flow chart"
|
|
41
|
+
- "添加一个架构图"
|
|
42
|
+
|
|
43
|
+
**updateDiagram** - Use this when user wants to modify an existing diagram:
|
|
44
|
+
- Keywords: update, modify, change, improve, 更新, 修改, 改进
|
|
45
|
+
- Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图
|
|
46
|
+
- Examples:
|
|
47
|
+
- "Update the diagram to show the new process"
|
|
48
|
+
- "Modify the chart to include more details"
|
|
49
|
+
- "更新架构图"
|
|
50
|
+
|
|
51
|
+
**updateDocument** - Use this for all other content modifications:
|
|
52
|
+
- Text changes, section updates, content improvements
|
|
53
|
+
- No mention of diagrams/images/charts
|
|
54
|
+
- Examples:
|
|
55
|
+
- "Update the introduction section"
|
|
56
|
+
- "Fix the typo in paragraph 2"
|
|
57
|
+
- "Improve the explanation"
|
|
58
|
+
</intent_classification_rules>
|
|
59
|
+
|
|
16
60
|
<user_feedback>
|
|
17
61
|
{{feedback}}
|
|
18
|
-
</user_feedback
|
|
62
|
+
</user_feedback>
|
|
63
|
+
|
|
64
|
+
<analysis_guidelines>
|
|
65
|
+
1. Pay close attention to action verbs (remove, delete, add, update, etc.)
|
|
66
|
+
2. Identify the target object (diagram, image, chart, or general content)
|
|
67
|
+
3. If feedback mentions removing/deleting a diagram/image/chart → deleteDiagram
|
|
68
|
+
4. If feedback mentions adding a diagram/image/chart → addDiagram
|
|
69
|
+
5. If feedback mentions updating a diagram/image/chart → updateDiagram
|
|
70
|
+
6. If feedback is about general content without diagram references → updateDocument
|
|
71
|
+
7. When in doubt, prioritize the most explicit action mentioned in the feedback
|
|
72
|
+
</analysis_guidelines>`;
|
|
19
73
|
const analyzeUpdateFeedbackIntentAgent = AIAgent.from({
|
|
20
74
|
name: "analyzeUpdateFeedbackIntent",
|
|
21
75
|
description:
|
|
@@ -43,11 +97,12 @@ You are a feedback intent analyzer. Your task is to determine which type of cont
|
|
|
43
97
|
return intentType;
|
|
44
98
|
}
|
|
45
99
|
|
|
46
|
-
async function saveDoc(input, options, { content }) {
|
|
100
|
+
async function saveDoc(input, options, { content, intentType }) {
|
|
47
101
|
const saveAgent = options.context?.agents?.["saveDoc"];
|
|
48
102
|
await options.context.invoke(saveAgent, {
|
|
49
103
|
...pick(input, ["path", "docsDir", "labels", "locale"]),
|
|
50
104
|
content,
|
|
105
|
+
intentType, // Pass intentType so saveDoc can handle translation sync
|
|
51
106
|
});
|
|
52
107
|
}
|
|
53
108
|
|
|
@@ -56,42 +111,70 @@ async function addDiagram(input, options) {
|
|
|
56
111
|
const currentContent = contentContext.get();
|
|
57
112
|
const generateDiagramAgent = options.context.agents["checkGenerateDiagram"];
|
|
58
113
|
const generateDiagramResult = await options.context.invoke(generateDiagramAgent, {
|
|
59
|
-
...pick(input, ["locale", "path", "diagramming", "feedback"]),
|
|
114
|
+
...pick(input, ["locale", "path", "docsDir", "diagramming", "feedback"]),
|
|
60
115
|
documentContent: currentContent,
|
|
116
|
+
originalContent: currentContent,
|
|
61
117
|
});
|
|
62
118
|
const content = generateDiagramResult.content;
|
|
63
119
|
contentContext.set(content);
|
|
64
|
-
|
|
120
|
+
// Pass intentType to saveDoc so it can handle translation sync automatically
|
|
121
|
+
await saveDoc(input, options, { content, intentType: "addDiagram" });
|
|
65
122
|
return { content };
|
|
66
123
|
}
|
|
67
124
|
|
|
68
125
|
async function updateDiagram(input, options) {
|
|
69
126
|
const contentContext = userContextAt(options, `currentContents.${input.path}`);
|
|
70
127
|
const currentContent = contentContext.get();
|
|
71
|
-
let [content
|
|
128
|
+
let [content] = replaceD2WithPlaceholder({
|
|
72
129
|
content: currentContent,
|
|
73
130
|
});
|
|
74
131
|
const generateAgent = options.context?.agents?.["generateDiagram"];
|
|
75
|
-
const
|
|
132
|
+
const result = await options.context.invoke(generateAgent, {
|
|
76
133
|
documentContent: content,
|
|
77
134
|
locale: input.locale,
|
|
78
|
-
|
|
135
|
+
diagramming: input.diagramming || {},
|
|
79
136
|
feedback: input.feedback,
|
|
137
|
+
originalContent: currentContent, // Pass original content to find existing diagrams
|
|
138
|
+
path: input.path,
|
|
139
|
+
docsDir: input.docsDir,
|
|
80
140
|
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
141
|
+
|
|
142
|
+
// generateDiagram now returns { content } with image already inserted
|
|
143
|
+
// The image replaces DIAGRAM_PLACEHOLDER or D2 code blocks
|
|
144
|
+
if (result?.content) {
|
|
145
|
+
content = result.content;
|
|
146
|
+
}
|
|
147
|
+
|
|
85
148
|
contentContext.set(content);
|
|
86
|
-
|
|
149
|
+
// Pass intentType to saveDoc so it can handle translation sync automatically
|
|
150
|
+
await saveDoc(input, options, { content, intentType: "updateDiagram" });
|
|
87
151
|
return { content };
|
|
88
152
|
}
|
|
89
153
|
|
|
90
154
|
async function deleteDiagram(input, options) {
|
|
91
155
|
const contentContext = userContextAt(options, `currentContents.${input.path}`);
|
|
92
156
|
const currentContent = contentContext.get();
|
|
93
|
-
|
|
157
|
+
|
|
158
|
+
// Extract diagram index from feedback if provided
|
|
159
|
+
// This allows deleting a specific diagram when multiple diagrams exist
|
|
160
|
+
let diagramIndex = input.diagramIndex;
|
|
161
|
+
if (diagramIndex === undefined && input.feedback) {
|
|
162
|
+
// Import extractDiagramIndexFromFeedback from replace-d2-with-image.mjs
|
|
163
|
+
const { extractDiagramIndexFromFeedback } = await import(
|
|
164
|
+
"../../create/replace-d2-with-image.mjs"
|
|
165
|
+
);
|
|
166
|
+
const extractedIndex = extractDiagramIndexFromFeedback(input.feedback);
|
|
167
|
+
if (extractedIndex !== null) {
|
|
168
|
+
diagramIndex = extractedIndex;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Replace all diagrams (D2 code blocks, generated images, Mermaid) with placeholder
|
|
173
|
+
// If diagramIndex is provided, only replace that specific diagram
|
|
174
|
+
// This ensures LLM can identify and remove the diagram regardless of its type
|
|
175
|
+
const documentContent = replaceDiagramsWithPlaceholder({
|
|
94
176
|
content: currentContent,
|
|
177
|
+
diagramIndex,
|
|
95
178
|
});
|
|
96
179
|
const instructions = `<role>
|
|
97
180
|
Your task is to remove ${DIAGRAM_PLACEHOLDER} and adjust the document context (based on the user's feedback) to make it easier to understand.
|
|
@@ -123,8 +206,24 @@ Your task is to remove ${DIAGRAM_PLACEHOLDER} and adjust the document context (b
|
|
|
123
206
|
documentContent,
|
|
124
207
|
feedback: input.feedback,
|
|
125
208
|
});
|
|
209
|
+
|
|
210
|
+
// Delete associated diagram image files
|
|
211
|
+
if (input.docsDir) {
|
|
212
|
+
try {
|
|
213
|
+
const { deleteDiagramImages } = await import("../../../utils/delete-diagram-images.mjs");
|
|
214
|
+
const { deleted } = await deleteDiagramImages(currentContent, input.path, input.docsDir);
|
|
215
|
+
if (deleted > 0) {
|
|
216
|
+
console.log(`Deleted ${deleted} diagram image file(s) for ${input.path}`);
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
// Don't fail the operation if image deletion fails
|
|
220
|
+
console.warn(`Failed to delete diagram images: ${error.message}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
126
224
|
contentContext.set(content);
|
|
127
|
-
|
|
225
|
+
// Pass intentType to saveDoc so it can handle translation sync automatically
|
|
226
|
+
await saveDoc(input, options, { content, intentType: "deleteDiagram" });
|
|
128
227
|
|
|
129
228
|
return { content };
|
|
130
229
|
}
|
|
@@ -149,7 +248,19 @@ async function updateDocument(input, options) {
|
|
|
149
248
|
}
|
|
150
249
|
|
|
151
250
|
export default async function updateSingleDocumentDetail(input, options) {
|
|
152
|
-
|
|
251
|
+
// Use intentType from input if available (analyzed in parent flow),
|
|
252
|
+
// otherwise fall back to analyzing it here (for backward compatibility)
|
|
253
|
+
let intentType = input.intentType;
|
|
254
|
+
if (!intentType && input.feedback) {
|
|
255
|
+
intentType = await getIntentType(input, options);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// If intentType is still null or undefined, default to updateDocument
|
|
259
|
+
// This ensures that some operation is always performed, even if intent analysis failed
|
|
260
|
+
// or no explicit intent was provided
|
|
261
|
+
if (!intentType) {
|
|
262
|
+
intentType = "updateDocument";
|
|
263
|
+
}
|
|
153
264
|
|
|
154
265
|
const fnMap = {
|
|
155
266
|
addDiagram,
|
|
@@ -162,5 +273,8 @@ export default async function updateSingleDocumentDetail(input, options) {
|
|
|
162
273
|
const result = await fnMap[intentType](input, options);
|
|
163
274
|
return result;
|
|
164
275
|
}
|
|
165
|
-
|
|
276
|
+
|
|
277
|
+
// Fallback: if intentType is not in fnMap, default to updateDocument
|
|
278
|
+
console.warn(`Unknown intentType: ${intentType}, defaulting to updateDocument`);
|
|
279
|
+
return await updateDocument(input, options);
|
|
166
280
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { AIAgent } from "@aigne/core";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Analyze user feedback to determine the intent type for document updates
|
|
6
|
+
* Returns one of: "addDiagram", "deleteDiagram", "updateDiagram", "updateDocument"
|
|
7
|
+
* Returns null if feedback is empty or invalid
|
|
8
|
+
*/
|
|
9
|
+
export default async function analyzeFeedbackIntent({ feedback, shouldUpdateDiagrams }, options) {
|
|
10
|
+
// Check if feedback exists and is not empty
|
|
11
|
+
// If feedback is empty and --diagram flag is set, default to updateDiagram
|
|
12
|
+
// Otherwise return null
|
|
13
|
+
if (!feedback || typeof feedback !== "string" || !feedback.trim()) {
|
|
14
|
+
// If --diagram flag is set, default to updateDiagram (user wants to update diagrams)
|
|
15
|
+
if (shouldUpdateDiagrams) {
|
|
16
|
+
return { intentType: "updateDiagram" };
|
|
17
|
+
}
|
|
18
|
+
return { intentType: null };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Always analyze user feedback first, even if --diagram flag is set
|
|
22
|
+
// This ensures user's explicit intent (e.g., "remove image", "delete diagram") is respected
|
|
23
|
+
// The --diagram flag should only be a hint, not override explicit user commands
|
|
24
|
+
|
|
25
|
+
const instructions = `<role>
|
|
26
|
+
You are a feedback intent analyzer. Your task is to determine which type of content modifications are needed based on the user's feedback.
|
|
27
|
+
|
|
28
|
+
You must analyze the user's feedback and classify it into one of the following intent types:
|
|
29
|
+
- addDiagram: User wants to add a new diagram/image/chart
|
|
30
|
+
- deleteDiagram: User wants to remove/delete a diagram/image/chart
|
|
31
|
+
- updateDiagram: User wants to modify/update an existing diagram/image/chart
|
|
32
|
+
- updateDocument: User wants to update document content (text, sections, etc.) without diagram operations
|
|
33
|
+
</role>
|
|
34
|
+
|
|
35
|
+
<intent_classification_rules>
|
|
36
|
+
**deleteDiagram** - Use this when user explicitly wants to remove or delete a diagram/image/chart:
|
|
37
|
+
- Keywords: remove, delete, 删除, 移除, 去掉, 清除
|
|
38
|
+
- Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图, 架构图
|
|
39
|
+
- Examples:
|
|
40
|
+
- "Remove the diagram"
|
|
41
|
+
- "Delete the image"
|
|
42
|
+
- "删除这张图片"
|
|
43
|
+
- "Remove the second diagram"
|
|
44
|
+
- "去掉架构图"
|
|
45
|
+
- "Remove image from page 3"
|
|
46
|
+
- "Delete the chart showing the flow"
|
|
47
|
+
|
|
48
|
+
**addDiagram** - Use this when user wants to add a new diagram:
|
|
49
|
+
- Keywords: add, create, insert, 添加, 创建, 插入
|
|
50
|
+
- Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图
|
|
51
|
+
- Examples:
|
|
52
|
+
- "Add a diagram showing the architecture"
|
|
53
|
+
- "Create a flow chart"
|
|
54
|
+
- "添加一个架构图"
|
|
55
|
+
|
|
56
|
+
**updateDiagram** - Use this when user wants to modify an existing diagram:
|
|
57
|
+
- Keywords: update, modify, change, improve, 更新, 修改, 改进
|
|
58
|
+
- Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图
|
|
59
|
+
- Examples:
|
|
60
|
+
- "Update the diagram to show the new process"
|
|
61
|
+
- "Modify the chart to include more details"
|
|
62
|
+
- "更新架构图"
|
|
63
|
+
|
|
64
|
+
**updateDocument** - Use this for all other content modifications:
|
|
65
|
+
- Text changes, section updates, content improvements
|
|
66
|
+
- No mention of diagrams/images/charts
|
|
67
|
+
- Examples:
|
|
68
|
+
- "Update the introduction section"
|
|
69
|
+
- "Fix the typo in paragraph 2"
|
|
70
|
+
- "Improve the explanation"
|
|
71
|
+
</intent_classification_rules>
|
|
72
|
+
|
|
73
|
+
<user_feedback>
|
|
74
|
+
{{feedback}}
|
|
75
|
+
</user_feedback>
|
|
76
|
+
|
|
77
|
+
<analysis_guidelines>
|
|
78
|
+
1. Pay close attention to action verbs (remove, delete, add, update, etc.)
|
|
79
|
+
2. Identify the target object (diagram, image, chart, or general content)
|
|
80
|
+
3. If feedback mentions removing/deleting a diagram/image/chart → deleteDiagram
|
|
81
|
+
4. If feedback mentions adding a diagram/image/chart → addDiagram
|
|
82
|
+
5. If feedback mentions updating a diagram/image/chart → updateDiagram
|
|
83
|
+
6. If feedback is about general content without diagram references → updateDocument
|
|
84
|
+
7. When in doubt, prioritize the most explicit action mentioned in the feedback
|
|
85
|
+
</analysis_guidelines>`;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const analyzeUpdateFeedbackIntentAgent = AIAgent.from({
|
|
89
|
+
name: "analyzeUpdateFeedbackIntent",
|
|
90
|
+
description:
|
|
91
|
+
"Analyze user feedback to determine if document are needed for content modifications",
|
|
92
|
+
task_render_mode: "hide",
|
|
93
|
+
instructions,
|
|
94
|
+
inputSchema: z.object({
|
|
95
|
+
feedback: z.string().describe("User feedback for content modifications"),
|
|
96
|
+
}),
|
|
97
|
+
outputSchema: z.object({
|
|
98
|
+
intentType: z
|
|
99
|
+
.enum(["addDiagram", "deleteDiagram", "updateDiagram", "updateDocument"])
|
|
100
|
+
.describe(
|
|
101
|
+
"The primary type of user intention: one of addDiagram, deleteDiagram, updateDiagram, updateDocument",
|
|
102
|
+
),
|
|
103
|
+
}),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const { intentType } = await options.context.invoke(analyzeUpdateFeedbackIntentAgent, {
|
|
107
|
+
feedback: feedback.trim(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// If --diagram flag is set and user didn't explicitly request delete/add,
|
|
111
|
+
// default to updateDiagram (for backward compatibility)
|
|
112
|
+
// But if user explicitly requested delete/add, respect that intent
|
|
113
|
+
if (
|
|
114
|
+
shouldUpdateDiagrams &&
|
|
115
|
+
intentType &&
|
|
116
|
+
!["deleteDiagram", "addDiagram"].includes(intentType)
|
|
117
|
+
) {
|
|
118
|
+
return { intentType: "updateDiagram" };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return { intentType };
|
|
122
|
+
} catch (error) {
|
|
123
|
+
// If analysis fails and --diagram flag is set, default to updateDiagram
|
|
124
|
+
// Otherwise return null to fall back to default document update flow
|
|
125
|
+
if (shouldUpdateDiagrams) {
|
|
126
|
+
console.warn(
|
|
127
|
+
`Failed to analyze feedback intent, defaulting to updateDiagram due to --diagram flag: ${error.message}`,
|
|
128
|
+
);
|
|
129
|
+
return { intentType: "updateDiagram" };
|
|
130
|
+
}
|
|
131
|
+
console.warn(`Failed to analyze feedback intent: ${error.message}`);
|
|
132
|
+
return { intentType: null };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
analyzeFeedbackIntent.task_render_mode = "hide";
|