@aigne/doc-smith 0.9.5-beta.1 → 0.9.6-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 CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.6-beta](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.5...v0.9.6-beta) (2025-11-18)
4
+
5
+
6
+ ### Features
7
+
8
+ * smaller granularity of updated single-document ([#320](https://github.com/AIGNE-io/aigne-doc-smith/issues/320)) ([588b924](https://github.com/AIGNE-io/aigne-doc-smith/commit/588b924649f5f116a07586a1f6760ee6f7e79953))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * always use short url during doc publish process ([#319](https://github.com/AIGNE-io/aigne-doc-smith/issues/319)) ([5fcf067](https://github.com/AIGNE-io/aigne-doc-smith/commit/5fcf067c2caf822576ee60e3f58a69040e5813f4))
14
+ * tune document detail update output constraint ([#322](https://github.com/AIGNE-io/aigne-doc-smith/issues/322)) ([6ac8aa4](https://github.com/AIGNE-io/aigne-doc-smith/commit/6ac8aa49e9bb761164c60ccddc4b601b9c612203))
15
+
16
+ ## [0.9.5](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.5-beta.1...v0.9.5) (2025-11-14)
17
+
3
18
  ## [0.9.5-beta.1](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.5-beta...v0.9.5-beta.1) (2025-11-14)
4
19
 
5
20
 
@@ -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, {
@@ -0,0 +1,140 @@
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
+
6
+ async function getIntentType(input, options) {
7
+ const instructions = `<role>
8
+ You are a feedback intent analyzer. Your task is to determine which type of content modifications are needed based on the user's feedback.
9
+ </role>
10
+
11
+ <user_feedback>
12
+ {{feedback}}
13
+ </user_feedback>`;
14
+ const analyzeUpdateFeedbackIntentAgent = AIAgent.from({
15
+ name: "analyzeUpdateFeedbackIntent",
16
+ description:
17
+ "Analyze user feedback to determine if document are needed for content modifications",
18
+ task_render_mode: "hide",
19
+ instructions,
20
+ // TODO: can't set reasoningEffort
21
+ // modelOptions: {
22
+ // reasoningEffort: 1,
23
+ // },
24
+ inputSchema: z.object({
25
+ feedback: z.string().describe("User feedback for content modifications"),
26
+ }),
27
+ outputSchema: z.object({
28
+ intentType: z
29
+ .enum(["addDiagram", "deleteDiagram", "updateDiagram", "updateDocument"])
30
+ .describe(
31
+ "The primary type of user intention: one of addDiagram, deleteDiagram, updateDiagram, updateDocument",
32
+ ),
33
+ }),
34
+ });
35
+ const { intentType } = await options.context.invoke(analyzeUpdateFeedbackIntentAgent, {
36
+ feedback: input.feedback,
37
+ });
38
+ return intentType;
39
+ }
40
+
41
+ async function saveDoc(input, options, { content }) {
42
+ const saveAgent = options.context?.agents?.["saveDoc"];
43
+ await options.context.invoke(saveAgent, {
44
+ ...pick(input, ["path", "docsDir", "labels", "locale"]),
45
+ content,
46
+ });
47
+ }
48
+
49
+ async function addDiagram(input, options) {
50
+ const generateDiagramAgent = options.context.agents["checkGenerateDiagram"];
51
+ const generateDiagramResult = await options.context.invoke(generateDiagramAgent, {
52
+ ...pick(input, ["locale", "path", "diagramming", "feedback"]),
53
+ documentContent: options.context.userContext.currentContent,
54
+ });
55
+ const content = generateDiagramResult.content;
56
+ await saveDoc(input, options, { content });
57
+ return { content };
58
+ }
59
+
60
+ async function updateDiagram(input, options) {
61
+ let [content, previousDiagramContent] = replacePlaceholder({
62
+ content: options.context.userContext.currentContent,
63
+ });
64
+ const generateAgent = options.context?.agents?.["generateDiagram"];
65
+ const { diagramSourceCode } = await options.context.invoke(generateAgent, {
66
+ documentContent: content,
67
+ locale: input.locale,
68
+ previousDiagramContent,
69
+ feedback: input.feedback,
70
+ });
71
+ content = content.replace(DIAGRAM_PLACEHOLDER, diagramSourceCode);
72
+ await saveDoc(input, options, { content });
73
+ return { content };
74
+ }
75
+
76
+ async function deleteDiagram(input, options) {
77
+ const [documentContent] = replacePlaceholder({
78
+ content: options.context.userContext.currentContent,
79
+ });
80
+ const instructions = `<role>
81
+ Your task is to remove ${DIAGRAM_PLACEHOLDER} and adjust the document context (based on the user's feedback) to make it easier to understand.
82
+ </role>
83
+
84
+ <document_content>
85
+ {{documentContent}}
86
+ </document_content>
87
+
88
+ <user_feedback>
89
+ {{feedback}}
90
+ </user_feedback>`;
91
+ const deleteAgent = AIAgent.from({
92
+ name: "deleteDiagram",
93
+ description: "Remove a diagram from the document content",
94
+ task_render_mode: "hide",
95
+ instructions,
96
+ inputSchema: z.object({
97
+ documentContent: z.string().describe("Source content of the document"),
98
+ feedback: z.string().describe("User feedback for content modifications"),
99
+ }),
100
+ outputKey: "message",
101
+ });
102
+ const { message: content } = await options.context.invoke(deleteAgent, {
103
+ documentContent,
104
+ feedback: input.feedback,
105
+ });
106
+ await saveDoc(input, options, { content });
107
+
108
+ return { content };
109
+ }
110
+
111
+ async function updateDocument(input, options) {
112
+ const updateAgent = options.context.agents["updateDocumentDetail"];
113
+ const updateResult = await options.context.invoke(updateAgent, {
114
+ ...input,
115
+ originalContent: options.context.userContext.currentContent,
116
+ });
117
+ if (updateResult.message === "success") {
118
+ await saveDoc(input, options, { content: options.context.userContext.currentContent });
119
+ }
120
+ return {
121
+ content: options.context.userContext.currentContent,
122
+ };
123
+ }
124
+
125
+ export default async function updateSingleDocumentDetail(input, options) {
126
+ const intentType = await getIntentType(input, options);
127
+
128
+ const fnMap = {
129
+ addDiagram,
130
+ updateDiagram,
131
+ deleteDiagram,
132
+ updateDocument,
133
+ };
134
+
135
+ if (fnMap[intentType]) {
136
+ const result = await fnMap[intentType](input, options);
137
+ return result;
138
+ }
139
+ return {};
140
+ }
@@ -200,7 +200,7 @@ export default async function userReviewDocument({ content, description, ...rest
200
200
  }
201
201
 
202
202
  // Get the updateDocument agent
203
- const updateAgent = options.context.agents["handleDocumentUpdate"];
203
+ const updateAgent = options.context.agents["updateSingleDocumentDetail"];
204
204
  if (!updateAgent) {
205
205
  console.log(
206
206
  "We can't process your feedback right now. The document update feature is temporarily unavailable.",
package/aigne.yaml CHANGED
@@ -39,6 +39,7 @@ agents:
39
39
  - ./agents/update/check-update-is-single.mjs
40
40
  - ./agents/update/save-and-translate-document.mjs
41
41
  - ./agents/update/index.yaml
42
+ - ./agents/update/update-single/update-single-document-detail.mjs
42
43
 
43
44
 
44
45
  # Translation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/doc-smith",
3
- "version": "0.9.5-beta.1",
3
+ "version": "0.9.6-beta",
4
4
  "description": "AI-driven documentation generation tool built on the AIGNE Framework",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -9,6 +9,9 @@ Generate a d2 diagram that represents the following document content:
9
9
  <user_rules>
10
10
 
11
11
  - Output only the diagram labels and text in the {{ locale }} language — keep all variable names, component names, and syntax unchanged.
12
+ {% if previousDiagramContent %}
13
+ - Update the diagram based on `<feedback>` and `<previous_diagram_content>`.
14
+ {% endif %}
12
15
 
13
16
  </user_rules>
14
17
 
@@ -24,3 +27,17 @@ Generate a d2 diagram that represents the following document content:
24
27
 
25
28
  </diagram_check_feedback>
26
29
  {% endif %}
30
+
31
+ {% if previousDiagramContent %}
32
+ <previous_diagram_content>
33
+ {{ previousDiagramContent }}
34
+ </previous_diagram_content>
35
+
36
+ {% if feedback %}
37
+ <feedback>
38
+ {{ feedback }}
39
+ </feedback>
40
+ {% endif %}
41
+
42
+ {% endif %}
43
+
@@ -49,7 +49,6 @@ Documentation content generation rules:
49
49
  </content_generation_rules>
50
50
 
51
51
 
52
-
53
52
  <output_constraints>
54
53
 
55
54
  1. Output the complete Markdown content for {{nodeName}}, only the content itself—no explanations or extra information.
@@ -3,9 +3,35 @@
3
3
  </role_and_goal>
4
4
 
5
5
 
6
- <document_structure>
7
- {{ documentStructureYaml }}
8
- </document_structure>
6
+ <task_instructions>
7
+ Your task is to:
8
+
9
+ Processing workflow:
10
+ - If user feedback is not in English, translate it to English first to better understand user intent
11
+ - Analyze user feedback to understand the exact intent and scope of changes
12
+ - Generate a unified diff patch that implements the requested improvements
13
+ - Use the available tool to apply the changes and get the final content
14
+ - Tool calls only need to return toolCalls information
15
+ - Ensure all modifications maintain document quality and consistency
16
+ - Return 'success' when the latest version of content meets user feedback(Don't add any explanation)
17
+
18
+ Tool usage guidelines:
19
+
20
+ **updateDocumentContent**: Use this tool to apply changes to the document content
21
+ - Generate a precise unified diff patch based on the user feedback
22
+ - Forbidden change diagram source code
23
+ - If user ask to add/update diagram, use `generateDiagram` tool instead.
24
+ - If user ask to remove diagram, should remove diagram content and update document context to get better understanding.
25
+ - The diff should include context lines for accurate application
26
+ - Only consider content within `<page_content>` tag when calculating line numbers, ensure line number calculation is accurate
27
+ - Test the patch application to ensure it works correctly
28
+
29
+ Error handling:
30
+ - If user intent is unclear, ask for clarification
31
+ - If the requested changes conflict with best practices, explain the issues and suggest alternatives
32
+ - If the diff patch fails to apply, revise the approach and try again
33
+ </task_instructions>
34
+
9
35
 
10
36
  <current_document>
11
37
  Current {{nodeName}} information:
@@ -16,6 +42,11 @@ parentId: {{parentId}}
16
42
  </current_document>
17
43
 
18
44
 
45
+ <document_structure>
46
+ {{ documentStructureYaml }}
47
+ </document_structure>
48
+
49
+
19
50
  {% if glossary %}
20
51
  <terms>
21
52
  Glossary of specialized terms. Please ensure correct spelling when using these terms.
@@ -39,7 +70,10 @@ Documentation content optimization rules:
39
70
 
40
71
  {% include "../../common/document/media-file-list-usage-rules.md" %}
41
72
 
42
- {% include "../diagram/rules.md" %}
73
+ {% include "../../common/document/openapi-usage-rules.md" %}
74
+
75
+ ** Update Constraints: **
76
+ - Forbidden change diagram source code
43
77
 
44
78
  </content_optimization_rules>
45
79
 
@@ -75,37 +109,11 @@ Analyze the user feedback to determine the specific improvements needed:
75
109
 
76
110
  </feedback_analysis_guidelines>
77
111
 
78
- <task_instructions>
79
- Your task is to:
80
-
81
- Processing workflow:
82
- - If user feedback is not in English, translate it to English first to better understand user intent
83
- - Analyze user feedback to understand the exact intent and scope of changes
84
- - Generate a unified diff patch that implements the requested improvements
85
- - Use the available tool to apply the changes and get the final content
86
- - Tool calls only need to return toolCalls information
87
- - Ensure all modifications maintain document quality and consistency
88
- - Return 'success' when the latest version of content meets user feedback
89
-
90
- Tool usage guidelines:
91
-
92
- **updateDocumentContent**: Use this tool to apply changes to the document content
93
- - Generate a precise unified diff patch based on the user feedback
94
- - The diff should include context lines for accurate application
95
- - Only consider content within `<page_content>` tag when calculating line numbers, ensure line number calculation is accurate
96
- - Test the patch application to ensure it works correctly
97
-
98
- Error handling:
99
- - If user intent is unclear, ask for clarification
100
- - If the requested changes conflict with best practices, explain the issues and suggest alternatives
101
- - If the diff patch fails to apply, revise the approach and try again
102
- </task_instructions>
103
-
104
112
  {% include "../generate/detail-example.md" %}
105
113
 
106
114
 
107
- <output_format>
115
+ <output_constraints>
108
116
  ** Only output operation execution status **:
109
117
  - Only return 'success' if operation executed successfully
110
118
  - Return brief error message if operation failed
111
- </output_format>
119
+ </output_constraints>
@@ -21,7 +21,6 @@ import {
21
21
  DISCUSS_KIT_STORE_URL,
22
22
  PAYMENT_KIT_DID,
23
23
  } from "./constants/index.mjs";
24
- import { requestWithAuthToken } from "./request.mjs";
25
24
  import { withQuery } from "ufo";
26
25
 
27
26
  const WELLKNOWN_SERVICE_PATH_PREFIX = "/.well-known/service";
@@ -143,16 +142,15 @@ export async function getAccessToken(appUrl, ltToken = "", locale = "en") {
143
142
 
144
143
  try {
145
144
  const officialBaseUrl = process.env.DOC_SMITH_BASE_URL || CLOUD_SERVICE_URL_PROD;
146
- const officialAccessToken = await getCachedAccessToken(officialBaseUrl);
147
- if (officialAccessToken) {
148
- const mountPoint = await getComponentMountPoint(officialBaseUrl, PAYMENT_KIT_DID);
149
- const data = await requestWithAuthToken(
150
- withQuery(joinURL(officialBaseUrl, mountPoint, "/api/tool/short-url"), {
151
- url: connectUrl,
152
- }),
153
- {},
154
- officialAccessToken,
155
- );
145
+ const mountPoint = await getComponentMountPoint(officialBaseUrl, PAYMENT_KIT_DID);
146
+ const response = await fetch(
147
+ withQuery(joinURL(officialBaseUrl, mountPoint, "/api/tool/short-connect-url"), {
148
+ url: connectUrl,
149
+ locale,
150
+ }),
151
+ );
152
+ const data = await response.json();
153
+ if (data.url) {
156
154
  connectUrl = data.url;
157
155
  }
158
156
  } catch {
@@ -160,7 +158,7 @@ export async function getAccessToken(appUrl, ltToken = "", locale = "en") {
160
158
  }
161
159
 
162
160
  console.log(
163
- "🔗 Please open the following URL in your browser to authorize access: ",
161
+ "🔗 Please open the following URL in your browser to authorize access:",
164
162
  chalk.cyan(connectUrl),
165
163
  "\n",
166
164
  );
@@ -220,16 +218,34 @@ export async function getOfficialAccessToken(baseUrl, openPage = true, locale =
220
218
  fetchInterval: FETCH_INTERVAL,
221
219
  appName: "AIGNE DocSmith",
222
220
  appLogo: "https://docsmith.aigne.io/image-bin/uploads/9645caf64b4232699982c4d940b03b90.svg",
223
- openPage: (pageUrl) => {
221
+ openPage: async (pageUrl) => {
224
222
  const url = new URL(pageUrl);
225
223
  if (locale) {
226
224
  url.searchParams.set("locale", locale);
227
225
  }
228
- open(url.toString());
226
+
227
+ let connectUrl = url.toString();
228
+ open(connectUrl);
229
+ try {
230
+ const officialBaseUrl = process.env.DOC_SMITH_BASE_URL || CLOUD_SERVICE_URL_PROD;
231
+ const mountPoint = await getComponentMountPoint(officialBaseUrl, PAYMENT_KIT_DID);
232
+ const response = await fetch(
233
+ withQuery(joinURL(officialBaseUrl, mountPoint, "/api/tool/short-connect-url"), {
234
+ url: connectUrl,
235
+ locale,
236
+ }),
237
+ );
238
+ const data = await response.json();
239
+ if (data.url) {
240
+ connectUrl = data.url;
241
+ }
242
+ } catch {
243
+ // Ignore error
244
+ }
229
245
 
230
246
  console.log(
231
- "🔗 Please open the following URL in your browser to authorize access: ",
232
- chalk.cyan(url.toString()),
247
+ "🔗 Please open the following URL in your browser to authorize access:",
248
+ chalk.cyan(connectUrl),
233
249
  "\n",
234
250
  );
235
251
  },
@@ -19,6 +19,8 @@ import { getContentHash } from "./utils.mjs";
19
19
 
20
20
  const codeBlockRegex = /```d2.*\n([\s\S]*?)```/g;
21
21
 
22
+ export const DIAGRAM_PLACEHOLDER = "DIAGRAM_PLACEHOLDER";
23
+
22
24
  export async function getChart({ content, strict }) {
23
25
  const d2 = new D2();
24
26
  const iconUrlList = Object.keys(iconMap);
@@ -203,3 +205,14 @@ export function wrapCode({ content }) {
203
205
 
204
206
  return `\`\`\`d2\n${content}\n\`\`\``;
205
207
  }
208
+
209
+ export function replacePlaceholder({ content }) {
210
+ const [firstMatch] = Array.from(content.matchAll(codeBlockRegex));
211
+ if (firstMatch) {
212
+ const matchContent = firstMatch[0];
213
+ const cleanContent = content.replace(matchContent, DIAGRAM_PLACEHOLDER);
214
+ return [cleanContent, matchContent];
215
+ }
216
+
217
+ return [content, ""];
218
+ }