@opensumi/ide-ai-native 3.9.1-next-1748593694.0 → 3.9.1-next-1748939097.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.
- package/lib/browser/chat/chat-model.d.ts.map +1 -1
- package/lib/browser/chat/chat-model.js +3 -1
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat-proxy.service.d.ts +0 -2
- package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-proxy.service.js +50 -57
- package/lib/browser/chat/chat-proxy.service.js.map +1 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +11 -7
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatMentionInput.d.ts.map +1 -1
- package/lib/browser/components/ChatMentionInput.js +123 -27
- package/lib/browser/components/ChatMentionInput.js.map +1 -1
- package/lib/browser/components/ChatToolRender.module.less +1 -0
- package/lib/browser/components/components.module.less +7 -0
- package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -1
- package/lib/browser/components/mention-input/mention-input.js +155 -13
- package/lib/browser/components/mention-input/mention-input.js.map +1 -1
- package/lib/browser/components/mention-input/mention-input.module.less +165 -0
- package/lib/browser/components/mention-input/types.d.ts +2 -1
- package/lib/browser/components/mention-input/types.d.ts.map +1 -1
- package/lib/browser/components/mention-input/types.js +1 -0
- package/lib/browser/components/mention-input/types.js.map +1 -1
- package/lib/browser/context/llm-context.service.d.ts +18 -2
- package/lib/browser/context/llm-context.service.d.ts.map +1 -1
- package/lib/browser/context/llm-context.service.js +168 -20
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/diff-computer.js +1 -1
- package/lib/browser/contrib/intelligent-completions/diff-computer.js.map +1 -1
- package/lib/browser/contrib/terminal/terminal.feature.registry.js.map +1 -1
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +7 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/mcp/base-apply.service.d.ts +2 -2
- package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
- package/lib/browser/mcp/base-apply.service.js.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
- package/lib/browser/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +5 -0
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/browser/rules/rules.contribution.d.ts +29 -0
- package/lib/browser/rules/rules.contribution.d.ts.map +1 -0
- package/lib/browser/rules/rules.contribution.js +94 -0
- package/lib/browser/rules/rules.contribution.js.map +1 -0
- package/lib/browser/rules/rules.module.less +174 -0
- package/lib/browser/rules/rules.service.d.ts +25 -0
- package/lib/browser/rules/rules.service.d.ts.map +1 -0
- package/lib/browser/rules/rules.service.js +180 -0
- package/lib/browser/rules/rules.service.js.map +1 -0
- package/lib/browser/rules/rules.view.d.ts +3 -0
- package/lib/browser/rules/rules.view.d.ts.map +1 -0
- package/lib/browser/rules/rules.view.js +76 -0
- package/lib/browser/rules/rules.view.js.map +1 -0
- package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
- package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
- package/lib/common/MDC_PARSER_README.md +171 -0
- package/lib/common/index.d.ts +2 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +2 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/llm-context.d.ts +19 -0
- package/lib/common/llm-context.d.ts.map +1 -1
- package/lib/common/llm-context.js.map +1 -1
- package/lib/common/mdc-parser.d.ts +60 -0
- package/lib/common/mdc-parser.d.ts.map +1 -0
- package/lib/common/mdc-parser.js +250 -0
- package/lib/common/mdc-parser.js.map +1 -0
- package/lib/common/prompts/context-prompt-provider.d.ts +0 -2
- package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
- package/lib/common/prompts/context-prompt-provider.js +35 -29
- package/lib/common/prompts/context-prompt-provider.js.map +1 -1
- package/lib/common/prompts/system-prompt.d.ts +2 -0
- package/lib/common/prompts/system-prompt.d.ts.map +1 -0
- package/lib/common/prompts/system-prompt.js +5 -0
- package/lib/common/prompts/system-prompt.js.map +1 -0
- package/lib/common/types.d.ts +7 -0
- package/lib/common/types.d.ts.map +1 -1
- package/lib/node/base-language-model.d.ts.map +1 -1
- package/lib/node/base-language-model.js.map +1 -1
- package/package.json +24 -24
- package/src/browser/chat/chat-model.ts +3 -1
- package/src/browser/chat/chat-proxy.service.ts +68 -81
- package/src/browser/chat/chat.view.tsx +19 -7
- package/src/browser/components/ChatMentionInput.tsx +143 -31
- package/src/browser/components/ChatToolRender.module.less +1 -0
- package/src/browser/components/components.module.less +7 -0
- package/src/browser/components/mention-input/mention-input.module.less +165 -0
- package/src/browser/components/mention-input/mention-input.tsx +244 -29
- package/src/browser/components/mention-input/types.ts +1 -0
- package/src/browser/context/llm-context.service.ts +185 -21
- package/src/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.ts +1 -1
- package/src/browser/contrib/intelligent-completions/diff-computer.ts +1 -1
- package/src/browser/contrib/terminal/terminal.feature.registry.ts +1 -1
- package/src/browser/index.ts +8 -0
- package/src/browser/mcp/base-apply.service.ts +0 -1
- package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -1
- package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +1 -1
- package/src/browser/mcp/tools/handlers/ListDir.ts +1 -1
- package/src/browser/mcp/tools/runTerminalCmd.ts +1 -1
- package/src/browser/preferences/schema.ts +5 -0
- package/src/browser/rules/rules.contribution.ts +105 -0
- package/src/browser/rules/rules.module.less +174 -0
- package/src/browser/rules/rules.service.ts +189 -0
- package/src/browser/rules/rules.view.tsx +127 -0
- package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +0 -1
- package/src/common/MDC_PARSER_README.md +171 -0
- package/src/common/index.ts +3 -0
- package/src/common/llm-context.ts +23 -0
- package/src/common/mdc-parser.ts +298 -0
- package/src/common/prompts/context-prompt-provider.ts +55 -40
- package/src/common/prompts/system-prompt.ts +2 -0
- package/src/common/types.ts +8 -0
- package/src/node/base-language-model.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensumi/ide-ai-native",
|
|
3
|
-
"version": "3.9.1-next-
|
|
3
|
+
"version": "3.9.1-next-1748939097.0",
|
|
4
4
|
"files": [
|
|
5
5
|
"lib",
|
|
6
6
|
"src"
|
|
@@ -24,27 +24,27 @@
|
|
|
24
24
|
"@ai-sdk/openai": "^1.1.9",
|
|
25
25
|
"@ai-sdk/openai-compatible": "^0.1.11",
|
|
26
26
|
"@modelcontextprotocol/sdk": "^1.3.1",
|
|
27
|
-
"@opensumi/ide-addons": "3.9.1-next-
|
|
28
|
-
"@opensumi/ide-components": "3.9.1-next-
|
|
29
|
-
"@opensumi/ide-connection": "3.9.1-next-
|
|
30
|
-
"@opensumi/ide-core-common": "3.9.1-next-
|
|
31
|
-
"@opensumi/ide-core-node": "3.9.1-next-
|
|
32
|
-
"@opensumi/ide-debug": "3.9.1-next-
|
|
33
|
-
"@opensumi/ide-design": "3.9.1-next-
|
|
34
|
-
"@opensumi/ide-editor": "3.9.1-next-
|
|
35
|
-
"@opensumi/ide-file-search": "3.9.1-next-
|
|
36
|
-
"@opensumi/ide-file-service": "3.9.1-next-
|
|
37
|
-
"@opensumi/ide-main-layout": "3.9.1-next-
|
|
38
|
-
"@opensumi/ide-markers": "3.9.1-next-
|
|
39
|
-
"@opensumi/ide-monaco": "3.9.1-next-
|
|
40
|
-
"@opensumi/ide-outline": "3.9.1-next-
|
|
41
|
-
"@opensumi/ide-overlay": "3.9.1-next-
|
|
42
|
-
"@opensumi/ide-preferences": "3.9.1-next-
|
|
43
|
-
"@opensumi/ide-search": "3.9.1-next-
|
|
44
|
-
"@opensumi/ide-terminal-next": "3.9.1-next-
|
|
45
|
-
"@opensumi/ide-theme": "3.9.1-next-
|
|
46
|
-
"@opensumi/ide-utils": "3.9.1-next-
|
|
47
|
-
"@opensumi/ide-workspace": "3.9.1-next-
|
|
27
|
+
"@opensumi/ide-addons": "3.9.1-next-1748939097.0",
|
|
28
|
+
"@opensumi/ide-components": "3.9.1-next-1748939097.0",
|
|
29
|
+
"@opensumi/ide-connection": "3.9.1-next-1748939097.0",
|
|
30
|
+
"@opensumi/ide-core-common": "3.9.1-next-1748939097.0",
|
|
31
|
+
"@opensumi/ide-core-node": "3.9.1-next-1748939097.0",
|
|
32
|
+
"@opensumi/ide-debug": "3.9.1-next-1748939097.0",
|
|
33
|
+
"@opensumi/ide-design": "3.9.1-next-1748939097.0",
|
|
34
|
+
"@opensumi/ide-editor": "3.9.1-next-1748939097.0",
|
|
35
|
+
"@opensumi/ide-file-search": "3.9.1-next-1748939097.0",
|
|
36
|
+
"@opensumi/ide-file-service": "3.9.1-next-1748939097.0",
|
|
37
|
+
"@opensumi/ide-main-layout": "3.9.1-next-1748939097.0",
|
|
38
|
+
"@opensumi/ide-markers": "3.9.1-next-1748939097.0",
|
|
39
|
+
"@opensumi/ide-monaco": "3.9.1-next-1748939097.0",
|
|
40
|
+
"@opensumi/ide-outline": "3.9.1-next-1748939097.0",
|
|
41
|
+
"@opensumi/ide-overlay": "3.9.1-next-1748939097.0",
|
|
42
|
+
"@opensumi/ide-preferences": "3.9.1-next-1748939097.0",
|
|
43
|
+
"@opensumi/ide-search": "3.9.1-next-1748939097.0",
|
|
44
|
+
"@opensumi/ide-terminal-next": "3.9.1-next-1748939097.0",
|
|
45
|
+
"@opensumi/ide-theme": "3.9.1-next-1748939097.0",
|
|
46
|
+
"@opensumi/ide-utils": "3.9.1-next-1748939097.0",
|
|
47
|
+
"@opensumi/ide-workspace": "3.9.1-next-1748939097.0",
|
|
48
48
|
"@xterm/xterm": "5.5.0",
|
|
49
49
|
"ai": "^4.1.45",
|
|
50
50
|
"ansi-regex": "^2.0.0",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"zod-to-json-schema": "^3.24.1"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@opensumi/ide-core-browser": "3.9.1-next-
|
|
64
|
+
"@opensumi/ide-core-browser": "3.9.1-next-1748939097.0"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "54024133ab1833b52a0fbfc07683a46906d19d31"
|
|
67
67
|
}
|
|
@@ -352,7 +352,9 @@ export class ChatModel extends Disposable implements IChatModel {
|
|
|
352
352
|
: request.message.prompt,
|
|
353
353
|
});
|
|
354
354
|
for (const part of request.response.responseParts) {
|
|
355
|
-
|
|
355
|
+
// Remove reasoning_content from history
|
|
356
|
+
// https://api-docs.deepseek.com/zh-cn/guides/reasoning_model#%E4%B8%8A%E4%B8%8B%E6%96%87%E6%8B%BC%E6%8E%A5
|
|
357
|
+
if (part.kind === 'treeData' || part.kind === 'component' || part.kind === 'reasoning') {
|
|
356
358
|
continue;
|
|
357
359
|
}
|
|
358
360
|
if (part.kind !== 'toolCall') {
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { Autowired, Injectable } from '@opensumi/di';
|
|
2
|
-
import {
|
|
2
|
+
import { PreferenceService } from '@opensumi/ide-core-browser';
|
|
3
3
|
import {
|
|
4
4
|
AIBackSerivcePath,
|
|
5
5
|
CancellationToken,
|
|
6
6
|
ChatAgentViewServiceToken,
|
|
7
7
|
ChatFeatureRegistryToken,
|
|
8
|
-
ChatServiceToken,
|
|
9
8
|
Deferred,
|
|
10
9
|
Disposable,
|
|
11
10
|
IAIBackService,
|
|
12
11
|
IAIReporter,
|
|
13
12
|
IApplicationService,
|
|
14
13
|
IChatProgress,
|
|
15
|
-
getOperatingSystemName,
|
|
16
14
|
} from '@opensumi/ide-core-common';
|
|
17
15
|
import { AINativeSettingSectionsId } from '@opensumi/ide-core-common/lib/settings/ai-native';
|
|
18
16
|
import { MonacoCommandRegistry } from '@opensumi/ide-editor/lib/browser/monaco-contrib/command/command.service';
|
|
@@ -27,10 +25,10 @@ import {
|
|
|
27
25
|
IChatAgentService,
|
|
28
26
|
IChatAgentWelcomeMessage,
|
|
29
27
|
} from '../../common';
|
|
28
|
+
import { DEFAULT_SYSTEM_PROMPT } from '../../common/prompts/system-prompt';
|
|
30
29
|
import { ChatToolRender } from '../components/ChatToolRender';
|
|
31
30
|
import { IChatAgentViewService } from '../types';
|
|
32
31
|
|
|
33
|
-
import { ChatService } from './chat.api.service';
|
|
34
32
|
import { ChatFeatureRegistry } from './chat.feature.registry';
|
|
35
33
|
|
|
36
34
|
/**
|
|
@@ -53,9 +51,6 @@ export class ChatProxyService extends Disposable {
|
|
|
53
51
|
@Autowired(MonacoCommandRegistry)
|
|
54
52
|
private readonly monacoCommandRegistry: MonacoCommandRegistry;
|
|
55
53
|
|
|
56
|
-
@Autowired(ChatServiceToken)
|
|
57
|
-
private aiChatService: ChatService;
|
|
58
|
-
|
|
59
54
|
@Autowired(IAIReporter)
|
|
60
55
|
private readonly aiReporter: IAIReporter;
|
|
61
56
|
|
|
@@ -71,9 +66,6 @@ export class ChatProxyService extends Disposable {
|
|
|
71
66
|
@Autowired(IMessageService)
|
|
72
67
|
private readonly messageService: IMessageService;
|
|
73
68
|
|
|
74
|
-
@Autowired(AppConfig)
|
|
75
|
-
private readonly appConfig: AppConfig;
|
|
76
|
-
|
|
77
69
|
private chatDeferred: Deferred<void> = new Deferred<void>();
|
|
78
70
|
|
|
79
71
|
public getRequestOptions() {
|
|
@@ -112,79 +104,74 @@ export class ChatProxyService extends Disposable {
|
|
|
112
104
|
initialProps: {},
|
|
113
105
|
});
|
|
114
106
|
|
|
115
|
-
this.
|
|
116
|
-
this.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this.preferenceService.get<string>(
|
|
107
|
+
this.applicationService.getBackendOS().then(() => {
|
|
108
|
+
this.addDispose(
|
|
109
|
+
this.chatAgentService.registerAgent({
|
|
110
|
+
id: ChatProxyService.AGENT_ID,
|
|
111
|
+
metadata: {
|
|
112
|
+
systemPrompt: this.preferenceService.get<string>(
|
|
121
113
|
AINativeSettingSectionsId.SystemPrompt,
|
|
122
|
-
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (commandHandler && commandHandler.providerPrompt) {
|
|
142
|
-
const editor = this.monacoCommandRegistry.getActiveCodeEditor();
|
|
143
|
-
const slashCommandPrompt = await commandHandler.providerPrompt(message, editor);
|
|
144
|
-
prompt = slashCommandPrompt;
|
|
114
|
+
DEFAULT_SYSTEM_PROMPT,
|
|
115
|
+
),
|
|
116
|
+
},
|
|
117
|
+
invoke: async (
|
|
118
|
+
request: IChatAgentRequest,
|
|
119
|
+
progress: (part: IChatProgress) => void,
|
|
120
|
+
history: CoreMessage[],
|
|
121
|
+
token: CancellationToken,
|
|
122
|
+
): Promise<IChatAgentResult> => {
|
|
123
|
+
this.chatDeferred = new Deferred<void>();
|
|
124
|
+
const { message, command } = request;
|
|
125
|
+
let prompt: string = message;
|
|
126
|
+
if (command) {
|
|
127
|
+
const commandHandler = this.chatFeatureRegistry.getSlashCommandHandler(command);
|
|
128
|
+
if (commandHandler && commandHandler.providerPrompt) {
|
|
129
|
+
const editor = this.monacoCommandRegistry.getActiveCodeEditor();
|
|
130
|
+
const slashCommandPrompt = await commandHandler.providerPrompt(message, editor);
|
|
131
|
+
prompt = slashCommandPrompt;
|
|
132
|
+
}
|
|
145
133
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
134
|
+
|
|
135
|
+
const stream = await this.aiBackService.requestStream(
|
|
136
|
+
prompt,
|
|
137
|
+
{
|
|
138
|
+
requestId: request.requestId,
|
|
139
|
+
sessionId: request.sessionId,
|
|
140
|
+
history,
|
|
141
|
+
images: request.images,
|
|
142
|
+
...this.getRequestOptions(),
|
|
143
|
+
},
|
|
144
|
+
token,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
listenReadable<IChatProgress>(stream, {
|
|
148
|
+
onData: (data) => {
|
|
149
|
+
progress(data);
|
|
150
|
+
},
|
|
151
|
+
onEnd: () => {
|
|
152
|
+
this.chatDeferred.resolve();
|
|
153
|
+
},
|
|
154
|
+
onError: (error) => {
|
|
155
|
+
this.messageService.error(error.message);
|
|
156
|
+
this.aiReporter.end(request.sessionId + '_' + request.requestId, {
|
|
157
|
+
message: error.message,
|
|
158
|
+
success: false,
|
|
159
|
+
command,
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
await this.chatDeferred.promise;
|
|
165
|
+
return {};
|
|
166
|
+
},
|
|
167
|
+
provideSlashCommands: async (): Promise<IChatAgentCommand[]> =>
|
|
168
|
+
this.chatFeatureRegistry
|
|
169
|
+
.getAllSlashCommand()
|
|
170
|
+
.map((s) => ({ ...s, name: s.name, description: s.description || '' })),
|
|
171
|
+
provideChatWelcomeMessage: async (): Promise<IChatAgentWelcomeMessage | undefined> => undefined,
|
|
172
|
+
}),
|
|
173
|
+
);
|
|
174
|
+
});
|
|
188
175
|
|
|
189
176
|
queueMicrotask(() => {
|
|
190
177
|
this.chatAgentService.updateAgent(ChatProxyService.AGENT_ID, {});
|
|
@@ -617,7 +617,12 @@ export const AIChatView = () => {
|
|
|
617
617
|
const { message, images, agentId, command, reportExtra } = value;
|
|
618
618
|
const { actionType, actionSource } = reportExtra || {};
|
|
619
619
|
|
|
620
|
-
const request = aiChatService.createRequest(
|
|
620
|
+
const request = aiChatService.createRequest(
|
|
621
|
+
message.replaceAll(LLM_CONTEXT_KEY_REGEX, ''),
|
|
622
|
+
agentId!,
|
|
623
|
+
images,
|
|
624
|
+
command,
|
|
625
|
+
);
|
|
621
626
|
if (!request) {
|
|
622
627
|
return;
|
|
623
628
|
}
|
|
@@ -641,7 +646,7 @@ export const AIChatView = () => {
|
|
|
641
646
|
600 * 1000,
|
|
642
647
|
);
|
|
643
648
|
msgHistoryManager.addUserMessage({
|
|
644
|
-
content: message
|
|
649
|
+
content: message,
|
|
645
650
|
images: images || [],
|
|
646
651
|
agentId: agentId!,
|
|
647
652
|
agentCommand: command!,
|
|
@@ -695,14 +700,9 @@ export const AIChatView = () => {
|
|
|
695
700
|
let processedContent = message;
|
|
696
701
|
const filePattern = /\{\{@file:(.*?)\}\}/g;
|
|
697
702
|
const fileMatches = message.match(filePattern);
|
|
698
|
-
let isCleanContext = false;
|
|
699
703
|
if (fileMatches) {
|
|
700
704
|
for (const match of fileMatches) {
|
|
701
705
|
const filePath = match.replace(/\{\{@file:(.*?)\}\}/, '$1');
|
|
702
|
-
if (filePath && !isCleanContext) {
|
|
703
|
-
isCleanContext = true;
|
|
704
|
-
llmContextService.cleanFileContext();
|
|
705
|
-
}
|
|
706
706
|
const fileUri = new URI(filePath);
|
|
707
707
|
const relativePath = (await workspaceService.asRelativePath(fileUri))?.path || fileUri.displayName;
|
|
708
708
|
processedContent = processedContent.replace(match, `\`${LLM_CONTEXT_KEY.AttachedFile}${relativePath}\``);
|
|
@@ -738,6 +738,18 @@ export const AIChatView = () => {
|
|
|
738
738
|
);
|
|
739
739
|
}
|
|
740
740
|
}
|
|
741
|
+
const rulePattern = /\{\{@rule:(.*?)\}\}/g;
|
|
742
|
+
const ruleMatches = processedContent.match(rulePattern);
|
|
743
|
+
if (ruleMatches) {
|
|
744
|
+
for (const match of ruleMatches) {
|
|
745
|
+
const ruleName = match.replace(/\{\{@rule:(.*?)\}\}/, '$1');
|
|
746
|
+
const ruleUri = new URI(ruleName);
|
|
747
|
+
processedContent = processedContent.replace(
|
|
748
|
+
match,
|
|
749
|
+
`\`${LLM_CONTEXT_KEY.AttachedFile}${ruleUri.displayName}\``,
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
741
753
|
return handleAgentReply({ message: processedContent, images, agentId, command, reportExtra });
|
|
742
754
|
},
|
|
743
755
|
[handleAgentReply],
|
|
@@ -10,7 +10,13 @@ import {
|
|
|
10
10
|
useInjectable,
|
|
11
11
|
} from '@opensumi/ide-core-browser';
|
|
12
12
|
import { Icon, getIcon } from '@opensumi/ide-core-browser/lib/components';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
AINativeSettingSectionsId,
|
|
15
|
+
ChatFeatureRegistryToken,
|
|
16
|
+
RulesServiceToken,
|
|
17
|
+
URI,
|
|
18
|
+
localize,
|
|
19
|
+
} from '@opensumi/ide-core-common';
|
|
14
20
|
import { CommandService } from '@opensumi/ide-core-common/lib/command';
|
|
15
21
|
import { defaultFilesWatcherExcludes } from '@opensumi/ide-core-common/lib/preferences/file-watch';
|
|
16
22
|
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
@@ -25,6 +31,8 @@ import { LLMContextService } from '../../common/llm-context';
|
|
|
25
31
|
import { ChatFeatureRegistry } from '../chat/chat.feature.registry';
|
|
26
32
|
import { ChatInternalService } from '../chat/chat.internal.service';
|
|
27
33
|
import { MCPConfigCommands } from '../mcp/config/mcp-config.commands';
|
|
34
|
+
import { RulesCommands } from '../rules/rules.contribution';
|
|
35
|
+
import { RulesService } from '../rules/rules.service';
|
|
28
36
|
|
|
29
37
|
import styles from './components.module.less';
|
|
30
38
|
import { MentionInput } from './mention-input/mention-input';
|
|
@@ -77,10 +85,15 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
|
|
|
77
85
|
const outlineTreeService = useInjectable<OutlineTreeService>(OutlineTreeService);
|
|
78
86
|
const prevOutlineItems = useRef<MentionItem[]>([]);
|
|
79
87
|
const preferenceService = useInjectable<PreferenceService>(PreferenceService);
|
|
88
|
+
const rulesService = useInjectable<RulesService>(RulesServiceToken);
|
|
80
89
|
const handleShowMCPConfig = React.useCallback(() => {
|
|
81
90
|
commandService.executeCommand(MCPConfigCommands.OPEN_MCP_CONFIG.id);
|
|
82
91
|
}, [commandService]);
|
|
83
92
|
|
|
93
|
+
const handleShowRules = React.useCallback(() => {
|
|
94
|
+
commandService.executeCommand(RulesCommands.OPEN_RULES_FILE.id);
|
|
95
|
+
}, [commandService]);
|
|
96
|
+
|
|
84
97
|
useEffect(() => {
|
|
85
98
|
if (props.value !== value) {
|
|
86
99
|
setValue(props.value || '');
|
|
@@ -107,6 +120,55 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
|
|
|
107
120
|
[outlineTreeService],
|
|
108
121
|
);
|
|
109
122
|
|
|
123
|
+
// 拆分目录路径为多个层级的辅助函数
|
|
124
|
+
const expandFolderPaths = async (folderPaths: string[], workspaceRootPath: string): Promise<MentionItem[]> => {
|
|
125
|
+
const expandedPaths = new Set<string>();
|
|
126
|
+
const workspaceUri = new URI(workspaceRootPath);
|
|
127
|
+
|
|
128
|
+
// 将所有路径展开为多层级
|
|
129
|
+
for (const folderPath of folderPaths) {
|
|
130
|
+
const uri = new URI(folderPath);
|
|
131
|
+
const relativePath = await workspaceService.asRelativePath(uri);
|
|
132
|
+
|
|
133
|
+
if (relativePath?.path) {
|
|
134
|
+
const pathSegments = relativePath.path.split('/').filter(Boolean);
|
|
135
|
+
|
|
136
|
+
// 为每个层级创建路径
|
|
137
|
+
for (let i = 0; i < pathSegments.length; i++) {
|
|
138
|
+
const segmentPath = pathSegments.slice(0, i + 1).join('/');
|
|
139
|
+
const fullPath = workspaceUri.resolve(segmentPath).codeUri.fsPath;
|
|
140
|
+
|
|
141
|
+
// 避免添加工作区本身或其上级目录
|
|
142
|
+
if (fullPath !== workspaceRootPath && !workspaceRootPath.startsWith(fullPath)) {
|
|
143
|
+
expandedPaths.add(fullPath);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
// 如果无法获取相对路径,直接添加(但仍要过滤工作区路径)
|
|
148
|
+
if (folderPath !== workspaceRootPath && !workspaceRootPath.startsWith(folderPath)) {
|
|
149
|
+
expandedPaths.add(folderPath);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 转换为 MentionItem 格式
|
|
155
|
+
return Promise.all(
|
|
156
|
+
Array.from(expandedPaths).map(async (folderPath) => {
|
|
157
|
+
const uri = new URI(folderPath);
|
|
158
|
+
const relativePath = await workspaceService.asRelativePath(uri);
|
|
159
|
+
return {
|
|
160
|
+
id: uri.codeUri.fsPath,
|
|
161
|
+
type: MentionType.FOLDER,
|
|
162
|
+
text: uri.displayName,
|
|
163
|
+
value: uri.codeUri.fsPath,
|
|
164
|
+
description: relativePath?.root ? relativePath.path : '',
|
|
165
|
+
contextId: uri.codeUri.fsPath,
|
|
166
|
+
icon: getIcon('folder'),
|
|
167
|
+
};
|
|
168
|
+
}),
|
|
169
|
+
);
|
|
170
|
+
};
|
|
171
|
+
|
|
110
172
|
// 默认菜单项
|
|
111
173
|
const defaultMenuItems: MentionItem[] = [
|
|
112
174
|
{
|
|
@@ -214,21 +276,7 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
|
|
|
214
276
|
.filter((folder) => folder !== workspaceService.workspace?.uri.toString() && folder !== '/'),
|
|
215
277
|
),
|
|
216
278
|
);
|
|
217
|
-
folders = await
|
|
218
|
-
recentFolder.map(async (folder) => {
|
|
219
|
-
const uri = new URI(folder);
|
|
220
|
-
const relativePath = await workspaceService.asRelativePath(uri);
|
|
221
|
-
return {
|
|
222
|
-
id: uri.codeUri.fsPath,
|
|
223
|
-
type: MentionType.FOLDER,
|
|
224
|
-
text: uri.displayName,
|
|
225
|
-
value: uri.codeUri.fsPath,
|
|
226
|
-
description: relativePath?.root ? relativePath.path : '',
|
|
227
|
-
contextId: uri.codeUri.fsPath,
|
|
228
|
-
icon: getIcon('folder'),
|
|
229
|
-
};
|
|
230
|
-
}),
|
|
231
|
-
);
|
|
279
|
+
folders = await expandFolderPaths(recentFolder, workspaceService.workspace?.uri.toString() || '');
|
|
232
280
|
} else {
|
|
233
281
|
const rootUris = (await workspaceService.roots).map((root) => new URI(root.uri).codeUri.fsPath.toString());
|
|
234
282
|
const files = await searchService.find(searchText, {
|
|
@@ -246,22 +294,11 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
|
|
|
246
294
|
.filter((folder) => folder !== workspaceService.workspace?.uri.toString()),
|
|
247
295
|
),
|
|
248
296
|
);
|
|
249
|
-
return
|
|
250
|
-
folders.map(async (folder) => {
|
|
251
|
-
const uri = new URI(folder);
|
|
252
|
-
return {
|
|
253
|
-
id: uri.codeUri.fsPath,
|
|
254
|
-
type: MentionType.FOLDER,
|
|
255
|
-
text: uri.displayName,
|
|
256
|
-
value: uri.codeUri.fsPath,
|
|
257
|
-
description: (await workspaceService.asRelativePath(uri.parent))?.path || '',
|
|
258
|
-
contextId: uri.codeUri.fsPath,
|
|
259
|
-
icon: getIcon('folder'),
|
|
260
|
-
};
|
|
261
|
-
}),
|
|
262
|
-
);
|
|
297
|
+
return await expandFolderPaths(folders, workspaceService.workspace?.uri.toString() || '');
|
|
263
298
|
}
|
|
264
|
-
return folders
|
|
299
|
+
return folders
|
|
300
|
+
.filter(Boolean)
|
|
301
|
+
.filter((folder) => folder.id !== new URI(workspaceService.workspace?.uri).codeUri.fsPath);
|
|
265
302
|
},
|
|
266
303
|
},
|
|
267
304
|
{
|
|
@@ -312,6 +349,74 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
|
|
|
312
349
|
}
|
|
313
350
|
},
|
|
314
351
|
},
|
|
352
|
+
{
|
|
353
|
+
id: MentionType.RULE,
|
|
354
|
+
type: MentionType.RULE,
|
|
355
|
+
text: 'Rule',
|
|
356
|
+
icon: getIcon('rules'),
|
|
357
|
+
getHighestLevelItems: () => [],
|
|
358
|
+
getItems: async (searchText: string) => {
|
|
359
|
+
const rules = await rulesService.projectRules;
|
|
360
|
+
const mappedRules = rules.map((rule) => {
|
|
361
|
+
const uri = new URI(rule.path);
|
|
362
|
+
return {
|
|
363
|
+
id: uri.codeUri.fsPath,
|
|
364
|
+
type: MentionType.RULE,
|
|
365
|
+
text: uri.displayName,
|
|
366
|
+
value: uri.codeUri.fsPath,
|
|
367
|
+
contextId: uri.codeUri.fsPath,
|
|
368
|
+
description: rule.description,
|
|
369
|
+
icon: getIcon('rules'),
|
|
370
|
+
};
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
if (!searchText) {
|
|
374
|
+
return mappedRules.slice(0, 10);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const lowerSearchText = searchText.toLocaleLowerCase();
|
|
378
|
+
return mappedRules
|
|
379
|
+
.filter((rule) => rule.text.toLocaleLowerCase().includes(lowerSearchText))
|
|
380
|
+
.sort((a, b) => {
|
|
381
|
+
const aTextLower = a.text.toLocaleLowerCase();
|
|
382
|
+
const bTextLower = b.text.toLocaleLowerCase();
|
|
383
|
+
const aDescLower = a.description?.toLocaleLowerCase() || '';
|
|
384
|
+
const bDescLower = b.description?.toLocaleLowerCase() || '';
|
|
385
|
+
|
|
386
|
+
// 优先级:文件名包含搜索文本 > 描述包含搜索文本
|
|
387
|
+
const aTextMatch = aTextLower.includes(lowerSearchText);
|
|
388
|
+
const bTextMatch = bTextLower.includes(lowerSearchText);
|
|
389
|
+
const aDescMatch = aDescLower.includes(lowerSearchText);
|
|
390
|
+
const bDescMatch = bDescLower.includes(lowerSearchText);
|
|
391
|
+
|
|
392
|
+
if (aTextMatch && bTextMatch) {
|
|
393
|
+
// 如果都匹配文件名,按文件名字母序排序
|
|
394
|
+
return aTextLower.localeCompare(bTextLower);
|
|
395
|
+
}
|
|
396
|
+
if (aTextMatch && !bTextMatch) {
|
|
397
|
+
return -1;
|
|
398
|
+
}
|
|
399
|
+
if (!aTextMatch && bTextMatch) {
|
|
400
|
+
return 1;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// 如果文件名都不匹配,比较描述
|
|
404
|
+
if (aDescMatch && bDescMatch) {
|
|
405
|
+
return aTextLower.localeCompare(bTextLower);
|
|
406
|
+
}
|
|
407
|
+
if (aDescMatch && !bDescMatch) {
|
|
408
|
+
return -1;
|
|
409
|
+
}
|
|
410
|
+
if (!aDescMatch && bDescMatch) {
|
|
411
|
+
return 1;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// 如果都不匹配,按文件名字母序排序
|
|
415
|
+
return aTextLower.localeCompare(bTextLower);
|
|
416
|
+
})
|
|
417
|
+
.slice(0, 10);
|
|
418
|
+
},
|
|
419
|
+
},
|
|
315
420
|
];
|
|
316
421
|
|
|
317
422
|
const defaultMentionInputFooterOptions: FooterConfig = useMemo(
|
|
@@ -330,6 +435,13 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
|
|
|
330
435
|
onClick: handleShowMCPConfig,
|
|
331
436
|
position: FooterButtonPosition.LEFT,
|
|
332
437
|
},
|
|
438
|
+
{
|
|
439
|
+
id: 'rules',
|
|
440
|
+
icon: 'rules',
|
|
441
|
+
title: 'Rules',
|
|
442
|
+
onClick: handleShowRules,
|
|
443
|
+
position: FooterButtonPosition.LEFT,
|
|
444
|
+
},
|
|
333
445
|
{
|
|
334
446
|
id: 'upload-image',
|
|
335
447
|
icon: 'image',
|
|
@@ -620,6 +620,13 @@
|
|
|
620
620
|
vertical-align: middle;
|
|
621
621
|
font-size: 12px;
|
|
622
622
|
word-break: break-all;
|
|
623
|
+
max-width: 100px;
|
|
624
|
+
text-overflow: ellipsis;
|
|
625
|
+
direction: rtl;
|
|
626
|
+
unicode-bidi: plaintext;
|
|
627
|
+
overflow: hidden;
|
|
628
|
+
white-space: nowrap;
|
|
629
|
+
display: inline-block;
|
|
623
630
|
}
|
|
624
631
|
|
|
625
632
|
.thumbnail_container {
|