@comate/zulu 0.7.1 → 0.7.3

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 (155) hide show
  1. package/comate-engine/node_modules/@comate/plugin-shared-internals/dist/index.d.ts +1 -0
  2. package/comate-engine/server.js +3 -3
  3. package/dist/bundle/index.js +2 -2
  4. package/package.json +1 -1
  5. package/comate-engine/node_modules/better-sqlite3/build/Release/better_sqlite3.node +0 -0
  6. package/comate-engine/plugins/aiscan/assets/icon.svg +0 -12
  7. package/comate-engine/plugins/aiscan/dist/index.js +0 -54426
  8. package/comate-engine/plugins/aiscan/package.json +0 -67
  9. package/comate-engine/plugins/appdev/assets/icon.png +0 -0
  10. package/comate-engine/plugins/appdev/dist/help.md +0 -12
  11. package/comate-engine/plugins/appdev/dist/index.d.ts +0 -2
  12. package/comate-engine/plugins/appdev/dist/index.js +0 -194
  13. package/comate-engine/plugins/appdev/dist/providers/err.d.ts +0 -8
  14. package/comate-engine/plugins/appdev/dist/providers/err.js +0 -37
  15. package/comate-engine/plugins/appdev/dist/providers/fallback.d.ts +0 -5
  16. package/comate-engine/plugins/appdev/dist/providers/fallback.js +0 -28
  17. package/comate-engine/plugins/appdev/dist/providers/help.d.ts +0 -8
  18. package/comate-engine/plugins/appdev/dist/providers/help.js +0 -19
  19. package/comate-engine/plugins/appdev/dist/providers/medusa.d.ts +0 -8
  20. package/comate-engine/plugins/appdev/dist/providers/medusa.js +0 -39
  21. package/comate-engine/plugins/appdev/dist/providers/qa.d.ts +0 -8
  22. package/comate-engine/plugins/appdev/dist/providers/qa.js +0 -33
  23. package/comate-engine/plugins/appdev/package.json +0 -67
  24. package/comate-engine/plugins/bfc/assets/bfc-icon.png +0 -0
  25. package/comate-engine/plugins/bfc/dist/config/config.d.ts +0 -4
  26. package/comate-engine/plugins/bfc/dist/config/config.js +0 -4
  27. package/comate-engine/plugins/bfc/dist/help.md +0 -11
  28. package/comate-engine/plugins/bfc/dist/index.d.ts +0 -2
  29. package/comate-engine/plugins/bfc/dist/index.js +0 -452
  30. package/comate-engine/plugins/bfc/dist/providers/bfcInstructMode.d.ts +0 -8
  31. package/comate-engine/plugins/bfc/dist/providers/bfcInstructMode.js +0 -77
  32. package/comate-engine/plugins/bfc/dist/providers/genAbnormalCode.d.ts +0 -8
  33. package/comate-engine/plugins/bfc/dist/providers/genAbnormalCode.js +0 -71
  34. package/comate-engine/plugins/bfc/dist/providers/genBfcCode.d.ts +0 -8
  35. package/comate-engine/plugins/bfc/dist/providers/genBfcCode.js +0 -74
  36. package/comate-engine/plugins/bfc/dist/providers/getBatchCases.d.ts +0 -10
  37. package/comate-engine/plugins/bfc/dist/providers/getBatchCases.js +0 -71
  38. package/comate-engine/plugins/bfc/dist/providers/help.d.ts +0 -8
  39. package/comate-engine/plugins/bfc/dist/providers/help.js +0 -19
  40. package/comate-engine/plugins/bfc/dist/service/generateService.d.ts +0 -14
  41. package/comate-engine/plugins/bfc/dist/service/generateService.js +0 -27
  42. package/comate-engine/plugins/bfc/package.json +0 -85
  43. package/comate-engine/plugins/bpm/assets/bpm.png +0 -0
  44. package/comate-engine/plugins/bpm/dist/index.js +0 -313
  45. package/comate-engine/plugins/bpm/package.json +0 -65
  46. package/comate-engine/plugins/casebuilder/assets/icon.svg +0 -1
  47. package/comate-engine/plugins/casebuilder/dist/help.md +0 -33
  48. package/comate-engine/plugins/casebuilder/dist/index.js +0 -837
  49. package/comate-engine/plugins/casebuilder/package.json +0 -80
  50. package/comate-engine/plugins/centrino/assets/icon.png +0 -0
  51. package/comate-engine/plugins/centrino/dist/help.md +0 -30
  52. package/comate-engine/plugins/centrino/dist/index.js +0 -1046
  53. package/comate-engine/plugins/centrino/package.json +0 -68
  54. package/comate-engine/plugins/cnap/assets/cnap.png +0 -0
  55. package/comate-engine/plugins/cnap/dist/help.md +0 -11
  56. package/comate-engine/plugins/cnap/dist/index.js +0 -171
  57. package/comate-engine/plugins/cnap/package.json +0 -65
  58. package/comate-engine/plugins/demo-timer/assets/icon.svg +0 -2
  59. package/comate-engine/plugins/demo-timer/dist/index.js +0 -463
  60. package/comate-engine/plugins/demo-timer/package.json +0 -73
  61. package/comate-engine/plugins/dev-tools/assets/icon.png +0 -0
  62. package/comate-engine/plugins/dev-tools/dist/help.md +0 -18
  63. package/comate-engine/plugins/dev-tools/dist/index.js +0 -166160
  64. package/comate-engine/plugins/dev-tools/package.json +0 -95
  65. package/comate-engine/plugins/devaux/assets/icon.svg +0 -1
  66. package/comate-engine/plugins/devaux/dist/help.md +0 -41
  67. package/comate-engine/plugins/devaux/dist/index.js +0 -75551
  68. package/comate-engine/plugins/devaux/dist/static/tree-sitter-cpp.wasm +0 -0
  69. package/comate-engine/plugins/devaux/dist/static/tree-sitter-go.wasm +0 -0
  70. package/comate-engine/plugins/devaux/dist/static/tree-sitter.wasm +0 -0
  71. package/comate-engine/plugins/devaux/dist/tree-sitter.wasm +0 -0
  72. package/comate-engine/plugins/devaux/package.json +0 -82
  73. package/comate-engine/plugins/f2c/assets/icon.svg +0 -11
  74. package/comate-engine/plugins/f2c/dist/help.md +0 -13
  75. package/comate-engine/plugins/f2c/dist/index.js +0 -101649
  76. package/comate-engine/plugins/f2c/package.json +0 -56
  77. package/comate-engine/plugins/fcnap/assets/icon.png +0 -0
  78. package/comate-engine/plugins/fcnap/dist/help.md +0 -9
  79. package/comate-engine/plugins/fcnap/dist/index.js +0 -105
  80. package/comate-engine/plugins/fcnap/package.json +0 -50
  81. package/comate-engine/plugins/front-end-skills/assets/icon.svg +0 -1
  82. package/comate-engine/plugins/front-end-skills/dist/help.md +0 -17
  83. package/comate-engine/plugins/front-end-skills/dist/index.js +0 -8172
  84. package/comate-engine/plugins/front-end-skills/package.json +0 -79
  85. package/comate-engine/plugins/gdp/assets/icon.png +0 -0
  86. package/comate-engine/plugins/gdp/dist/help.md +0 -11
  87. package/comate-engine/plugins/gdp/dist/index.js +0 -70806
  88. package/comate-engine/plugins/gdp/package.json +0 -80
  89. package/comate-engine/plugins/git/assets/git.svg +0 -1
  90. package/comate-engine/plugins/git/assets/icon.svg +0 -1
  91. package/comate-engine/plugins/git/dist/help.md +0 -7
  92. package/comate-engine/plugins/git/dist/index.js +0 -32765
  93. package/comate-engine/plugins/git/package.json +0 -91
  94. package/comate-engine/plugins/harmonyos/assets/harmonyos.png +0 -0
  95. package/comate-engine/plugins/harmonyos/dist/index.js +0 -78
  96. package/comate-engine/plugins/harmonyos/package.json +0 -37
  97. package/comate-engine/plugins/iapi/assets/icon.png +0 -0
  98. package/comate-engine/plugins/iapi/dist/help.md +0 -13
  99. package/comate-engine/plugins/iapi/dist/index.js +0 -458
  100. package/comate-engine/plugins/iapi/dist/static/lang/tree-sitter-go.wasm +0 -0
  101. package/comate-engine/plugins/iapi/dist/static/lang/tree-sitter-java.wasm +0 -0
  102. package/comate-engine/plugins/iapi/dist/static/tree-sitter-go.wasm +0 -0
  103. package/comate-engine/plugins/iapi/dist/static/tree-sitter-java.wasm +0 -0
  104. package/comate-engine/plugins/iapi/dist/tree-sitter.wasm +0 -0
  105. package/comate-engine/plugins/iapi/package.json +0 -102
  106. package/comate-engine/plugins/icafe/assets/icafe.svg +0 -1
  107. package/comate-engine/plugins/icafe/dist/help.md +0 -5
  108. package/comate-engine/plugins/icafe/dist/index.js +0 -885
  109. package/comate-engine/plugins/icafe/package.json +0 -74
  110. package/comate-engine/plugins/ievalue/assets/iEValue.svg +0 -10
  111. package/comate-engine/plugins/ievalue/dist/index.js +0 -2920
  112. package/comate-engine/plugins/ievalue/package.json +0 -88
  113. package/comate-engine/plugins/ipipe/assets/iPipePlugin.png +0 -0
  114. package/comate-engine/plugins/ipipe/dist/help.md +0 -15
  115. package/comate-engine/plugins/ipipe/dist/index.js +0 -7268
  116. package/comate-engine/plugins/ipipe/package.json +0 -62
  117. package/comate-engine/plugins/jarvis/assets/icon.svg +0 -1
  118. package/comate-engine/plugins/jarvis/dist/help.md +0 -17
  119. package/comate-engine/plugins/jarvis/dist/index.js +0 -140473
  120. package/comate-engine/plugins/jarvis/package.json +0 -93
  121. package/comate-engine/plugins/mapsearch/assets/mapsearchicon.png +0 -0
  122. package/comate-engine/plugins/mapsearch/dist/help.md +0 -4
  123. package/comate-engine/plugins/mapsearch/dist/index.js +0 -145
  124. package/comate-engine/plugins/mapsearch/package.json +0 -53
  125. package/comate-engine/plugins/paddle/assets/icon.png +0 -0
  126. package/comate-engine/plugins/paddle/assets/paconvert-3.0.1-py3-none-any.whl +0 -0
  127. package/comate-engine/plugins/paddle/dist/help.md +0 -31
  128. package/comate-engine/plugins/paddle/dist/index.js +0 -1011
  129. package/comate-engine/plugins/paddle/package.json +0 -129
  130. package/comate-engine/plugins/robot/assets/Robot.png +0 -0
  131. package/comate-engine/plugins/robot/dist/index.js +0 -476
  132. package/comate-engine/plugins/robot/package.json +0 -91
  133. package/comate-engine/plugins/security/assets/comate.png +0 -0
  134. package/comate-engine/plugins/security/dist/index.js +0 -18434
  135. package/comate-engine/plugins/security/package.json +0 -82
  136. package/comate-engine/plugins/smartapp/assets/icon.png +0 -0
  137. package/comate-engine/plugins/smartapp/dist/help.md +0 -4
  138. package/comate-engine/plugins/smartapp/dist/index.js +0 -113
  139. package/comate-engine/plugins/smartapp/package.json +0 -54
  140. package/comate-engine/plugins/testmate/assets/icon.svg +0 -1
  141. package/comate-engine/plugins/testmate/dist/help.md +0 -62
  142. package/comate-engine/plugins/testmate/dist/index.js +0 -21483
  143. package/comate-engine/plugins/testmate/package.json +0 -85
  144. package/comate-engine/plugins/tor/assets/TorPlugin.png +0 -0
  145. package/comate-engine/plugins/tor/dist/help.md +0 -22
  146. package/comate-engine/plugins/tor/dist/index.js +0 -807
  147. package/comate-engine/plugins/tor/package.json +0 -99
  148. package/comate-engine/plugins/weiyun/assets/icon.png +0 -0
  149. package/comate-engine/plugins/weiyun/dist/help.md +0 -11
  150. package/comate-engine/plugins/weiyun/dist/index.js +0 -100495
  151. package/comate-engine/plugins/weiyun/package.json +0 -55
  152. package/comate-engine/plugins/workcard/assets/favicon.png +0 -0
  153. package/comate-engine/plugins/workcard/dist/help.md +0 -30
  154. package/comate-engine/plugins/workcard/dist/index.js +0 -547
  155. package/comate-engine/plugins/workcard/package.json +0 -102
