Skip to content

Commit 6bfbba6

Browse files
committed
chore: improve chat context
1 parent 83d7b2e commit 6bfbba6

3 files changed

Lines changed: 97 additions & 59 deletions

File tree

packages/ai-native/src/browser/components/ChatContext/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const ChatContext = memo(() => {
3939
50,
4040
)((files) => {
4141
if (files) {
42-
updateAddedFiles(files);
42+
updateAddedFiles(files.attached);
4343
}
4444
}, contextService);
4545

packages/ai-native/src/browser/context/llm-context.service.ts

Lines changed: 87 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { EditorSelectionChangeEvent } from '@opensumi/ide-editor/lib/browser/types';
1313
import { IMarkerService } from '@opensumi/ide-markers/lib/common/types';
1414

15-
import { FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
15+
import { AttachFileContext, FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
1616

1717
@Injectable()
1818
export class LLMContextServiceImpl extends WithEventBus implements LLMContextService {
@@ -27,40 +27,61 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
2727

2828
private isAutoCollecting = false;
2929

30-
private contextFiles: FileContext[] = [];
31-
32-
private maxFiles: number = 10; // 上下文的最大长度限制
33-
34-
private onDidContextFilesChangeEmitter = new Emitter<FileContext[]>();
30+
private readonly maxAttachFilesLimit = 10;
31+
private readonly maxViewFilesLimit = 20;
32+
private readonly attachedFiles: FileContext[] = [];
33+
private readonly recentlyViewFiles: FileContext[] = [];
34+
private readonly onDidContextFilesChangeEmitter = new Emitter<{ viewed: FileContext[]; attached: FileContext[] }>();
3535
onDidContextFilesChangeEvent = this.onDidContextFilesChangeEmitter.event;
3636

37-
addFileToContext(uri: URI, selection?: [number, number], isManual = true): void {
38-
this.removeFileFromContext(uri);
37+
private addFileToList(file: FileContext, list: FileContext[], maxLimit: number) {
38+
const existingIndex = list.findIndex((f) => f.uri.toString() === file.uri.toString());
39+
if (existingIndex > -1) {
40+
list.splice(existingIndex, 1);
41+
}
3942

40-
this.contextFiles.push({ uri, selection, isManual });
43+
list.push(file);
44+
if (list.length > maxLimit) {
45+
list.shift();
46+
}
47+
}
4148

42-
if (this.contextFiles.length > this.maxFiles) {
43-
this.contextFiles.shift();
49+
addFileToContext(uri: URI, selection?: [number, number], isManual = false): void {
50+
if (!uri) {
51+
return;
4452
}
4553

54+
const file = { uri, selection };
55+
const targetList = isManual ? this.attachedFiles : this.recentlyViewFiles;
56+
const maxLimit = isManual ? this.maxAttachFilesLimit : this.maxViewFilesLimit;
57+
58+
this.addFileToList(file, targetList, maxLimit);
59+
this.notifyContextChange();
60+
}
61+
62+
private notifyContextChange(): void {
4663
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
4764
}
4865

4966
cleanFileContext() {
50-
this.contextFiles = [];
51-
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
67+
this.attachedFiles.length = 0;
68+
this.notifyContextChange();
5269
}
5370

5471
private getAllContextFiles() {
55-
return [...this.contextFiles];
72+
return {
73+
viewed: this.recentlyViewFiles,
74+
attached: this.attachedFiles,
75+
};
5676
}
5777

58-
removeFileFromContext(uri: URI): void {
59-
const index = this.contextFiles.findIndex((file) => file.uri.toString() === uri.toString());
78+
removeFileFromContext(uri: URI, isManual = false): void {
79+
const targetList = isManual ? this.attachedFiles : this.recentlyViewFiles;
80+
const index = targetList.findIndex((file) => file.uri.toString() === uri.toString());
6081
if (index > -1) {
61-
this.contextFiles.splice(index, 1);
62-
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
82+
targetList.splice(index, 1);
6383
}
84+
this.notifyContextChange();
6485
}
6586

6687
startAutoCollection(): void {
@@ -78,8 +99,7 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
7899
if (event.payload.uri.scheme !== 'file') {
79100
return;
80101
}
81-
// FIXME: 暂时不自动添加
82-
// this.addFileToContext(event.payload.uri);
102+
this.addFileToContext(event.payload.uri, undefined, false);
83103
}),
84104
);
85105

@@ -88,6 +108,8 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
88108
if (event.payload.scheme !== 'file') {
89109
return;
90110
}
111+
112+
this.removeFileFromContext(event.payload, false);
91113
}),
92114
);
93115

@@ -109,11 +131,12 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
109131
].sort() as [number, number];
110132

111133
if (selection[0] === selection[1]) {
112-
this.addFileToContext(event.payload.editorUri, undefined);
134+
this.addFileToContext(event.payload.editorUri, undefined, false);
113135
} else {
114136
this.addFileToContext(
115137
event.payload.editorUri,
116138
selection.sort((a, b) => a - b),
139+
false,
117140
);
118141
}
119142
}
@@ -127,42 +150,51 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
127150

