@opensumi/ide-ai-native 3.9.1-next-1749540423.0 → 3.9.1-next-1749546307.0

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 (253) hide show
  1. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  2. package/lib/browser/ai-core.contribution.js +9 -4
  3. package/lib/browser/ai-core.contribution.js.map +1 -1
  4. package/lib/browser/chat/apply.service.d.ts +3 -0
  5. package/lib/browser/chat/apply.service.d.ts.map +1 -1
  6. package/lib/browser/chat/apply.service.js +47 -0
  7. package/lib/browser/chat/apply.service.js.map +1 -1
  8. package/lib/browser/chat/chat-manager.service.d.ts +1 -0
  9. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  10. package/lib/browser/chat/chat-manager.service.js +9 -3
  11. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  12. package/lib/browser/chat/chat-model.d.ts +8 -1
  13. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  14. package/lib/browser/chat/chat-model.js +113 -76
  15. package/lib/browser/chat/chat-model.js.map +1 -1
  16. package/lib/browser/chat/chat-proxy.service.d.ts +0 -2
  17. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  18. package/lib/browser/chat/chat-proxy.service.js +50 -57
  19. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  20. package/lib/browser/chat/chat.feature.registry.d.ts +4 -1
  21. package/lib/browser/chat/chat.feature.registry.d.ts.map +1 -1
  22. package/lib/browser/chat/chat.feature.registry.js +6 -0
  23. package/lib/browser/chat/chat.feature.registry.js.map +1 -1
  24. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  25. package/lib/browser/chat/chat.view.js +49 -10
  26. package/lib/browser/chat/chat.view.js.map +1 -1
  27. package/lib/browser/components/ChatEditor.js +2 -2
  28. package/lib/browser/components/ChatEditor.js.map +1 -1
  29. package/lib/browser/components/ChatHistory.d.ts.map +1 -1
  30. package/lib/browser/components/ChatHistory.js +2 -1
  31. package/lib/browser/components/ChatHistory.js.map +1 -1
  32. package/lib/browser/components/ChatMentionInput.d.ts.map +1 -1
  33. package/lib/browser/components/ChatMentionInput.js +148 -30
  34. package/lib/browser/components/ChatMentionInput.js.map +1 -1
  35. package/lib/browser/components/ChatReply.js +2 -2
  36. package/lib/browser/components/ChatReply.js.map +1 -1
  37. package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
  38. package/lib/browser/components/ChatToolRender.js +7 -2
  39. package/lib/browser/components/ChatToolRender.js.map +1 -1
  40. package/lib/browser/components/ChatToolRender.module.less +25 -0
  41. package/lib/browser/components/components.module.less +37 -8
  42. package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -1
  43. package/lib/browser/components/mention-input/mention-input.js +150 -14
  44. package/lib/browser/components/mention-input/mention-input.js.map +1 -1
  45. package/lib/browser/components/mention-input/mention-input.module.less +165 -1
  46. package/lib/browser/components/mention-input/mention-select.d.ts +28 -0
  47. package/lib/browser/components/mention-input/mention-select.d.ts.map +1 -0
  48. package/lib/browser/components/mention-input/mention-select.js +136 -0
  49. package/lib/browser/components/mention-input/mention-select.js.map +1 -0
  50. package/lib/browser/components/mention-input/mention-select.module.less +297 -0
  51. package/lib/browser/components/mention-input/types.d.ts +28 -1
  52. package/lib/browser/components/mention-input/types.d.ts.map +1 -1
  53. package/lib/browser/components/mention-input/types.js +1 -0
  54. package/lib/browser/components/mention-input/types.js.map +1 -1
  55. package/lib/browser/components/utils.d.ts +2 -2
  56. package/lib/browser/context/llm-context.service.d.ts +21 -2
  57. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  58. package/lib/browser/context/llm-context.service.js +162 -20
  59. package/lib/browser/context/llm-context.service.js.map +1 -1
  60. package/lib/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.d.ts.map +1 -1
  61. package/lib/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.js.map +1 -1
  62. package/lib/browser/contrib/intelligent-completions/diff-computer.js +1 -1
  63. package/lib/browser/contrib/intelligent-completions/diff-computer.js.map +1 -1
  64. package/lib/browser/contrib/terminal/terminal.feature.registry.js.map +1 -1
  65. package/lib/browser/index.d.ts.map +1 -1
  66. package/lib/browser/index.js +7 -0
  67. package/lib/browser/index.js.map +1 -1
  68. package/lib/browser/layout/ai-layout.d.ts.map +1 -1
  69. package/lib/browser/layout/ai-layout.js +6 -4
  70. package/lib/browser/layout/ai-layout.js.map +1 -1
  71. package/lib/browser/layout/tabbar.view.d.ts +1 -1
  72. package/lib/browser/layout/tabbar.view.d.ts.map +1 -1
  73. package/lib/browser/layout/tabbar.view.js +5 -12
  74. package/lib/browser/layout/tabbar.view.js.map +1 -1
  75. package/lib/browser/mcp/base-apply.service.d.ts +5 -4
  76. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  77. package/lib/browser/mcp/base-apply.service.js +23 -5
  78. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  79. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +3 -1
  80. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
  81. package/lib/browser/mcp/mcp-server-proxy.service.js +4 -0
  82. package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -1
  83. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
  84. package/lib/browser/mcp/mcp-server.feature.registry.js +7 -1
  85. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
  86. package/lib/browser/mcp/tools/createNewFileWithText.d.ts +1 -3
  87. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  88. package/lib/browser/mcp/tools/createNewFileWithText.js +14 -40
  89. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  90. package/lib/browser/mcp/tools/fileSearch.d.ts.map +1 -1
  91. package/lib/browser/mcp/tools/fileSearch.js +9 -5
  92. package/lib/browser/mcp/tools/fileSearch.js.map +1 -1
  93. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  94. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -1
  95. package/lib/browser/mcp/tools/grepSearch.d.ts.map +1 -1
  96. package/lib/browser/mcp/tools/grepSearch.js +22 -10
  97. package/lib/browser/mcp/tools/grepSearch.js.map +1 -1
  98. package/lib/browser/mcp/tools/handlers/CreateNewFileWithText.d.ts +15 -0
  99. package/lib/browser/mcp/tools/handlers/CreateNewFileWithText.d.ts.map +1 -0
  100. package/lib/browser/mcp/tools/handlers/CreateNewFileWithText.js +53 -0
  101. package/lib/browser/mcp/tools/handlers/CreateNewFileWithText.js.map +1 -0
  102. package/lib/browser/mcp/tools/handlers/ListDir.js +1 -1
  103. package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -1
  104. package/lib/browser/mcp/tools/handlers/ReadFile.js +1 -1
  105. package/lib/browser/mcp/tools/handlers/ReadFile.js.map +1 -1
  106. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts +11 -1
  107. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
  108. package/lib/browser/mcp/tools/handlers/RunCommand.js +11 -4
  109. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
  110. package/lib/browser/mcp/tools/listDir.d.ts.map +1 -1
  111. package/lib/browser/mcp/tools/listDir.js +19 -15
  112. package/lib/browser/mcp/tools/listDir.js.map +1 -1
  113. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  114. package/lib/browser/model/msg-history-manager.d.ts +47 -1
  115. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  116. package/lib/browser/model/msg-history-manager.js +127 -2
  117. package/lib/browser/model/msg-history-manager.js.map +1 -1
  118. package/lib/browser/preferences/schema.d.ts.map +1 -1
  119. package/lib/browser/preferences/schema.js +5 -0
  120. package/lib/browser/preferences/schema.js.map +1 -1
  121. package/lib/browser/rules/rules.contribution.d.ts +29 -0
  122. package/lib/browser/rules/rules.contribution.d.ts.map +1 -0
  123. package/lib/browser/rules/rules.contribution.js +94 -0
  124. package/lib/browser/rules/rules.contribution.js.map +1 -0
  125. package/lib/browser/rules/rules.module.less +175 -0
  126. package/lib/browser/rules/rules.service.d.ts +25 -0
  127. package/lib/browser/rules/rules.service.d.ts.map +1 -0
  128. package/lib/browser/rules/rules.service.js +180 -0
  129. package/lib/browser/rules/rules.service.js.map +1 -0
  130. package/lib/browser/rules/rules.view.d.ts +3 -0
  131. package/lib/browser/rules/rules.view.d.ts.map +1 -0
  132. package/lib/browser/rules/rules.view.js +76 -0
  133. package/lib/browser/rules/rules.view.js.map +1 -0
  134. package/lib/browser/types.d.ts +12 -1
  135. package/lib/browser/types.d.ts.map +1 -1
  136. package/lib/browser/types.js.map +1 -1
  137. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  138. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  139. package/lib/common/image-compression.d.ts +25 -0
  140. package/lib/common/image-compression.d.ts.map +1 -0
  141. package/lib/common/image-compression.js +153 -0
  142. package/lib/common/image-compression.js.map +1 -0
  143. package/lib/common/index.d.ts +5 -1
  144. package/lib/common/index.d.ts.map +1 -1
  145. package/lib/common/index.js +2 -0
  146. package/lib/common/index.js.map +1 -1
  147. package/lib/common/llm-context.d.ts +19 -0
  148. package/lib/common/llm-context.d.ts.map +1 -1
  149. package/lib/common/llm-context.js.map +1 -1
  150. package/lib/common/mdc-parser.d.ts +60 -0
  151. package/lib/common/mdc-parser.d.ts.map +1 -0
  152. package/lib/common/mdc-parser.js +246 -0
  153. package/lib/common/mdc-parser.js.map +1 -0
  154. package/lib/common/model.d.ts +1 -0
  155. package/lib/common/model.d.ts.map +1 -1
  156. package/lib/common/model.js.map +1 -1
  157. package/lib/common/prompts/context-prompt-provider.d.ts +0 -2
  158. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  159. package/lib/common/prompts/context-prompt-provider.js +35 -29
  160. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  161. package/lib/common/prompts/system-prompt.d.ts +2 -0
  162. package/lib/common/prompts/system-prompt.d.ts.map +1 -0
  163. package/lib/common/prompts/system-prompt.js +5 -0
  164. package/lib/common/prompts/system-prompt.js.map +1 -0
  165. package/lib/common/types.d.ts +21 -0
  166. package/lib/common/types.d.ts.map +1 -1
  167. package/lib/common/types.js.map +1 -1
  168. package/lib/common/utils.d.ts +1 -0
  169. package/lib/common/utils.d.ts.map +1 -1
  170. package/lib/common/utils.js +5 -2
  171. package/lib/common/utils.js.map +1 -1
  172. package/lib/node/anthropic/anthropic-language-model.d.ts +1 -1
  173. package/lib/node/base-language-model.d.ts +2 -1
  174. package/lib/node/base-language-model.d.ts.map +1 -1
  175. package/lib/node/base-language-model.js +12 -2
  176. package/lib/node/base-language-model.js.map +1 -1
  177. package/lib/node/deepseek/deepseek-language-model.d.ts +1 -1
  178. package/lib/node/mcp/sumi-mcp-server.d.ts +3 -1
  179. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
  180. package/lib/node/mcp/sumi-mcp-server.js +7 -1
  181. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  182. package/lib/node/mcp-server-manager-impl.d.ts +3 -1
  183. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  184. package/lib/node/mcp-server-manager-impl.js +14 -2
  185. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  186. package/lib/node/mcp-server.sse.d.ts +187 -1
  187. package/lib/node/mcp-server.sse.d.ts.map +1 -1
  188. package/lib/node/mcp-server.sse.js +2 -2
  189. package/lib/node/mcp-server.sse.js.map +1 -1
  190. package/lib/node/mcp-server.stdio.d.ts +187 -1
  191. package/lib/node/mcp-server.stdio.d.ts.map +1 -1
  192. package/package.json +27 -26
  193. package/src/browser/ai-core.contribution.ts +14 -4
  194. package/src/browser/chat/apply.service.ts +62 -1
  195. package/src/browser/chat/chat-manager.service.ts +16 -7
  196. package/src/browser/chat/chat-model.ts +130 -73
  197. package/src/browser/chat/chat-proxy.service.ts +68 -81
  198. package/src/browser/chat/chat.feature.registry.ts +17 -1
  199. package/src/browser/chat/chat.view.tsx +73 -12
  200. package/src/browser/components/ChatEditor.tsx +1 -1
  201. package/src/browser/components/ChatHistory.tsx +2 -1
  202. package/src/browser/components/ChatMentionInput.tsx +180 -35
  203. package/src/browser/components/ChatReply.tsx +4 -4
  204. package/src/browser/components/ChatToolRender.module.less +25 -0
  205. package/src/browser/components/ChatToolRender.tsx +10 -2
  206. package/src/browser/components/components.module.less +37 -8
  207. package/src/browser/components/mention-input/mention-input.module.less +165 -1
  208. package/src/browser/components/mention-input/mention-input.tsx +232 -31
  209. package/src/browser/components/mention-input/mention-select.module.less +297 -0
  210. package/src/browser/components/mention-input/mention-select.tsx +256 -0
  211. package/src/browser/components/mention-input/types.ts +29 -0
  212. package/src/browser/context/llm-context.service.ts +182 -21
  213. package/src/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.ts +1 -1
  214. package/src/browser/contrib/intelligent-completions/diff-computer.ts +1 -1
  215. package/src/browser/contrib/terminal/terminal.feature.registry.ts +1 -1
  216. package/src/browser/index.ts +8 -0
  217. package/src/browser/layout/ai-layout.tsx +12 -8
  218. package/src/browser/layout/tabbar.view.tsx +10 -23
  219. package/src/browser/mcp/base-apply.service.ts +30 -10
  220. package/src/browser/mcp/mcp-server-proxy.service.ts +6 -1
  221. package/src/browser/mcp/mcp-server.feature.registry.ts +6 -1
  222. package/src/browser/mcp/tools/createNewFileWithText.ts +17 -46
  223. package/src/browser/mcp/tools/fileSearch.ts +8 -5
  224. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -1
  225. package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +1 -1
  226. package/src/browser/mcp/tools/grepSearch.ts +32 -21
  227. package/src/browser/mcp/tools/handlers/CreateNewFileWithText.ts +49 -0
  228. package/src/browser/mcp/tools/handlers/ListDir.ts +2 -2
  229. package/src/browser/mcp/tools/handlers/ReadFile.ts +2 -2
  230. package/src/browser/mcp/tools/handlers/RunCommand.ts +21 -14
  231. package/src/browser/mcp/tools/listDir.ts +15 -12
  232. package/src/browser/mcp/tools/runTerminalCmd.ts +1 -1
  233. package/src/browser/model/msg-history-manager.ts +181 -2
  234. package/src/browser/preferences/schema.ts +5 -0
  235. package/src/browser/rules/rules.contribution.ts +105 -0
  236. package/src/browser/rules/rules.module.less +175 -0
  237. package/src/browser/rules/rules.service.ts +189 -0
  238. package/src/browser/rules/rules.view.tsx +127 -0
  239. package/src/browser/types.ts +18 -0
  240. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +0 -1
  241. package/src/common/image-compression.ts +174 -0
  242. package/src/common/index.ts +6 -1
  243. package/src/common/llm-context.ts +23 -0
  244. package/src/common/mdc-parser.ts +295 -0
  245. package/src/common/model.ts +1 -0
  246. package/src/common/prompts/context-prompt-provider.ts +55 -40
  247. package/src/common/prompts/system-prompt.ts +2 -0
  248. package/src/common/types.ts +18 -0
  249. package/src/common/utils.ts +4 -1
  250. package/src/node/base-language-model.ts +11 -14
  251. package/src/node/mcp/sumi-mcp-server.ts +10 -2
  252. package/src/node/mcp-server-manager-impl.ts +17 -2
  253. package/src/node/mcp-server.sse.ts +1 -2
