Skip to content

Commit 19613ae

Browse files
committed
refactor: Simplify documentation generation process and enhance content handling
1 parent 97bfdf1 commit 19613ae

File tree

5 files changed

+379
-570
lines changed

5 files changed

+379
-570
lines changed

src/KoalaWiki/KernelFactory.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static Kernel GetKernel(string chatEndpoint,
2626
string apiKey,
2727
string gitPath,
2828
string model, bool isCodeAnalysis = true,
29-
List<string>? files = null)
29+
List<string>? files = null, Action<IKernelBuilder>? kernelBuilderAction = null)
3030
{
3131
using var activity = Activity.Current?.Source.StartActivity();
3232
activity?.SetTag("model", model);
@@ -99,7 +99,7 @@ public static Kernel GetKernel(string chatEndpoint,
9999
}
100100

101101
// 添加文件函数
102-
var fileFunction = new FileFunction(gitPath,files);
102+
var fileFunction = new FileFunction(gitPath, files);
103103
kernelBuilder.Plugins.AddFromObject(fileFunction);
104104
kernelBuilder.Plugins.AddFromType<AgentFunction>();
105105
activity?.SetTag("plugins.file_function", "loaded");
@@ -111,6 +111,8 @@ public static Kernel GetKernel(string chatEndpoint,
111111
activity?.SetTag("plugins.code_analyze_function", "loaded");
112112
}
113113

114+
kernelBuilderAction?.Invoke(kernelBuilder);
115+
114116
var kernel = kernelBuilder.Build();
115117
kernel.FunctionInvocationFilters.Add(new FunctionResultInterceptor());
116118

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using System.ComponentModel;
2+
3+
namespace KoalaWiki.KoalaWarehouse.DocumentPending;
4+
5+
public class DocsFunction
6+
{
7+
/// <summary>
8+
/// 写入内容
9+
/// </summary>
10+
/// <returns></returns>
11+
[KernelFunction("Write"), Description("""
12+
Generate the content for the document.
13+
Usage:
14+
- This tool will overwrite the existing content.
15+
- Always edit the existing content first. Do not overwrite it unless explicitly required.
16+
- Use emojis only when the user explicitly requests it. Avoid adding emojis to the document unless specifically asked to do so.
17+
""")]
18+
public string Write(
19+
[Description("The content to write")] string content)
20+
{
21+
Content = content;
22+
if (string.IsNullOrEmpty(Content))
23+
{
24+
return "<system-reminder>Content cannot be empty.</system-reminder>";
25+
}
26+
27+
Content = Content.Trim();
28+
return @$"<system-reminder>Write successful</system-reminder>";
29+
}
30+
31+
[KernelFunction("Edit"), Description("""
32+
Perform precise string replacement operations in the generated document.
33+
Usage:
34+
- Before making any edits, you must use the `Read` tool at least once in the conversation. If you attempt to edit without reading the file, the tool will report an error.
35+
- When editing the text output from the `Read` tool, make sure to retain its exact indentation (tabs/spaces), that is, the form that appears after the line number prefix. The line number prefix format is: space + line number + tab. Everything after that tab is the actual file content and must match it. Do not include any components of the line number prefix in the old string or new string.
36+
- Always prioritize editing existing files in the code repository. Do not overwrite the content unless explicitly required.
37+
- Use emojis only when the user explicitly requests it. Do not add emojis to the file unless required.
38+
- If the `oldString` is not unique in the file, the edit will fail. Either provide a longer string with more context to make it unique, or use `replaceAll` to change all instances of the "old string".
39+
- Use `replaceAll` to replace and rename strings throughout the file. This parameter is very useful when renaming variables, etc.
40+
""")]
41+
public string Edit(
42+
[Description("The text to replace")]
43+
string oldString,
44+
[Description("The text to replace it with (must be different from old_string)")]
45+
string newString,
46+
[Description("Replace all occurences of old_string (default false)")]
47+
bool replaceAll = false)
48+
{
49+
if (string.IsNullOrEmpty(Content))
50+
{
51+
return "<system-reminder>Document content is empty, please write content first.</system-reminder>";
52+
}
53+
54+
if (string.IsNullOrEmpty(oldString))
55+
{
56+
return "<system-reminder>Old string cannot be empty.</system-reminder>";
57+
}
58+
59+
if (oldString == newString)
60+
{
61+
return "<system-reminder>New string must be different from old string.</system-reminder>";
62+
}
63+
64+
if (!Content.Contains(oldString))
65+
{
66+
return "<system-reminder>Old string not found in document.</system-reminder>";
67+
}
68+
69+
if (!replaceAll && Content.Split(new[] { oldString }, StringSplitOptions.None).Length > 2)
70+
{
71+
return "<system-reminder>Old string is not unique in the document. Use replaceAll=true to replace all occurrences or provide a longer string with more context.</system-reminder>";
72+
}
73+
74+
if (replaceAll)
75+
{
76+
Content = Content.Replace(oldString, newString);
77+
}
78+
else
79+
{
80+
int index = Content.IndexOf(oldString);
81+
Content = Content.Substring(0, index) + newString + Content.Substring(index + oldString.Length);
82+
}
83+
84+
return @$"<system-reminder>Edit successful</system-reminder>";
85+
}
86+
87+
[KernelFunction("Read"), Description("""
88+
To read the current generated document content, please note that this method can only read the content of the generated document.
89+
Usage:
90+
- By default, it reads up to 2000 lines from the beginning of the file.
91+
- You can choose to specify the line offset and limit, but it is recommended not to provide these parameters to read the entire file.
92+
- Any lines exceeding 2000 characters will be truncated.
93+
- If the file you are reading exists but is empty, you will receive a system warning instead of the file content.
94+
""")]
95+
public string Read(
96+
[Description("The line number to start reading from. Only provide if the file is too large to read at once")]
97+
int offset,
98+
[Description("The number of lines to read. Only provide if the file is too large to read at once.")]
99+
int limit = 2000)
100+
{
101+
var lines = Content.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
102+
103+
if (offset < 0 || offset >= lines.Length)
104+
{
105+
// 读取所有
106+
return string.Join("\n", lines);
107+
}
108+
109+
if (limit <= 0 || offset + limit > lines.Length)
110+
{
111+
// 读取到结尾
112+
return string.Join("\n", lines.Skip(offset));
113+
}
114+
115+
// 读取指定范围
116+
return string.Join("\n", lines.Skip(offset).Take(limit));
117+
}
118+
119+
/// <summary>
120+
/// 内容
121+
/// </summary>
122+
public string? Content { get; private set; }
123+
}

src/KoalaWiki/KoalaWarehouse/DocumentPending/DocumentPendingService.cs

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,16 @@ private static async Task<DocumentFileItem> ProcessCatalogueItems(DocumentCatalo
236236
string gitRepository, string branch, string path, ClassifyType? classify, List<string> files)
237237
{
238238
DocumentContext.DocumentStore = new DocumentStore();
239+
240+
var docs = new DocsFunction();
239241
// 为每个文档处理创建独立的Kernel实例,避免状态管理冲突
240242
var documentKernel = KernelFactory.GetKernel(
241243
OpenAIOptions.Endpoint,
242244
OpenAIOptions.ChatApiKey,
243245
path,
244246
OpenAIOptions.ChatModel,
245247
false, // 文档生成不需要代码分析功能
246-
files
248+
files, (builder => { builder.Plugins.AddFromObject(docs); })
247249
);
248250

249251
var chat = documentKernel.Services.GetService<IChatCompletionService>();
@@ -288,7 +290,7 @@ private static async Task<DocumentFileItem> ProcessCatalogueItems(DocumentCatalo
288290
// 保存原始内容,防止精炼失败时丢失
289291
var originalContent = sr.ToString();
290292

291-
if (string.IsNullOrEmpty(originalContent) && count < 3)
293+
if (string.IsNullOrEmpty(docs.Content) && count < 3)
292294
{
293295
count++;
294296
goto reset;
@@ -371,6 +373,8 @@ 7. ENSURE all enhancements are based on the code files analyzed in the original
371373
history.AddUserMessage(refineContents);
372374

373375
var refinedContent = new StringBuilder();
376+
int reset1 = 1;
377+
reset1:
374378
await foreach (var item in chat.GetStreamingChatMessageContentsAsync(history, settings, documentKernel))
375379
{
376380
if (!string.IsNullOrEmpty(item.Content))
@@ -379,6 +383,12 @@ 7. ENSURE all enhancements are based on the code files analyzed in the original
379383
}
380384
}
381385

386+
if (string.IsNullOrEmpty(docs.Content) && reset1 < 3)
387+
{
388+
reset1++;
389+
goto reset1;
390+
}
391+
382392
// 检查精炼后的内容是否有效
383393
if (!string.IsNullOrWhiteSpace(refinedContent.ToString()))
384394
{
@@ -398,43 +408,10 @@ 7. ENSURE all enhancements are based on the code files analyzed in the original
398408
}
399409
}
400410

401-
// 删除内容中所有的<thinking>内的内容,可能存在多个<thinking>标签,
402-
var thinkingRegex = new Regex(@"<thinking>.*?</thinking>", RegexOptions.Singleline);
403-
sr = new StringBuilder(thinkingRegex.Replace(sr.ToString(), string.Empty));
404-
405-
406-
// 使用正则表达式将<blog></blog>中的内容提取
407-
var regex = new Regex(@"<blog>(.*?)</blog>", RegexOptions.Singleline);
408-
409-
var match = regex.Match(sr.ToString());
410-
411-
if (match.Success)
412-
{
413-
// 提取到的内容
414-
var extractedContent = match.Groups[1].Value;
415-
sr.Clear();
416-
sr.Append(extractedContent);
417-
}
418-
419-
var content = sr.ToString().Trim();
420-
421-
// 删除所有的所有的<think></think>
422-
var thinkRegex = new Regex(@"<think>(.*?)</think>", RegexOptions.Singleline);
423-
content = thinkRegex.Replace(content, string.Empty);
424-
425-
// 从docs提取
426-
var docsRegex = new Regex(@"<docs>(.*?)</docs>", RegexOptions.Singleline);
427-
var docsMatch = docsRegex.Match(content);
428-
if (docsMatch.Success)
429-
{
430-
// 提取到的内容
431-
var extractedDocs = docsMatch.Groups[1].Value;
432-
content = content.Replace(docsMatch.Value, extractedDocs);
433-
}
434411

435412
var fileItem = new DocumentFileItem()
436413
{
437-
Content = content,
414+
Content = docs.Content,
438415
DocumentCatalogId = catalog.Id,
439416
Description = string.Empty,
440417
Extra = new Dictionary<string, string>(),

0 commit comments

Comments
 (0)