@@ -1,1046 +0,0 @@
1
- import { SkillProvider, StringChunkStream, TextModel } from '@comate/plugin-host';
2
- import { readFileSync } from 'fs';
3
- import { fileURLToPath } from 'node:url';
4
- import { dirname } from 'path';
5
-
6
- class HelpSkillProvider extends SkillProvider {
7
- static{
8
- this.skillName = 'help';
9
- }
10
- static{
11
- this.description = '插件介绍';
12
- }
13
- static{
14
- this.parameters = {
15
- type: 'object',
16
- properties: {}
17
- };
18
- }
19
- async *execute() {
20
- const stream = new StringChunkStream();
21
- const filename = fileURLToPath(import.meta.url);
22
- const content = readFileSync(`${dirname(filename)}/help.md`, 'utf8');
23
- yield stream.flush(content);
24
- }
25
- }
26
-
27
- const API_SERVER_HOST = 'http://youfang-new.baidu-int.com';
28
- const apiRequest$1 = async (method, path, options = {}, timeout = 5000)=>{
29
- try {
30
- const response = await fetch(`${API_SERVER_HOST}${path}`, {
31
- method,
32
- ...options,
33
- signal: AbortSignal.timeout(timeout)
34
- });
35
- if (!response.ok) {
36
- throw new Error(`[${response.status}] 请求错误。请求参数:${JSON.stringify({
37
- method,
38
- path,
39
- ...options
40
- })}`);
41
- }
42
- const jsonRes = await response.json();
43
- // console.log('------ api response: ', jsonRes);
44
- return jsonRes;
45
- } catch (err) {
46
- // console.log('------ api err: ', err);
47
- throw err;
48
- }
49
- };
50
- const queryKnowledgeConfig = (username, icode, source)=>{
51
- return apiRequest$1('GET', `/api/v1/products/centrino/comate/knowledge?icode=${icode}&source=${source}`, {
52
- headers: {
53
- 'X-COMATE-USER': username
54
- }
55
- });
56
- };
57
- const setKnowledgeConfig = (username, body)=>{
58
- return apiRequest$1('POST', `/api/v1/products/centrino/comate/knowledge`, {
59
- headers: {
60
- 'X-COMATE-USER': username,
61
- 'Content-Type': 'application/json'
62
- },
63
- body: JSON.stringify(body)
64
- });
65
- };
66
- const createTask = (username, body)=>{
67
- return apiRequest$1('POST', `/api/v1/products/centrino/comate/task`, {
68
- headers: {
69
- 'X-COMATE-USER': username,
70
- 'Content-Type': 'application/json'
71
- },
72
- body: JSON.stringify(body)
73
- });
74
- };
75
- const updateTaskStatus = (username, body)=>{
76
- return apiRequest$1('POST', `/api/v1/products/centrino/comate/task`, {
77
- headers: {
78
- 'X-COMATE-USER': username,
79
- 'Content-Type': 'application/json'
80
- },
81
- body: JSON.stringify(body)
82
- });
83
- };
84
- const updateTaskKnowledge = (username, body)=>{
85
- return apiRequest$1('POST', `/api/v1/products/centrino/comate/task`, {
86
- headers: {
87
- 'X-COMATE-USER': username,
88
- 'Content-Type': 'application/json'
89
- },
90
- body: JSON.stringify(body)
91
- });
92
- };
93
- const getTaskDetail = (username, taskId)=>{
94
- return apiRequest$1('GET', `/api/v1/products/centrino/comate/task?task_id=${taskId}`, {
95
- headers: {
96
- 'X-COMATE-USER': username
97
- }
98
- });
99
- };
100
- const addKnowledgeAB = (username, body)=>{
101
- return apiRequest$1('POST', `/api/v1/products/centrino/comate/ab/knowledge`, {
102
- headers: {
103
- 'X-COMATE-USER': username,
104
- 'Content-Type': 'application/json'
105
- },
106
- body: JSON.stringify(body)
107
- }, 600000);
108
- };
109
-
110
- class knowledgeConfigSkillProvider extends SkillProvider {
111
- static{
112
- this.skillName = 'konwledgeConfig';
113
- }
114
- static{
115
- this.displayName = '知识库配置';
116
- }
117
- static{
118
- this.description = '为当前项目绑定私域知识库ID,或查询绑定状态';
119
- }
120
- static{
121
- this.parameters = {
122
- type: 'object',
123
- properties: {}
124
- };
125
- }
126
- async *execute() {
127
- const userDetail = await this.currentUser.requestDetail() || {
128
- name: "",
129
- email: 'xxx@baidu.com'
130
- };
131
- const { activeFilePath, selectedCode, activeFileLanguage, query } = this.currentContext;
132
- const stream = new StringChunkStream();
133
- // 获取仓库信息
134
- const repository = await this.retriever.repositoryInfo();
135
- let repositoryUrl;
136
- if (repository.versionControl === 'git') {
137
- repositoryUrl = repository.repositoryUrl;
138
- const matched = repositoryUrl?.match(/baidu\/.*\/.*/);
139
- if (matched?.length) {
140
- repositoryUrl = matched[0];
141
- }
142
- }
143
- if (!repositoryUrl) {
144
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个iCode仓库或者缺少.git配置目录');
145
- return;
146
- }
147
- try {
148
- // 绑定(或更新)私域知识库
149
- if (this.isValidUUID(query)) {
150
- const response = await setKnowledgeConfig(userDetail.name, {
151
- icode: repositoryUrl,
152
- source: 'comate',
153
- knowledgeId: query,
154
- createUser: userDetail.name
155
- });
156
- if (!response || !response.knowledgeId) {
157
- yield stream.flushReplaceLast('私域知识绑定失败,请联系管理员查看');
158
- } else {
159
- yield stream.flushReplaceLast('私域知识绑定成功。\n\n' + '可输入用例描述信息,进行知识检索结果验证;\n\n' + '可通过指令 **/用例生成** 尝试生成测试用例。');
160
- }
161
- return;
162
- }
163
- // 查询当前代码库绑定的知识集ID
164
- const knowledgeConfig = await queryKnowledgeConfig(userDetail.name, repositoryUrl, 'comate');
165
- if (!knowledgeConfig || !knowledgeConfig.knowledgeId) {
166
- yield stream.flushReplaceLast('当前代码库未绑定私域知识,请输入知识集ID进行绑定\n\n若无知识集,可前往 [Comate知识中心]' + '(https://comate.baidu-int.com/cop/knowledge/list)创建并添加知识');
167
- return;
168
- }
169
- if (query.length === 0) {
170
- // 查询知识库
171
- yield stream.flushReplaceLast(`当前代码库已绑定私域知识:[${knowledgeConfig.knowledgeId}](https://comate.baidu-int.com/cop/knowledge/` + `detail/NORMAL/${knowledgeConfig.knowledgeId})\n\n若无访问权限,请联系业务负责人或管理员`);
172
- return;
173
- } else {
174
- yield stream.flushReplaceLast('私域知识检索中...');
175
- //检索知识测试
176
- let queryWithCode = query;
177
- // 拼接query与选中代码
178
- if (selectedCode) {
179
- queryWithCode = `${query}\n\`\`\`${activeFileLanguage}\n${selectedCode}\n\`\`\``;
180
- }
181
- let queryCodePrompt = `请根据下列用例步骤描述检索出相关的函数或引用\n${query}`;
182
- const [knowledge, code] = await Promise.all([
183
- this.retriever.knowledgeFromQuery(queryWithCode, {
184
- knowledgeSets: [
185
- {
186
- uuid: knowledgeConfig.knowledgeId,
187
- type: 'NORMAL'
188
- }
189
- ],
190
- queryRewrite: true
191
- }),
192
- this.retriever.codeFromQuery(queryCodePrompt, {
193
- knowledgeSets: [
194
- {
195
- uuid: knowledgeConfig.knowledgeId,
196
- type: 'NORMAL'
197
- }
198
- ],
199
- queryRewrite: false
200
- })
201
- ]);
202
- yield stream.flushReplaceLast('只返回top6个知识点\n\n');
203
- let index = 1;
204
- for(let i = 0; i < knowledge.length; i++){
205
- if (i >= 6) {
206
- break;
207
- }
208
- index = i + 1;
209
- yield stream.flush(`# 知识${index}\n\n`);
210
- yield stream.flush(knowledge[i]);
211
- yield stream.flush('\n\n');
212
- }
213
- }
214
- } catch (error) {
215
- yield stream.flushReplaceLast('出现错误,请稍后再试');
216
- }
217
- }
218
- trimKnowledge(list, maxCount = 6, maxLength = 10000) {
219
- const state = {
220
- length: 0
221
- };
222
- const output = [];
223
- for (const item of list){
224
- if (state.length + item.length > maxLength || output.length >= maxCount) {
225
- break;
226
- }
227
- output.push(item);
228
- state.length += item.length;
229
- }
230
- return output;
231
- }
232
- isValidUUID(uuid) {
233
- // UUID v4 regex pattern
234
- const uuidPattern = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89aAbB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;
235
- // Use .match to check if the UUID matches the pattern
236
- return uuid.match(uuidPattern) !== null;
237
- }
238
- }
239
-
240
- var promptTemplate = "你是一位资深的{{frame}}自动化测试技术专家。你的核心职责是理解输出代码示例、并根据需解答的问题及回答要求生成一个自动化测试用例代码。在解答问题前,你会收到多个背景知识和一个具体的问题。\n* 在提供的背景知识中,将通过『##』明确标注需要参考的信息类型。例如,`## 编程语言`表示提问者当前使用的编程语言,`## 参考文档片段`表示引用特定的文档内容,`## 输出代码示例`表示需要输出的代码样式示例。准确识别这些信息对于解答问题至关重要。\n\n# 背景知识\n## 编程语言\n{{activeFileLanguage}}\n\n## 参考文档片段\n{{trim_knowledge}}\n\n## 输出代码示例\n{{templateCaseCode}}\n\n# 回答要求\n1. 请参考所提供的背景知识来回答问题,但不要提及你参考了这些背景知识,因为背景知识对提问者是不可见的。\n2. 保持简洁,直接、明确地回应问题,避免复述问题本身。\n3. 回答中如包含代码,应优先使用背景知识中的封装函数来实现。若使用了非背景知识中的函数,请输出相应代码。\n4. 请保证引用包和代码逻辑的语法正确性,并应减少文字解释,必要的解释以代码注释形式给出。\n4. 回答中如包含代码,则请参考示例代码的样式进行输出,且单行不超过120字符。代码应作为完整块展示,避免分割解释。\n5. 回答中如有时间信息,请更新为当前时间;若提及用户名信息,请更新为{{email}};若用例名中有编号,请递增编号。\n6. 使用Markdown格式编排回答,确保逻辑清晰。对于代码块,请采用标准的Markdown代码块格式,并指定编程语言,例如:\n```python\n# 这是一个Python代码块示例\n```\n\n# 需解答的问题\n请根据如下用例步骤信息生成一个测试用例:\n{{query}}";
241
-
242
- class CaseByCaseSkillProvider extends SkillProvider {
243
- static{
244
- this.skillName = 'genCaseByCase';
245
- }
246
- static{
247
- this.displayName = '用例生成';
248
- }
249
- static{
250
- this.description = '基于用例功能和步骤描述生成用例';
251
- }
252
- static{
253
- this.parameters = {
254
- type: 'object',
255
- properties: {}
256
- };
257
- }
258
- async *execute() {
259
- const userDetail = await this.currentUser.requestDetail() || {
260
- name: "",
261
- email: 'xxx@baidu.com'
262
- };
263
- const email = userDetail.email;
264
- let { activeFilePath, selectedCode, activeFileLanguage, query } = this.currentContext;
265
- query = query.trim();
266
- selectedCode = selectedCode.trim();
267
- const stream = new StringChunkStream();
268
- // 入参校验
269
- if (query.length === 0) {
270
- yield stream.flush("用例步骤描述不可为空,请输入并重试");
271
- return;
272
- }
273
- if (selectedCode === '') {
274
- yield stream.flush('(选中一段用例代码作为示例,有助于统一代码风格)\n\n');
275
- // return;
276
- }
277
- // 获取仓库信息
278
- const repository = await this.retriever.repositoryInfo();
279
- let repositoryUrl;
280
- if (repository.versionControl === 'git') {
281
- repositoryUrl = repository.repositoryUrl;
282
- const matched = repositoryUrl?.match(/baidu\/.*\/.*/);
283
- if (matched?.length) {
284
- repositoryUrl = matched[0];
285
- }
286
- }
287
- if (!repositoryUrl) {
288
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个iCode仓库或者缺少.git配置目录');
289
- return;
290
- }
291
- // 打点:初始化
292
- let taskInfo = await createTask(userDetail.name, {
293
- conversationId: '',
294
- icode: repositoryUrl,
295
- query: query,
296
- selected: selectedCode,
297
- knowledge: '',
298
- frame: '',
299
- language: activeFileLanguage,
300
- status: 'init',
301
- createUser: userDetail.name
302
- });
303
- if (!taskInfo || !taskInfo.taskId) {
304
- yield stream.flush('打点失败,不影响生成\n\n');
305
- }
306
- // 查询当前代码库绑定的知识集ID
307
- const knowledgeConfig = await queryKnowledgeConfig(userDetail.name, repositoryUrl, 'comate');
308
- if (!knowledgeConfig || !knowledgeConfig.knowledgeId) {
309
- yield stream.flushReplaceLast('请通过指令 **/知识库** 为当前代码仓库绑定知识集ID。去创建知识:[Comate知识中心](https://comate.baidu-int.com/cop/knowledge/list)');
310
- return;
311
- }
312
- // 框架
313
- let frame = knowledgeConfig.frame;
314
- if (frame !== '') {
315
- frame = frame + '框架';
316
- } else {
317
- frame = 'pytest框架';
318
- }
319
- // yield stream.flush('若超时未响应,请尝试重新生成\n\n');
320
- // 打点:running
321
- if (taskInfo && taskInfo.taskId) {
322
- await updateTaskStatus(userDetail.name, {
323
- taskId: taskInfo.taskId,
324
- status: 'running'
325
- });
326
- }
327
- // 拆解步骤
328
- const [queryFunc, querySteps] = this.parseQueryStep(query);
329
- let knowledgeList = [];
330
- const maxCount = Math.max(Math.floor(10 / querySteps.length), 1);
331
- // 记录开始时间
332
- const startTime = performance.now();
333
- try {
334
- yield stream.flush(`检索知识`);
335
- for(let i = 0; i < querySteps.length; i++){
336
- const retreiveTemplate = '请根据下列描述信息检索出相关的函数或引用,并根据相关性排序,描述如下:';
337
- let queryCodePrompt = `${retreiveTemplate}\n${querySteps[i]}`;
338
- if (queryFunc.length > 0) {
339
- queryCodePrompt = `${retreiveTemplate}\n${queryFunc}:${querySteps[i]}`;
340
- }
341
- yield stream.flush(`.`);
342
- const [knowledge] = await Promise.all([
343
- this.retriever.knowledgeFromQuery(queryCodePrompt, {
344
- knowledgeSets: [
345
- {
346
- uuid: knowledgeConfig.knowledgeId,
347
- type: 'NORMAL'
348
- }
349
- ],
350
- queryRewrite: true
351
- })
352
- ]);
353
- knowledgeList = this.updateKnowledgeList(knowledgeList, knowledge, maxCount);
354
- }
355
- yield stream.flush(`\n\n检索完成\n\n`);
356
- // 记录结束时间
357
- const retriveTime = performance.now();
358
- // 计算执行时长
359
- let duration = retriveTime - startTime;
360
- const trim_knowledge = this.trimKnowledge(knowledgeList, 9);
361
- // const trim_code = this.trimKnowledge(code, 5, 3000);
362
- const trim_code = '';
363
- let templateCaseCode = `\`\`\`${activeFileLanguage}\n${selectedCode}\n\`\`\``;
364
- const prompt = this.llm.createPrompt(promptTemplate, {
365
- frame,
366
- activeFileLanguage,
367
- trim_knowledge: trim_knowledge.join('\n\n'),
368
- templateCaseCode,
369
- email,
370
- query
371
- });
372
- const chunks = this.llm.askForTextStreaming(prompt, {
373
- model: TextModel.Default
374
- });
375
- yield stream.flushReplaceLast('\n\n');
376
- for await (const chunk of chunks){
377
- yield stream.flush(chunk);
378
- }
379
- // 记录结束时间
380
- const endTime = performance.now();
381
- // 计算执行时长
382
- duration = endTime - retriveTime;
383
- // 打点:success
384
- if (taskInfo && taskInfo.taskId) {
385
- let response = await updateTaskStatus(userDetail.name, {
386
- taskId: taskInfo.taskId,
387
- status: 'success'
388
- });
389
- }
390
- } catch (error) {
391
- yield stream.flushReplaceLast('出现错误,请稍后再试');
392
- // 打点:fail
393
- if (taskInfo && taskInfo.taskId) {
394
- await updateTaskStatus(userDetail.name, {
395
- taskId: taskInfo.taskId,
396
- status: 'fail'
397
- });
398
- }
399
- }
400
- }
401
- trimKnowledge(list, maxCount = 6, maxLength = 10000) {
402
- const state = {
403
- length: 0
404
- };
405
- const output = [];
406
- for (const item of list){
407
- if (state.length + item.length > maxLength || output.length >= maxCount) {
408
- break;
409
- }
410
- output.push(item);
411
- state.length += item.length;
412
- }
413
- return output;
414
- }
415
- parseQueryStep(queryRaw) {
416
- if (queryRaw === '') {
417
- return [
418
- '',
419
- []
420
- ];
421
- }
422
- let queryFuncDesc = '';
423
- const list = queryRaw.split('\n');
424
- if (!queryRaw.startsWith('1')) {
425
- queryFuncDesc = list[0];
426
- list.splice(0, 1);
427
- // if (!queryFuncDesc.includes('步骤')) {
428
- // queryFuncDesc = queryFuncDesc + ',步骤描述如下:';
429
- // }
430
- }
431
- for(let i = 0; i < list.length; i++){
432
- list[i] = list[i].trim();
433
- }
434
- return [
435
- queryFuncDesc,
436
- list
437
- ];
438
- }
439
- updateKnowledgeList(knowledgeList, knowledge, maxCount) {
440
- // 使用 Set 去除 knowledgeList 中的重复项并方便快速查找
441
- const knowledgeSet = new Set(knowledgeList);
442
- // 新知识去重
443
- const newKnowledgeSet = new Set(knowledge);
444
- const newKnowledge = [
445
- ...newKnowledgeSet
446
- ];
447
- // 过滤掉已经在 knowledgeList 中的新知识,并限制最大数量为 maxCount
448
- const newKnowledgeList = newKnowledge.filter((k)=>!knowledgeSet.has(k)).slice(0, maxCount);
449
- // 将新知识合并到旧知识列表中
450
- return [
451
- ...knowledgeList,
452
- ...newKnowledgeList
453
- ];
454
- }
455
- }
456
-
457
- const AB_AUTH = 'Bearer bce-v3/ALTAK-wPXaAeVTpgBy9uLMFHtII/6860c1ecfe6aa6c6366e374057f51bf5b5400dd4';
458
- const AB_KNOWLEDGE_APP_ID = '8c0358d9-8854-4e53-96a2-5bf8bf966913';
459
- const AB_CASE_APP_ID = 'c3d7d0ad-39cc-4ca1-8912-8ad2f3b1cf49';
460
-
461
- function createParser(onParse) {
462
- let isFirstChunk, buffer, startingPosition, startingFieldLength, eventId, eventName, data;
463
- return reset(), { feed, reset };
464
- function reset() {
465
- isFirstChunk = !0, buffer = "", startingPosition = 0, startingFieldLength = -1, eventId = void 0, eventName = void 0, data = "";
466
- }
467
- function feed(chunk) {
468
- buffer = buffer ? buffer + chunk : chunk, isFirstChunk && hasBom(buffer) && (buffer = buffer.slice(BOM.length)), isFirstChunk = !1;
469
- const length = buffer.length;
470
- let position = 0, discardTrailingNewline = !1;
471
- for (; position < length; ) {
472
- discardTrailingNewline && (buffer[position] === `
473
- ` && ++position, discardTrailingNewline = !1);
474
- let lineLength = -1, fieldLength = startingFieldLength, character;
475
- for (let index = startingPosition; lineLength < 0 && index < length; ++index)
476
- character = buffer[index], character === ":" && fieldLength < 0 ? fieldLength = index - position : character === "\r" ? (discardTrailingNewline = !0, lineLength = index - position) : character === `
477
- ` && (lineLength = index - position);
478
- if (lineLength < 0) {
479
- startingPosition = length - position, startingFieldLength = fieldLength;
480
- break;
481
- } else
482
- startingPosition = 0, startingFieldLength = -1;
483
- parseEventStreamLine(buffer, position, fieldLength, lineLength), position += lineLength + 1;
484
- }
485
- position === length ? buffer = "" : position > 0 && (buffer = buffer.slice(position));
486
- }
487
- function parseEventStreamLine(lineBuffer, index, fieldLength, lineLength) {
488
- if (lineLength === 0) {
489
- data.length > 0 && (onParse({
490
- type: "event",
491
- id: eventId,
492
- event: eventName || void 0,
493
- data: data.slice(0, -1)
494
- // remove trailing newline
495
- }), data = "", eventId = void 0), eventName = void 0;
496
- return;
497
- }
498
- const noValue = fieldLength < 0, field = lineBuffer.slice(index, index + (noValue ? lineLength : fieldLength));
499
- let step = 0;
500
- noValue ? step = lineLength : lineBuffer[index + fieldLength + 1] === " " ? step = fieldLength + 2 : step = fieldLength + 1;
501
- const position = index + step, valueLength = lineLength - step, value = lineBuffer.slice(position, position + valueLength).toString();
502
- if (field === "data")
503
- data += value ? `${value}
504
- ` : `
505
- `;
506
- else if (field === "event")
507
- eventName = value;
508
- else if (field === "id" && !value.includes("\0"))
509
- eventId = value;
510
- else if (field === "retry") {
511
- const retry = parseInt(value, 10);
512
- Number.isNaN(retry) || onParse({ type: "reconnect-interval", value: retry });
513
- }
514
- }
515
- }
516
- const BOM = [239, 187, 191];
517
- function hasBom(buffer) {
518
- return BOM.every((charCode, index) => buffer.charCodeAt(index) === charCode);
519
- }
520
-
521
- class EventSourceParserStream extends TransformStream {
522
- constructor() {
523
- let parser;
524
- super({
525
- start(controller) {
526
- parser = createParser((event) => {
527
- event.type === "event" && controller.enqueue(event);
528
- });
529
- },
530
- transform(chunk) {
531
- parser.feed(chunk);
532
- }
533
- });
534
- }
535
- }
536
-
537
- const AB_SERVER_HOST = 'https://qianfan.baidubce.com';
538
- const apiRequest = async (method, path, options = {}, timeout = 20000)=>{
539
- try {
540
- const response = await fetch(`${AB_SERVER_HOST}${path}`, {
541
- method,
542
- ...options,
543
- signal: AbortSignal.timeout(timeout)
544
- });
545
- if (!response.ok) {
546
- throw new Error(`[${response.status}] 请求错误。请求参数:${JSON.stringify({
547
- method,
548
- path,
549
- ...options
550
- })}`);
551
- }
552
- const jsonRes = await response.json();
553
- // console.log('------ api response: ', jsonRes);
554
- return jsonRes;
555
- } catch (err) {
556
- // console.error('------ api error: ', err);
557
- throw err;
558
- }
559
- };
560
- async function* abSteamRequest(method, path, options = {}) {
561
- try {
562
- const response = await fetch(`${AB_SERVER_HOST}${path}`, {
563
- method,
564
- headers: {
565
- 'Content-Type': 'application/json'
566
- },
567
- ...options
568
- });
569
- if (!response.ok) {
570
- throw new Error(`[${response.status}] 请求错误。请求参数:${JSON.stringify({
571
- method,
572
- path,
573
- ...options
574
- })}`);
575
- }
576
- if (!response.body) {
577
- throw new Error(`[${response.status}] 响应体错误。请求参数:${JSON.stringify({
578
- method,
579
- path,
580
- ...options
581
- })}`);
582
- }
583
- // 兼容非流式返回的处理逻辑
584
- const contentType = response.headers.get("Content-Type");
585
- if (contentType?.indexOf("application/json") !== -1) {
586
- const jsonRes = response.json();
587
- yield jsonRes.then((res)=>{
588
- if (res.code !== 'OK') {
589
- throw new Error(`[${res.code}] ${res.message}`);
590
- } else {
591
- return res.data;
592
- }
593
- });
594
- }
595
- const resBody = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream());
596
- const reader = resBody.getReader();
597
- try {
598
- while(true){
599
- const { value, done } = await reader.read();
600
- if (done) {
601
- break;
602
- }
603
- const text = value?.type === 'event' ? JSON.parse(value.data).answer : undefined;
604
- if (!text) {
605
- continue;
606
- }
607
- yield text;
608
- }
609
- } catch (e) {
610
- throw e;
611
- } finally{
612
- reader.releaseLock();
613
- }
614
- } catch (err) {
615
- throw err;
616
- }
617
- }
618
- const initABChat = (auth, body)=>{
619
- return apiRequest('POST', `/v2/app/conversation`, {
620
- headers: {
621
- 'Content-Type': 'application/json',
622
- 'X-Appbuilder-Authorization': auth
623
- },
624
- body: JSON.stringify(body)
625
- });
626
- };
627
- const runABChat = (auth, body)=>{
628
- body.query = JSON.stringify(body.query);
629
- return apiRequest('POST', `/v2/app/conversation/runs`, {
630
- headers: {
631
- 'Content-Type': 'application/json',
632
- 'X-Appbuilder-Authorization': auth
633
- },
634
- body: JSON.stringify(body)
635
- });
636
- };
637
- const runABChatStream = (auth, body)=>{
638
- console.log('runABChatStream body:', body);
639
- const res = abSteamRequest('POST', `/v2/app/conversation/runs`, {
640
- headers: {
641
- 'Content-Type': 'application/json',
642
- 'X-Appbuilder-Authorization': auth
643
- },
644
- body: JSON.stringify(body)
645
- });
646
- return res;
647
- };
648
-
649
- class CaseABSkillProvider extends SkillProvider {
650
- static{
651
- this.skillName = 'genCaseAB';
652
- }
653
- static{
654
- this.displayName = '用例生成New';
655
- }
656
- static{
657
- this.description = '基于用例功能和步骤描述生成用例';
658
- }
659
- static{
660
- this.parameters = {
661
- type: 'object',
662
- properties: {}
663
- };
664
- }
665
- async *execute() {
666
- const userDetail = await this.currentUser.requestDetail() || {
667
- name: "",
668
- email: 'xxx@baidu.com'
669
- };
670
- userDetail.email;
671
- let { selectedCode, activeFileLanguage, query } = this.currentContext;
672
- query = query.trim();
673
- selectedCode = selectedCode.trim();
674
- const stream = new StringChunkStream();
675
- // 入参校验
676
- if (query.length === 0) {
677
- yield stream.flush("用例步骤描述不可为空,请输入并重试");
678
- return;
679
- }
680
- if (selectedCode === '') {
681
- yield stream.flush('(选中一段用例代码作为示例,有助于统一代码风格)\n\n');
682
- // return;
683
- }
684
- // 回放模式
685
- try {
686
- if (Number(query) > 0) {
687
- yield stream.flushReplaceLast(' **进入了回放模式(debug)** \n\n');
688
- let taskDetail = await getTaskDetail(userDetail.name, query);
689
- if (!taskDetail || !taskDetail.conversationId) {
690
- yield stream.flush(`获取任务记录失败,任务ID:${query}\n\n`);
691
- return;
692
- }
693
- // 生成对话
694
- const caseChunks = runABChatStream(AB_AUTH, {
695
- app_id: AB_CASE_APP_ID,
696
- conversation_id: taskDetail?.conversationId,
697
- query: query,
698
- stream: true
699
- });
700
- yield stream.flush('将基于历史任务记录,直接进入LLM用例生成节点\n\n');
701
- for await (const chunk of caseChunks){
702
- yield stream.flush(chunk);
703
- }
704
- yield stream.flush('\n\n');
705
- return;
706
- }
707
- } catch (error) {
708
- yield stream.flush('回放失败,请确认任务ID是否存在');
709
- return;
710
- }
711
- yield stream.flush('知识库配置检查•••');
712
- // 获取仓库信息
713
- const repository = await this.retriever.repositoryInfo();
714
- let repositoryUrl;
715
- if (repository.versionControl === 'git') {
716
- repositoryUrl = repository.repositoryUrl;
717
- const matched = repositoryUrl?.match(/baidu\/.*\/.*/);
718
- if (matched?.length) {
719
- repositoryUrl = matched[0];
720
- }
721
- }
722
- if (!repositoryUrl) {
723
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个iCode仓库或者缺少.git配置目录');
724
- return;
725
- }
726
- // 打点:init
727
- let taskInfo = await createTask(userDetail.name, {
728
- conversationId: '',
729
- icode: repositoryUrl,
730
- query: query,
731
- selected: selectedCode,
732
- knowledge: '',
733
- frame: '',
734
- language: activeFileLanguage,
735
- status: 'init',
736
- createUser: userDetail.name
737
- });
738
- if (!taskInfo || !taskInfo.taskId) {
739
- yield stream.flush('创建任务失败\n\n');
740
- return;
741
- }
742
- // 查询当前代码库绑定的知识集ID
743
- const knowledgeConfig = await queryKnowledgeConfig(userDetail.name, repositoryUrl, 'ab');
744
- if (!knowledgeConfig || !knowledgeConfig.knowledgeId) {
745
- yield stream.flushReplaceLast('\n\n ** 请联系管理员为当前库添加知识库配置,用于添加私域知识 ** \n\n');
746
- return;
747
- } else {
748
- yield stream.flush('done\n\n');
749
- }
750
- // 框架
751
- let frame = knowledgeConfig.frame;
752
- if (frame !== '' && frame !== 'undefined') {
753
- frame = frame + '框架';
754
- } else {
755
- frame = 'pytest框架';
756
- }
757
- // 打点:running
758
- await updateTaskStatus(userDetail.name, {
759
- taskId: taskInfo.taskId,
760
- status: 'running'
761
- });
762
- // 拆解步骤
763
- const [queryFunc, querySteps] = this.parseQueryStep(query);
764
- let knowledgeList = [];
765
- const maxKnowledgeCount = 20;
766
- const maxKnowledgeLength = 20000;
767
- const maxCount = Math.max(Math.floor(maxKnowledgeCount / querySteps.length), 1);
768
- // 记录开始时间
769
- const startTime = performance.now();
770
- try {
771
- // 创建检索会话
772
- const chatInfo = await initABChat(AB_AUTH, {
773
- app_id: AB_KNOWLEDGE_APP_ID
774
- });
775
- if (!chatInfo || !chatInfo.conversation_id) {
776
- yield stream.flushReplaceLast('创建会话失败,请联系管理员\n\n');
777
- return;
778
- }
779
- yield stream.flush(`检索知识`);
780
- for(let i = 0; i < querySteps.length; i++){
781
- const retreiveTemplate = '请检索函数或步骤:';
782
- let queryCodePrompt = `${retreiveTemplate}\n${querySteps[i]}`;
783
- if (queryFunc.length > 0) {
784
- queryCodePrompt = `${retreiveTemplate}:${querySteps[i]}\n${queryFunc}`;
785
- }
786
- yield stream.flush(`${i + 1}`);
787
- // 知识检索对话
788
- const chatResp = await runABChat(AB_AUTH, {
789
- app_id: AB_KNOWLEDGE_APP_ID,
790
- conversation_id: chatInfo.conversation_id,
791
- query: {
792
- icode: repositoryUrl,
793
- query: queryCodePrompt,
794
- selected: selectedCode,
795
- username: userDetail.name
796
- },
797
- stream: false
798
- });
799
- if (chatResp?.answer === undefined || chatResp?.answer === null) {
800
- yield stream.flushReplaceLast('检索知识失败\n\n');
801
- return;
802
- }
803
- const knowledge = this.parseKnowledge(chatResp.answer);
804
- knowledgeList = this.updateKnowledgeList(knowledgeList, knowledge, maxCount);
805
- yield stream.flushReplaceLast(`•`);
806
- }
807
- yield stream.flush(`done\n\n`);
808
- // 记录结束时间
809
- const retriveTime = performance.now();
810
- // 计算执行时长
811
- let duration = retriveTime - startTime;
812
- if (knowledgeList.length === 0) {
813
- yield stream.flushReplaceLast(' **未检索到任何相关知识,无法生成用例** \n\n请确认是否已配置知识库且添加了知识,否则请联系管理员\n\n');
814
- return;
815
- }
816
- const trim_knowledge = this.trimKnowledge(knowledgeList, maxKnowledgeCount, maxKnowledgeLength);
817
- // 创建生成会话
818
- const caseChatInfo = await initABChat(AB_AUTH, {
819
- app_id: AB_CASE_APP_ID
820
- });
821
- if (!caseChatInfo || !caseChatInfo.conversation_id) {
822
- yield stream.flushReplaceLast('创建用例生成会话失败,请联系管理员\n\n');
823
- return;
824
- }
825
- // 打点:记录数据
826
- let taskResponse = await updateTaskKnowledge(userDetail.name, {
827
- taskId: taskInfo.taskId,
828
- conversation_id: caseChatInfo.conversation_id,
829
- knowledge: trim_knowledge.join('\n\n'),
830
- frame: frame
831
- });
832
- // 用例对话会通过api获取知识等信息,sleep 0.5s打一个时间差
833
- // await this.sleep(500);
834
- yield stream.flush('生成中•••\n\n');
835
- // 开始用例对话
836
- const caseChunks = runABChatStream(AB_AUTH, {
837
- app_id: AB_CASE_APP_ID,
838
- conversation_id: caseChatInfo.conversation_id,
839
- query: String(taskInfo.taskId),
840
- stream: true
841
- });
842
- // 输出stream内容
843
- yield stream.flushReplaceLast(`\n\n`);
844
- for await (const chunk of caseChunks){
845
- yield stream.flush(chunk);
846
- }
847
- yield stream.flush('\n\n');
848
- // 记录结束时间
849
- const endTime = performance.now();
850
- // 计算执行时长
851
- duration = endTime - retriveTime;
852
- // 打点:success
853
- let response = await updateTaskStatus(userDetail.name, {
854
- taskId: taskInfo.taskId,
855
- status: 'success'
856
- });
857
- } catch (error) {
858
- yield stream.flushReplaceLast('出现错误,请稍后再试');
859
- // 打点:fail
860
- await updateTaskStatus(userDetail.name, {
861
- taskId: taskInfo.taskId,
862
- status: 'fail'
863
- });
864
- }
865
- }
866
- trimKnowledge(list, maxCount = 6, maxLength = 20000) {
867
- const state = {
868
- length: 0
869
- };
870
- const output = [];
871
- for (const item of list){
872
- if (state.length + item.length > maxLength || output.length >= maxCount) {
873
- break;
874
- }
875
- output.push(item);
876
- state.length += item.length;
877
- }
878
- return output;
879
- }
880
- parseQueryStep(queryRaw) {
881
- if (queryRaw === '') {
882
- return [
883
- '',
884
- []
885
- ];
886
- }
887
- let queryFuncDesc = '';
888
- const list = queryRaw.split('\n');
889
- if (!queryRaw.startsWith('1')) {
890
- queryFuncDesc = list[0];
891
- list.splice(0, 1);
892
- // if (!queryFuncDesc.includes('步骤')) {
893
- // queryFuncDesc = queryFuncDesc + ',步骤描述如下:';
894
- // }
895
- }
896
- for(let i = 0; i < list.length; i++){
897
- list[i] = list[i].trim();
898
- }
899
- return [
900
- queryFuncDesc,
901
- list
902
- ];
903
- }
904
- updateKnowledgeList(knowledgeList, knowledge, maxCount) {
905
- // 过滤掉不是函数名和步骤名的知识
906
- let rawKnowledge = knowledge.map((str)=>str.trim()).filter((str)=>str.includes("函数名") || str.includes("步骤名"));
907
- // 使用 Set 去除 knowledgeList 中的重复项并方便快速查找
908
- const knowledgeSet = new Set(knowledgeList);
909
- // 新知识去重
910
- const newKnowledgeSet = new Set(rawKnowledge);
911
- const newKnowledge = [
912
- ...newKnowledgeSet
913
- ];
914
- // 过滤掉已经在 knowledgeList 中的新知识,并限制最大数量为 maxCount
915
- const newKnowledgeList = newKnowledge.filter((k)=>!knowledgeSet.has(k)).slice(0, maxCount);
916
- // 将新知识合并到旧知识列表中
917
- return [
918
- ...knowledgeList,
919
- ...newKnowledgeList
920
- ];
921
- }
922
- parseKnowledge(answer) {
923
- if (answer === '') {
924
- return [];
925
- }
926
- const jsonObject = JSON.parse(answer);
927
- if (jsonObject && jsonObject.knowledge) {
928
- return jsonObject.knowledge;
929
- }
930
- return [];
931
- }
932
- sleep(ms) {
933
- return new Promise((resolve)=>setTimeout(resolve, ms));
934
- }
935
- }
936
-
937
- class addKnowledgeSkillProvider extends SkillProvider {
938
- static{
939
- this.skillName = 'addKonwledge';
940
- }
941
- static{
942
- this.displayName = '添加知识';
943
- }
944
- static{
945
- this.description = '将函数或用例代码转化为知识文本,添加到知识库中';
946
- }
947
- static{
948
- this.parameters = {
949
- type: 'object',
950
- properties: {}
951
- };
952
- }
953
- async *execute() {
954
- const userDetail = await this.currentUser.requestDetail() || {
955
- name: "",
956
- email: 'xxx@baidu.com'
957
- };
958
- const { activeFilePath, selectedCode, activeFileLanguage, query } = this.currentContext;
959
- const stream = new StringChunkStream();
960
- if (selectedCode === "" && query === '') {
961
- yield stream.flushReplaceLast('请选中或输入一段代码,再重试\n\n代码片段类型:完整的函数片段或一个用例的完整代码');
962
- return;
963
- }
964
- // 获取仓库信息
965
- const repository = await this.retriever.repositoryInfo();
966
- let repositoryUrl;
967
- if (repository.versionControl === 'git') {
968
- repositoryUrl = repository.repositoryUrl;
969
- const matched = repositoryUrl?.match(/baidu\/.*\/.*/);
970
- if (matched?.length) {
971
- repositoryUrl = matched[0];
972
- }
973
- }
974
- if (!repositoryUrl) {
975
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个iCode仓库或者缺少.git配置目录');
976
- return;
977
- }
978
- try {
979
- // 查询当前代码库绑定的知识集ID
980
- const knowledgeConfig = await queryKnowledgeConfig(userDetail.name, repositoryUrl, 'ab');
981
- if (!knowledgeConfig || !knowledgeConfig.knowledgeId) {
982
- yield stream.flushReplaceLast('当前代码库不支持使用,请联系管理员添加配置');
983
- return;
984
- }
985
- // 文本长度限制
986
- const contentLines = selectedCode.split('\n');
987
- if (contentLines.length > 500) {
988
- yield stream.flushReplaceLast('代码行数过长,请控制在500行以内,再重试');
989
- }
990
- yield stream.flushReplaceLast('执行时间与代码行数正相关,请耐心等待\n\n');
991
- // TODO 调用service接口,添加知识
992
- let taskResponse = await addKnowledgeAB(userDetail.name, {
993
- knowledgeBaseId: knowledgeConfig.knowledgeId,
994
- icode: repositoryUrl,
995
- path: activeFilePath,
996
- query: query,
997
- selected: selectedCode,
998
- language: activeFileLanguage,
999
- createUser: userDetail.name
1000
- });
1001
- yield stream.flushReplaceLast('\n\n');
1002
- if (taskResponse && taskResponse?.message.length > 0) {
1003
- yield stream.flush(`${taskResponse?.message}`);
1004
- }
1005
- if (taskResponse && taskResponse?.succeedList.length > 0) {
1006
- yield stream.flush(`添加成功清单:\n\n- ${taskResponse?.succeedList.join('\n\n- ')}`);
1007
- }
1008
- yield stream.flush('\n\n');
1009
- if (taskResponse && taskResponse?.failedList.length > 0) {
1010
- yield stream.flush(`添加失败清单:\n\n- ${taskResponse?.failedList.join('\n\n- ')}`);
1011
- }
1012
- } catch (error) {
1013
- yield stream.flushReplaceLast('出现错误,请稍后再试');
1014
- }
1015
- }
1016
- trimKnowledge(list, maxCount = 6, maxLength = 10000) {
1017
- const state = {
1018
- length: 0
1019
- };
1020
- const output = [];
1021
- for (const item of list){
1022
- if (state.length + item.length > maxLength || output.length >= maxCount) {
1023
- break;
1024
- }
1025
- output.push(item);
1026
- state.length += item.length;
1027
- }
1028
- return output;
1029
- }
1030
- isValidUUID(uuid) {
1031
- // UUID v4 regex pattern
1032
- const uuidPattern = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89aAbB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;
1033
- // Use .match to check if the UUID matches the pattern
1034
- return uuid.match(uuidPattern) !== null;
1035
- }
1036
- }
1037
-
1038
- function setup({ registry }) {
1039
- registry.registerSkillProvider('help', HelpSkillProvider);
1040
- registry.registerSkillProvider('knowledgeConfig', knowledgeConfigSkillProvider);
1041
- registry.registerSkillProvider('genCaseByCase', CaseByCaseSkillProvider);
1042
- registry.registerSkillProvider('genCaseAB', CaseABSkillProvider);
1043
- registry.registerSkillProvider('addKnowledge', addKnowledgeSkillProvider);
1044
- }
1045
-
1046
- export { setup };