128151
serialize(): SerializedContext {
129152
const files = this.getAllContextFiles();
130-
const recentlyViewFiles = files
131-
.filter((v) => !v.selection)
132-
.map((file) => {
133-
const relativePath = URI.file(this.appConfig.workspaceDir).relative(file.uri);
134-
if (relativePath) {
135-
return relativePath.toString();
136-
}
137-
return file.uri.parent.toString();
138-
})
139-
.filter(Boolean);
140-
141-
const attachedFiles = files
142-
.filter((v) => v.selection)
143-
.map((file) => {
144-
const ref = this.docModelManager.getModelReference(file.uri);
145-
const content = ref!.instance.getText();
146-
const lineErrors = this.markerService
147-
.getManager()
148-
.getMarkers({
149-
resource: file.uri.toString(),
150-
severities: MarkerSeverity.Error,
151-
})
152-
.map((marker) => marker.message);
153-
154-
return {
155-
content,
156-
lineErrors,
157-
path: URI.file(this.appConfig.workspaceDir).relative(file.uri)!.toString(),
158-
language: ref?.instance.languageId!,
159-
};
160-
})
161-
.filter(Boolean);
153+
const workspaceRoot = URI.file(this.appConfig.workspaceDir);
162154

163155
return {
164-
recentlyViewFiles,
165-
attachedFiles,
156+
recentlyViewFiles: this.serializeRecentlyViewFiles(files.viewed, workspaceRoot),
157+
attachedFiles: this.serializeAttachedFiles(files.attached, workspaceRoot),
166158
};
167159
}
160+
161+
private serializeRecentlyViewFiles(files: FileContext[], workspaceRoot: URI): string[] {
162+
return files
163+
.map((file) => workspaceRoot.relative(file.uri)?.toString() || file.uri.parent.toString())
164+
.filter(Boolean);
165+
}
166+
167+
private serializeAttachedFiles(files: FileContext[], workspaceRoot: URI): AttachFileContext[] {
168+
return files
169+
.map((file) => this.serializeAttachedFile(file, workspaceRoot))
170+
.filter(Boolean) as unknown as AttachFileContext[];
171+
}
172+
173+
private serializeAttachedFile(file: FileContext, workspaceRoot: URI) {
174+
try {
175+
const ref = this.docModelManager.getModelReference(file.uri);
176+
if (!ref) {
177+
return null;
178+
}
179+
180+
return {
181+
content: ref.instance.getText(),
182+
lineErrors: this.getFileErrors(file.uri),
183+
path: workspaceRoot.relative(file.uri)!.toString(),
184+
language: ref.instance.languageId!,
185+
};
186+
} catch (e) {
187+
return null;
188+
}
189+
}
190+
191+
private getFileErrors(uri: URI): string[] {
192+
return this.markerService
193+
.getManager()
194+
.getMarkers({
195+
resource: uri.toString(),
196+
severities: MarkerSeverity.Error,
197+
})
198+
.map((marker) => marker.message);
199+
}
168200
}

packages/ai-native/src/common/llm-context.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface LLMContextService {
1515
*/
1616
cleanFileContext(): void;
1717

18-
onDidContextFilesChangeEvent: Event<FileContext[]>;
18+
onDidContextFilesChangeEvent: Event<{ viewed: FileContext[]; attached: FileContext[] }>;
1919

2020
/**
2121
* 从 context 中移除文件
@@ -30,12 +30,18 @@ export interface LLMContextService {
3030
export interface FileContext {
3131
uri: URI;
3232
selection?: [number, number];
33-
isManual: boolean;
3433
}
3534

3635
export const LLMContextServiceToken = Symbol('LLMContextService');
3736

37+
export interface AttachFileContext {
38+
content: string;
39+
lineErrors: string[];
40+
path: string;
41+
language: string;
42+
}
43+
3844
export interface SerializedContext {
3945
recentlyViewFiles: string[];
40-
attachedFiles: Array<{ content: string; lineErrors: string[]; path: string; language: string }>;
46+
attachedFiles: Array<AttachFileContext>;
4147
}

0 commit comments

Comments
 (0)