Skip to content

Commit 5aa4c51

Browse files
committed
added tests for prediction tracker
1 parent 2bfa873 commit 5aa4c51

File tree

4 files changed

+402
-57
lines changed

4 files changed

+402
-57
lines changed

packages/core/src/codewhisperer/models/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,7 @@ export const testGenExcludePatterns = [
934934

935935
export const predictionTrackerDefaultConfig = {
936936
maxFiles: 25,
937-
maxTotalSizeKb: 50000,
937+
maxStorageSizeKb: 50000,
938938
debounceIntervalMs: 2000,
939939
maxAgeMs: 30000,
940940
maxSupplementalContext: 15,

packages/core/src/codewhisperer/nextEditPrediction/PredictionTracker.ts

Lines changed: 26 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import { predictionTrackerDefaultConfig } from '../models/constants'
1414
export interface FileTrackerConfig {
1515
/** Maximum number of files to track (default: 15) */
1616
maxFiles: number
17-
/** Maximum total size in kilobytes (default: 200) */
18-
maxTotalSizeKb: number
17+
/** Maximum total size of all snapshots in kilobytes (default: 200) */
18+
maxStorageSizeKb: number
1919
/** Debounce interval in milliseconds (default: 2000) */
2020
debounceIntervalMs: number
2121
/** Maximum age of snapshots in milliseconds (default: 30000) */
@@ -37,13 +37,11 @@ export interface FileSnapshot {
3737
export class PredictionTracker {
3838
private snapshots: Map<string, FileSnapshot[]> = new Map()
3939
readonly config: FileTrackerConfig
40-
private totalSize: number = 0
40+
private storageSize: number = 0
4141
private storagePath?: string
4242
private debounceTracker: Set<string> = new Set()
4343

4444
constructor(extensionContext: vscode.ExtensionContext, config?: Partial<FileTrackerConfig>) {
45-
getLogger().debug('Initializing PredictionTracker')
46-
4745
this.config = {
4846
...predictionTrackerDefaultConfig,
4947
...config,
@@ -60,7 +58,7 @@ export class PredictionTracker {
6058
const filePath = document.uri.fsPath
6159
getLogger().debug(`Processing edit for file: ${filePath}`)
6260

63-
if (!this.storagePath || filePath.startsWith('untitled:') || !document.uri.scheme.startsWith('file')) {
61+
if (!this.storagePath || !document.uri.scheme.startsWith('file')) {
6462
return
6563
}
6664

@@ -77,7 +75,7 @@ export class PredictionTracker {
7775
const size = Buffer.byteLength(content, 'utf8')
7876

7977
const timestamp = Date.now()
80-
const storageKey = this.generateStorageKey(filePath, timestamp)
78+
const storageKey = `${filePath}-${timestamp}`
8179

8280
const snapshot: FileSnapshot = {
8381
filePath,
@@ -101,7 +99,7 @@ export class PredictionTracker {
10199

102100
fileSnapshots.push(snapshot)
103101
this.snapshots.set(filePath, fileSnapshots)
104-
this.totalSize += size
102+
this.storageSize += size
105103

106104
await this.enforceMemoryLimits()
107105

@@ -110,8 +108,7 @@ export class PredictionTracker {
110108
const index = fileSnapshots.indexOf(snapshot)
111109
if (index !== -1) {
112110
fileSnapshots.splice(index, 1)
113-
this.totalSize -= size
114-
await this.deleteSnapshotFromStorage(snapshot)
111+
await this.deleteSnapshot(snapshot)
115112
if (fileSnapshots.length === 0) {
116113
this.snapshots.delete(filePath)
117114
}
@@ -123,20 +120,12 @@ export class PredictionTracker {
123120
}
124121
}
125122

126-
/**
127-
* Generates a unique storage key for a snapshot
128-
*/
129-
private generateStorageKey(filePath: string, timestamp: number): string {
130-
const fileName = path.basename(filePath)
131-
return `${fileName}-${timestamp}`
132-
}
133-
134123
/**
135124
* Enforces memory limits by removing old snapshots if necessary
136125
*/
137126
private async enforceMemoryLimits(): Promise<void> {
138127
// Enforce total size limit
139-
while (this.totalSize > this.config.maxTotalSizeKb * 1024) {
128+
while (this.storageSize > this.config.maxStorageSizeKb * 1024) {
140129
const oldestFile = this.findOldestFile()
141130
if (!oldestFile) {
142131
break
@@ -150,33 +139,13 @@ export class PredictionTracker {
150139

151140
const removedSnapshot = fileSnapshots.shift()
152141
if (removedSnapshot) {
153-
this.totalSize -= removedSnapshot.size
154-
await this.deleteSnapshotFromStorage(removedSnapshot)
142+
await this.deleteSnapshot(removedSnapshot)
155143
}
156144

157145
if (fileSnapshots.length === 0) {
158146
this.snapshots.delete(oldestFile)
159147
}
160148
}
161-
162-
// Enforce max files limit
163-
while (this.snapshots.size > this.config.maxFiles) {
164-
const oldestFile = this.findOldestFile()
165-
if (!oldestFile) {
166-
break
167-
}
168-
169-
const fileSnapshots = this.snapshots.get(oldestFile)
170-
if (fileSnapshots) {
171-
// Subtract all snapshot sizes from the total
172-
for (const snapshot of fileSnapshots) {
173-
this.totalSize -= snapshot.size
174-
await this.deleteSnapshotFromStorage(snapshot)
175-
}
176-
}
177-
178-
this.snapshots.delete(oldestFile)
179-
}
180149
}
181150

182151
/**
@@ -213,8 +182,7 @@ export class PredictionTracker {
213182
const validSnapshots = snapshots.filter((snapshot) => {
214183
const isValid = now - snapshot.timestamp <= maxAge
215184
if (!isValid) {
216-
this.totalSize -= snapshot.size
217-
void this.deleteSnapshotFromStorage(snapshot)
185+
void this.deleteSnapshot(snapshot)
218186
}
219187
return isValid
220188
})
@@ -271,21 +239,20 @@ export class PredictionTracker {
271239
await fs.mkdir(snapshotsDir)
272240
}
273241

274-
const filePath = path.join(snapshotsDir, `${storageKey}.content`)
242+
const filePath = path.join(snapshotsDir, `${storageKey}.nep-snapshot`)
275243
await fs.writeFile(filePath, content)
276244
}
277245

278-
/**
279-
* Deletes a snapshot content from Storage
280-
* @param snapshot The snapshot to delete
281-
*/
282-
private async deleteSnapshotFromStorage(snapshot: FileSnapshot): Promise<void> {
246+
private async deleteSnapshot(snapshot: FileSnapshot): Promise<void> {
283247
if (!this.storagePath) {
284248
return
285249
}
286250

251+
// Update the storage size
252+
this.storageSize -= snapshot.size
253+
287254
const snapshotsDir = path.join(this.storagePath, 'AmazonQ-file-snapshots')
288-
const filePath = path.join(snapshotsDir, `${snapshot.storageKey}.content`)
255+
const filePath = path.join(snapshotsDir, `${snapshot.storageKey}.nep-snapshot`)
289256

290257
if (await fs.exists(filePath)) {
291258
try {
@@ -307,7 +274,7 @@ export class PredictionTracker {
307274
}
308275

309276
const snapshotsDir = path.join(this.storagePath, 'AmazonQ-file-snapshots')
310-
const filePath = path.join(snapshotsDir, `${snapshot.storageKey}.content`)
277+
const filePath = path.join(snapshotsDir, `${snapshot.storageKey}.nep-snapshot`)
311278

312279
try {
313280
return await fs.readFileText(filePath)
@@ -389,11 +356,11 @@ export class PredictionTracker {
389356

390357
// First, collect all the metadata files
391358
for (const [filename, fileType] of files) {
392-
if (!filename.endsWith('.content') || fileType !== vscode.FileType.File) {
359+
if (!filename.endsWith('.nep-snapshot') || fileType !== vscode.FileType.File) {
393360
continue
394361
}
395362

396-
const storageKey = filename.substring(0, filename.length - '.content'.length)
363+
const storageKey = filename.substring(0, filename.length - '.nep-snapshot'.length)
397364
const parts = storageKey.split('-')
398365
const timestamp = parseInt(parts[parts.length - 1], 10)
399366
const originalFilename = parts.slice(0, parts.length - 1).join('-')
@@ -407,9 +374,10 @@ export class PredictionTracker {
407374

408375
// Now process each file that we found
409376
for (const [storageKey, metadata] of metadataFiles.entries()) {
410-
const contentPath = path.join(snapshotsDir, `${storageKey}.content`)
377+
const contentPath = path.join(snapshotsDir, `${storageKey}.nep-snapshot`)
411378

412379
try {
380+
// if original file no longer exists, delete the snapshot
413381
if (!(await fs.exists(metadata.filePath))) {
414382
await fs.delete(contentPath)
415383
continue
@@ -431,7 +399,7 @@ export class PredictionTracker {
431399
const fileSnapshots = this.snapshots.get(metadata.filePath) || []
432400
fileSnapshots.push(snapshot)
433401
this.snapshots.set(metadata.filePath, fileSnapshots)
434-
this.totalSize += size
402+
this.storageSize += size
435403
} catch (err) {
436404
// Remove invalid files
437405
getLogger().error(`Error processing snapshot file ${storageKey}: ${err}`)
@@ -457,6 +425,10 @@ export class PredictionTracker {
457425
}
458426
}
459427

428+
public getTotalSize() {
429+
return this.storageSize
430+
}
431+
460432
/**
461433
* Disposes of resources used by the tracker
462434
*/

packages/core/src/codewhisperer/service/recommendationHandler.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,6 @@ export class RecommendationHandler {
220220
session.requestContext = await EditorContext.buildGenerateRecommendationRequest(editor as vscode.TextEditor)
221221
}
222222
const request = session.requestContext.request
223-
// eslint-disable-next-line aws-toolkits/no-json-stringify-in-log
224-
getLogger().info(JSON.stringify(request))
225223
// record preprocessing end time
226224
TelemetryHelper.instance.setPreprocessEndTime()
227225

0 commit comments

Comments
 (0)