@@ -1,11 +1,61 @@
1
1
  import { Disposable, Emitter, Event, uuid } from '@opensumi/ide-core-common';
2
2
  import { ChatMessageRole, IHistoryChatMessage } from '@opensumi/ide-core-common/lib/types/ai-native';
3
3
 
4
+ import { ChatFeatureRegistry } from '../chat/chat.feature.registry';
5
+
4
6
  type IExcludeMessage = Omit<IHistoryChatMessage, 'id' | 'order'>;
5
7
 
8
+ interface IMemoryConfig {
9
+ shortTermSize: number; // 最近消息窗口大小(10条)
10
+ bufferSize: number; // 缓冲区大小(5条)
11
+ }
12
+
13
+ interface IMemorySummary {
14
+ content: string;
15
+ timestamp: number;
16
+ messageIds: string[];
17
+ }
18
+
19
+ interface IToolCallInfo {
20
+ id: string;
21
+ name: string;
22
+ args: Record<string, any>;
23
+ result: any;
24
+ }
25
+
26
+ export interface MessageBufferManager {
27
+ messages: IHistoryChatMessage[];
28
+ add(message: IHistoryChatMessage): void;
29
+ clear(): void;
30
+ size(): number;
31
+ }
32
+
33
+ class SimpleMessageBuffer implements MessageBufferManager {
34
+ private _messages: IHistoryChatMessage[] = [];
35
+
36
+ get messages(): IHistoryChatMessage[] {
37
+ return this._messages;
38
+ }
39
+
40
+ add(message: IHistoryChatMessage): void {
41
+ this._messages.push(message);
42
+ }
43
+
44
+ clear(): void {
45
+ this._messages = [];
46
+ }
47
+
48
+ size(): number {
49
+ return this._messages.length;
50
+ }
51
+ }
52
+
6
53
  export class MsgHistoryManager extends Disposable {
7
54
  private messageMap: Map<string, IHistoryChatMessage> = new Map();
8
55
  private messageAdditionalMap: Map<string, Record<string, any>> = new Map();
56
+ private memorySummaries: IMemorySummary[] = [];
57
+ private toolCallMap: Map<string, IToolCallInfo> = new Map();
58
+ private isCompressing = false; // 添加压缩锁,防止重复压缩
9
59
 
10
60
  private readonly _onMessageChange = new Emitter<IHistoryChatMessage[]>();
11
61
  public readonly onMessageChange: Event<IHistoryChatMessage[]> = this._onMessageChange.event;
@@ -13,11 +63,33 @@ export class MsgHistoryManager extends Disposable {
13
63
  private readonly _onMessageAdditionalChange = new Emitter<Record<string, any>>();
14
64
  public readonly onMessageAdditionalChange: Event<Record<string, any>> = this._onMessageAdditionalChange.event;
15
65
 
16
- constructor(data?: { additional: Record<string, any>; messages: IHistoryChatMessage[] }) {
66
+ private messageBuffer: MessageBufferManager;
67
+
68
+ memoryConfig: IMemoryConfig = {
69
+ shortTermSize: 10,
70
+ bufferSize: 5,
71
+ };
72
+
73
+ constructor(
74
+ private chatFeatureRegistry: ChatFeatureRegistry,
75
+ data?: {
76
+ additional: Record<string, any>;
77
+ messages: IHistoryChatMessage[];
78
+ toolCalls?: Record<string, IToolCallInfo>;
79
+ memorySummaries?: IMemorySummary[];
80
+ },
81
+ ) {
17
82
  super();
83
+ this.messageBuffer = new SimpleMessageBuffer();
18
84
  if (data) {
19
85
  this.messageMap = new Map(data.messages.map((item) => [item.id, item]));
20
86
  this.messageAdditionalMap = new Map(Object.entries(data.additional));
87
+ if (data.toolCalls) {
88
+ this.toolCallMap = new Map(Object.entries(data.toolCalls));
89
+ }
90
+ if (data.memorySummaries) {
91
+ this.memorySummaries = data.memorySummaries;
92
+ }
21
93
  }
22
94
  }
23
95
 
@@ -33,6 +105,91 @@ export class MsgHistoryManager extends Disposable {
33
105
  public clearMessages() {
34
106
  this.messageMap.clear();
35
107
  this.messageAdditionalMap.clear();
108
+ this.memorySummaries = [];
109
+ this.toolCallMap.clear();
110
+ }
111
+
112
+ /**
113
+ * 压缩历史消息的方法:
114
+ * 1. 保持最新的10条消息不变
115
+ * 2. 当累积了5条超出限制的消息时,对这5条(最早的消息)进行总结
116
+ * 3. 总结完成后删除这5条消息
117
+ * 4. 重复这个过程,确保消息数量始终在可控范围内
118
+ */
119
+ private async compressMemory() {
120
+ // 如果正在压缩中,直接返回
121
+ if (this.isCompressing) {
122
+ return;
123
+ }
124
+
125
+ const messages = this.messageList;
126
+ // 只有当消息总数超过短期记忆限制时才进行压缩
127
+ if (messages.length <= this.memoryConfig.shortTermSize) {
128
+ return;
129
+ }
130
+
131
+ try {
132
+ this.isCompressing = true;
133
+
134
+ // 1. 获取超出短期记忆限制的最新一条消息
135
+ const latestExcessMessage = messages[messages.length - this.memoryConfig.shortTermSize - 1];
136
+
137
+ // 如果这条消息已经被总结过,就不需要再处理
138
+ if (latestExcessMessage.isSummarized) {
139
+ return;
140
+ }
141
+
142
+ // 2. 将这条消息添加到缓冲区
143
+ this.messageBuffer.add(latestExcessMessage);
144
+
145
+ // 3. 当缓冲区达到指定大小时,进行总结
146
+ if (this.messageBuffer.size() >= this.memoryConfig.bufferSize) {
147
+ const messagesToSummarize = this.messageBuffer.messages;
148
+
149
+ const summaryProvider = this.chatFeatureRegistry.getMessageSummaryProvider?.();
150
+ if (summaryProvider) {
151
+ const messageContents = messagesToSummarize.map((msg) => ({
152
+ role: msg.role,
153
+ content: msg.content,
154
+ }));
155
+
156
+ const memorize = await summaryProvider.generateMemorizedMessage(messageContents);
157
+ if (memorize) {
158
+ // 添加新的记忆总结
159
+ this.memorySummaries.push({
160
+ content: memorize,
161
+ timestamp: Date.now(),
162
+ messageIds: messagesToSummarize.map((msg) => msg.id),
163
+ });
164
+
165
+ // 标记消息为已总结
166
+ for (const msg of messagesToSummarize) {
167
+ const existingMsg = this.messageMap.get(msg.id);
168
+ if (existingMsg) {
169
+ this.messageMap.set(msg.id, {
170
+ ...existingMsg,
171
+ isSummarized: true,
172
+ });
173
+ }
174
+ }
175
+
176
+ // 清空缓冲区
177
+ this.messageBuffer.clear();
178
+ }
179
+ }
180
+ }
181
+ } finally {
182
+ this.isCompressing = false;
183
+ }
184
+ }
185
+
186
+ public addToolCall(toolCall: IToolCallInfo): void {
187
+ this.toolCallMap.set(toolCall.id, toolCall);
188
+ }
189
+
190
+ public getToolCall(id: string): IToolCallInfo | undefined {
191
+ const toolCall = this.toolCallMap.get(id);
192
+ return toolCall;
36
193
  }
37
194
 
38
195
  private doAddMessage(message: IExcludeMessage): string {
@@ -48,11 +205,19 @@ export class MsgHistoryManager extends Disposable {
48
205
 
49
206
  this.messageMap.set(id, msg);
50
207
 
208
+ // 在添加新消息后尝试压缩记忆
209
+ this.compressMemory().catch((error) => {
210
+ // eslint-disable-next-line no-console
211
+ console.error('[MsgHistoryManager] Error compressing memory', error);
212
+ });
213
+
214
+ // 无论压缩是否完成,都触发消息变更事件
51
215
  this._onMessageChange.fire(this.getMessages());
52
216
  return id;
53
217
  }
54
218
 
55
219
  private get messageList(): IHistoryChatMessage[] {
220
+ // 按 order 升序排序,保持消息的原始顺序
56
221
  return Array.from(this.messageMap.values()).sort((a, b) => a.order - b.order);
57
222
  }
58
223
 
@@ -65,6 +230,17 @@ export class MsgHistoryManager extends Disposable {
65
230
  return this.messageList;
66
231
  }
67
232
 
233
+ public getMemorySummaries(): IMemorySummary[] {
234
+ return this.memorySummaries;
235
+ }
236
+
237
+ public setMemoryConfig(config: Partial<IMemoryConfig>) {
238
+ this.memoryConfig = {
239
+ ...this.memoryConfig,
240
+ ...config,
241
+ };
242
+ }
243
+
68
244
  public addUserMessage(
69
245
  message: Required<Pick<IExcludeMessage, 'agentId' | 'agentCommand' | 'content' | 'relationId' | 'images'>>,
70
246
  ): string {
@@ -118,9 +294,12 @@ export class MsgHistoryManager extends Disposable {
118
294
  }
119
295
 
120
296
  toJSON() {
121
- return {
297
+ const data = {
122
298
  messages: this.getMessages(),
123
299
  additional: Object.fromEntries(this.messageAdditionalMap.entries()),
300
+ memorySummaries: this.memorySummaries,
301
+ toolCalls: Object.fromEntries(this.toolCallMap.entries()),
124
302
  };
303
+ return data;
125
304
  }
126
305
  }
@@ -177,5 +177,10 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
177
177
  type: 'string',
178
178
  description: '%preference.ai.native.chat.system.prompt.description%',
179
179
  },
180
+ [AINativeSettingSectionsId.GlobalRules]: {
181
+ type: 'string',
182
+ default: '',
183
+ description: '%preference.ai.native.globalRules.description%',
184
+ },
180
185
  },
181
186
  };
@@ -0,0 +1,105 @@
1
+ import { Autowired } from '@opensumi/di';
2
+ import { getIcon } from '@opensumi/ide-components';
3
+ import { ClientAppContribution } from '@opensumi/ide-core-browser';
4
+ import { LabelService } from '@opensumi/ide-core-browser/lib/services';
5
+ import {
6
+ CommandContribution,
7
+ CommandRegistry,
8
+ Domain,
9
+ RulesServiceToken,
10
+ URI,
11
+ localize,
12
+ } from '@opensumi/ide-core-common';
13
+ import {
14
+ BrowserEditorContribution,
15
+ EditorComponentRegistry,
16
+ EditorComponentRenderMode,
17
+ IResource,
18
+ ResourceService,
19
+ WorkbenchEditorService,
20
+ } from '@opensumi/ide-editor/lib/browser/types';
21
+ import { IconService } from '@opensumi/ide-theme/lib/browser';
22
+ import { IWorkspaceService } from '@opensumi/ide-workspace/lib/common';
23
+
24
+ import { RulesService } from './rules.service';
25
+ import { RulesView } from './rules.view';
26
+
27
+ export namespace RulesCommands {
28
+ export const OPEN_RULES_FILE = {
29
+ id: 'rules.openRulesConfig',
30
+ label: 'Open Rules Configuration',
31
+ };
32
+ }
33
+
34
+ const COMPONENTS_ID = 'opensumi-rules-viewer';
35
+ export const RULES_COMPONENTS_SCHEME_ID = 'rules';
36
+
37
+ export type IRulesResource = IResource<{ configType: string }>;
38
+
39
+ @Domain(BrowserEditorContribution, CommandContribution, ClientAppContribution)
40
+ export class RulesContribution implements BrowserEditorContribution, CommandContribution, ClientAppContribution {
41
+ @Autowired(IWorkspaceService)
42
+ protected readonly workspaceService: IWorkspaceService;
43
+
44
+ @Autowired(IconService)
45
+ protected readonly iconService: IconService;
46
+
47
+ @Autowired(WorkbenchEditorService)
48
+ protected readonly editorService: WorkbenchEditorService;
49
+
50
+ @Autowired()
51
+ labelService: LabelService;
52
+
53
+ @Autowired(RulesServiceToken)
54
+ protected readonly rulesService: RulesService;
55
+
56
+ onStart() {
57
+ this.rulesService.initProjectRules();
58
+ }
59
+
60
+ registerEditorComponent(registry: EditorComponentRegistry) {
61
+ registry.registerEditorComponent({
62
+ uid: COMPONENTS_ID,
63
+ scheme: RULES_COMPONENTS_SCHEME_ID,
64
+ component: RulesView,
65
+ renderMode: EditorComponentRenderMode.ONE_PER_WORKBENCH,
66
+ });
67
+
68
+ registry.registerEditorComponentResolver(RULES_COMPONENTS_SCHEME_ID, (resource, results) => {
69
+ results.push({
70
+ type: 'component',
71
+ componentId: COMPONENTS_ID,
72
+ });
73
+ });
74
+ }
75
+
76
+ registerResource(service: ResourceService) {
77
+ service.registerResourceProvider({
78
+ scheme: RULES_COMPONENTS_SCHEME_ID,
79
+ provideResource: async (uri: URI): Promise<IRulesResource> => {
80
+ const { configType } = uri.getParsedQuery();
81
+
82
+ return {
83
+ uri,
84
+ name: localize('ai.native.rules.title'),
85
+ icon: getIcon('rules'),
86
+ metadata: {
87
+ configType,
88
+ },
89
+ };
90
+ },
91
+ });
92
+ }
93
+
94
+ registerCommands(registry: CommandRegistry) {
95
+ registry.registerCommand(RulesCommands.OPEN_RULES_FILE, {
96
+ execute: () => {
97
+ const uri = new URI().withScheme(RULES_COMPONENTS_SCHEME_ID);
98
+ this.editorService.open(uri, {
99
+ preview: false,
100
+ focus: true,
101
+ });
102
+ },
103
+ });
104
+ }
105
+ }
@@ -0,0 +1,175 @@
1
+ .container {
2
+ padding: 20px;
3
+ color: var(--foreground);
4
+ textarea {
5
+ resize: vertical;
6
+ min-height: 60px;
7
+ }
8
+ input,
9
+ textarea {
10
+ width: 100%;
11
+ padding: 8px;
12
+ border: 1px solid var(--input-border);
13
+ border-radius: 4px;
14
+ background-color: var(--input-background);
15
+ color: var(--input-foreground);
16
+ font-size: 13px;
17
+ font-family: var(--monaco-monospace-font);
18
+
19
+ &:focus {
20
+ border-color: var(--focusBorder);
21
+ outline: none;
22
+ }
23
+
24
+ &::placeholder {
25
+ color: var(--descriptionForeground);
26
+ opacity: 0.6;
27
+ }
28
+ }
29
+ }
30
+
31
+ .header {
32
+ display: flex;
33
+ justify-content: space-between;
34
+ align-items: flex-start;
35
+ margin-bottom: 24px;
36
+ }
37
+
38
+ .title {
39
+ margin: 0 0 8px 0;
40
+ font-size: 24px;
41
+ font-weight: 600;
42
+ }
43
+
44
+ .description {
45
+ margin: 0;
46
+ color: var(--descriptionForeground);
47
+ font-size: 14px;
48
+ line-height: 1.5;
49
+ }
50
+
51
+ .user_rules {
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 16px;
55
+ .user_rules_header {
56
+ display: flex;
57
+ flex-direction: column;
58
+ }
59
+ }
60
+
61
+ .project_rules {
62
+ margin-top: 20px;
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: 16px;
66
+ h3 {
67
+ position: relative;
68
+ }
69
+ .actionButton {
70
+ position: absolute;
71
+ right: 0;
72
+ top: 0;
73
+ }
74
+ }
75
+
76
+ .project_rules_header {
77
+ display: flex;
78
+ justify-content: space-between;
79
+ align-items: flex-start;
80
+ }
81
+
82
+ .project_rules_header_left {
83
+ width: 100%;
84
+ display: flex;
85
+ flex-direction: column;
86
+ }
87
+
88
+ .actionButton {
89
+ padding: 8px 16px;
90
+ border-radius: 4px;
91
+ background-color: var(--button-primary-background);
92
+ color: var(--button-primary-foreground);
93
+ border: none;
94
+ cursor: pointer;
95
+ font-size: 13px;
96
+ .actionButtonIcon {
97
+ margin-right: 5px;
98
+ }
99
+
100
+ &:hover {
101
+ background-color: var(--button-primary-hover-background);
102
+ }
103
+ }
104
+
105
+ .project_rules_list {
106
+ display: flex;
107
+ flex-direction: column;
108
+ gap: 8px;
109
+ }
110
+
111
+ .rule_item {
112
+ display: flex;
113
+ justify-content: space-between;
114
+ align-items: center;
115
+ padding: 12px;
116
+ border: 1px solid var(--input-border);
117
+ border-radius: 4px;
118
+ background-color: var(--input-background);
119
+ opacity: 0.6;
120
+
121
+ &:hover {
122
+ opacity: 1;
123
+ }
124
+ }
125
+
126
+ .rule_item_left {
127
+ display: flex;
128
+ flex-direction: column;
129
+ gap: 4px;
130
+ flex: 1;
131
+ }
132
+
133
+ .rule_item_right {
134
+ display: flex;
135
+ align-items: center;
136
+ flex-shrink: 0;
137
+ margin-left: 16px;
138
+ }
139
+
140
+ .rule_filename {
141
+ font-size: 13px;
142
+ font-weight: 500;
143
+ color: var(--foreground);
144
+ }
145
+
146
+ .rule_description {
147
+ font-size: 12px;
148
+ color: var(--descriptionForeground);
149
+ }
150
+
151
+ .rule_warning {
152
+ font-size: 12px;
153
+ color: var(--editorWarning-foreground);
154
+ display: flex;
155
+ align-items: center;
156
+ gap: 4px;
157
+
158
+ &::before {
159
+ content: '⚠';
160
+ color: var(--editorWarning-foreground);
161
+ }
162
+ }
163
+
164
+ .rule_applies_to {
165
+ font-size: 12px;
166
+ color: var(--descriptionForeground);
167
+ font-family: var(--monaco-monospace-font);
168
+ }
169
+
170
+ .empty_state {
171
+ text-align: center;
172
+ padding: 32px;
173
+ color: var(--descriptionForeground);
174
+ font-style: italic;
175
+ }
@@ -0,0 +1,189 @@
1
+ import { Autowired, Injectable } from '@opensumi/di';
2
+ import { VALIDATE_TYPE } from '@opensumi/ide-components';
3
+ import { AppConfig, PreferenceService } from '@opensumi/ide-core-browser';
4
+ import {
5
+ AINativeSettingSectionsId,
6
+ Disposable,
7
+ Emitter,
8
+ URI,
9
+ formatLocalize,
10
+ localize,
11
+ } from '@opensumi/ide-core-common';
12
+ import { WorkbenchEditorService } from '@opensumi/ide-editor';
13
+ import { IFileServiceClient } from '@opensumi/ide-file-service';
14
+ import { QuickInputService } from '@opensumi/ide-quick-open/lib/browser/quick-input-service';
15
+ import { WorkspaceService } from '@opensumi/ide-workspace/lib/browser/workspace-service';
16
+ import { IWorkspaceService } from '@opensumi/ide-workspace/lib/common';
17
+
18
+ import { IMDCContent, IMDCParseResult, parseMDC, serializeMDC } from '../../common';
19
+ import { ProjectRule } from '../../common/types';
20
+
21
+ @Injectable()
22
+ export class RulesService extends Disposable {
23
+ @Autowired(PreferenceService)
24
+ private readonly preferenceService: PreferenceService;
25
+
26
+ @Autowired(AppConfig)
27
+ private readonly appConfig: AppConfig;
28
+
29
+ @Autowired(IWorkspaceService)
30
+ private readonly workspaceService: WorkspaceService;
31
+
32
+ @Autowired(IFileServiceClient)
33
+ private readonly fileServiceClient: IFileServiceClient;
34
+
35
+ @Autowired(QuickInputService)
36
+ private readonly quickInputService: QuickInputService;
37
+
38
+ @Autowired(WorkbenchEditorService)
39
+ private readonly workbenchEditorService: WorkbenchEditorService;
40
+
41
+ private readonly rulesChangeEventEmitter = new Emitter<void>();
42
+
43
+ private _globalRules: string;
44
+ private _projectRules: ProjectRule[];
45
+
46
+ private _projectRulesPath: string;
47
+
48
+ get onRulesChange() {
49
+ return this.rulesChangeEventEmitter.event;
50
+ }
51
+
52
+ get globalRules() {
53
+ if (!this._globalRules) {
54
+ this._globalRules = this.preferenceService.get<string>(AINativeSettingSectionsId.GlobalRules) || '';
55
+ }
56
+ return this._globalRules;
57
+ }
58
+
59
+ get projectRules() {
60
+ return this._projectRules || [];
61
+ }
62
+
63
+ public async initProjectRules() {
64
+ this.dispose();
65
+ await this.workspaceService.whenReady;
66
+ const workspace = this.workspaceService.workspace;
67
+ // 如果存在 .sumi, 默认从 .sumi 中获取
68
+ const sumiConfigPath = new URI(workspace?.uri)
69
+ .resolve(this.appConfig.preferenceDirName || '.sumi')
70
+ .resolve('rules');
71
+ const cursorConfigPath = new URI(workspace?.uri).resolve('.cursor').resolve('rules');
72
+ if (await this.fileServiceClient.access(sumiConfigPath.codeUri.fsPath)) {
73
+ this._projectRulesPath = sumiConfigPath.codeUri.fsPath;
74
+ } else if (await this.fileServiceClient.access(cursorConfigPath.codeUri.fsPath)) {
75
+ this._projectRulesPath = cursorConfigPath.codeUri.fsPath;
76
+ } else {
77
+ this._projectRulesPath = sumiConfigPath.codeUri.fsPath;
78
+ }
79
+ const watcher = await this.fileServiceClient.watchFileChanges(new URI(this._projectRulesPath));
80
+ this.addDispose(
81
+ watcher.onFilesChanged((changes) => {
82
+ if (
83
+ changes.length > 0 &&
84
+ changes.some((change) => change.uri.endsWith('.mdc') && change.uri.includes('rules'))
85
+ ) {
86
+ this.initProjectRules();
87
+ }
88
+ }),
89
+ );
90
+ const dir = await this.fileServiceClient.getFileStat(this._projectRulesPath);
91
+ if (dir && dir.isDirectory) {
92
+ const files = dir.children?.filter((file) => !file.isDirectory && file.uri.endsWith('.mdc'));
93
+ if (files) {
94
+ const rules = await Promise.all(
95
+ files.map(async (file) => {
96
+ const item = await this.fileServiceClient.readFile(file.uri);
97
+ const data = this.parseMDCContent(item.content.toString());
98
+ return {
99
+ path: file.uri,
100
+ ...data.frontmatter,
101
+ content: data.content,
102
+ };
103
+ }),
104
+ );
105
+ if (rules.length > 0) {
106
+ this._projectRules = rules;
107
+ this.rulesChangeEventEmitter.fire();
108
+ return;
109
+ }
110
+ }
111
+ }
112
+ this._projectRules = [];
113
+ this.rulesChangeEventEmitter.fire();
114
+ }
115
+
116
+ async openRule(rule: ProjectRule) {
117
+ this.workbenchEditorService.open(new URI(rule.path));
118
+ }
119
+
120
+ async createNewRule() {
121
+ let value = await this.quickInputService.open({
122
+ title: localize('ai.native.rules.projectRules.newRule'),
123
+ value: '',
124
+ placeHolder: localize('ai.native.rules.projectRules.newRule.placeholder'),
125
+ validateInput: async (value) => {
126
+ const invalidCharsRegex = /[<>:"/\\|?*\x00-\x1F]/;
127
+ value = value.trim();
128
+ if (value === '') {
129
+ return {
130
+ message: localize('ai.native.rules.projectRules.newRule.error.notEmpty'),
131
+ type: VALIDATE_TYPE.ERROR,
132
+ };
133
+ } else if (invalidCharsRegex.test(value)) {
134
+ return {
135
+ message: localize('ai.native.rules.error.invalidFileName'),
136
+ type: VALIDATE_TYPE.ERROR,
137
+ };
138
+ } else {
139
+ const newRulePath = new URI(this._projectRulesPath).resolve(value + '.mdc');
140
+ const fileExists = this.projectRules.find(
141
+ (rule) => new URI(rule.path).codeUri.fsPath === newRulePath.codeUri.fsPath,
142
+ );
143
+ if (fileExists) {
144
+ return {
145
+ message: formatLocalize('ai.native.rules.error.fileExists', value + '.mdc'),
146
+ type: VALIDATE_TYPE.ERROR,
147
+ };
148
+ }
149
+ }
150
+ },
151
+ });
152
+ value = value?.trim();
153
+ if (value) {
154
+ const newRulePath = new URI(this._projectRulesPath).resolve(value + '.mdc');
155
+ await this.fileServiceClient.createFile(newRulePath.toString(), {
156
+ content: this.serializeMDCContent({
157
+ frontmatter: {
158
+ description: '',
159
+ globs: '',
160
+ alwaysApply: false,
161
+ },
162
+ content: '',
163
+ }),
164
+ });
165
+ this.workbenchEditorService.open(new URI(newRulePath.toString()));
166
+ this.initProjectRules();
167
+ }
168
+ }
169
+
170
+ updateGlobalRules(rules: string) {
171
+ this._globalRules = rules;
172
+ this.preferenceService.set(AINativeSettingSectionsId.GlobalRules, rules);
173
+ }
174
+
175
+ parseMDCContent(content: string): IMDCParseResult {
176
+ try {
177
+ return parseMDC(content);
178
+ } catch (error) {
179
+ return {
180
+ frontmatter: {},
181
+ content,
182
+ };
183
+ }
184
+ }
185
+
186
+ serializeMDCContent(mdcContent: IMDCContent): string {
187
+ return serializeMDC(mdcContent);
188
+ }
189
+ }