mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 16:57:46 +00:00
feat: Add programming language to CLI events (#6071)
Co-authored-by: christine betts <chrstn@uw.edu> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Adam Weidman <65992621+adamfweidman@users.noreply.github.com> Co-authored-by: JaeHo Jang <diehreo@gmail.com> Co-authored-by: Jacob Richman <jacob314@gmail.com> Co-authored-by: Victor May <mayvic@google.com> Co-authored-by: Gaurav <39389231+gsquared94@users.noreply.github.com> Co-authored-by: joshualitt <joshualitt@google.com> Co-authored-by: Billy Biggs <bbiggs@google.com> Co-authored-by: Ricardo Fabbri <rfabbri@gmail.com> Co-authored-by: Arya Gummadi <aryagummadi@google.com> Co-authored-by: Tommaso Sciortino <sciortino@gmail.com> Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com> Co-authored-by: Shreya Keshive <skeshive@gmail.com> Co-authored-by: Ben Guo <36952867+HunDun0Ben@users.noreply.github.com> Co-authored-by: Ben Guo <hundunben@gmail.com> Co-authored-by: mkusaka <hinoshita1992@gmail.com>
This commit is contained in:
@@ -26,6 +26,10 @@ vi.mock('../utils/editor.js', () => ({
|
||||
openDiff: mockOpenDiff,
|
||||
}));
|
||||
|
||||
vi.mock('../telemetry/loggers.js', () => ({
|
||||
logFileOperation: vi.fn(),
|
||||
}));
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach, vi, Mock } from 'vitest';
|
||||
import { applyReplacement, EditTool, EditToolParams } from './edit.js';
|
||||
import { FileDiff, ToolConfirmationOutcome } from './tools.js';
|
||||
|
||||
@@ -27,6 +27,11 @@ import { DEFAULT_DIFF_OPTIONS, getDiffStat } from './diffOptions.js';
|
||||
import { ReadFileTool } from './read-file.js';
|
||||
import { ModifiableDeclarativeTool, ModifyContext } from './modifiable-tool.js';
|
||||
import { IDEConnectionStatus } from '../ide/ide-client.js';
|
||||
import { FileOperation } from '../telemetry/metrics.js';
|
||||
import { logFileOperation } from '../telemetry/loggers.js';
|
||||
import { FileOperationEvent } from '../telemetry/types.js';
|
||||
import { getProgrammingLanguage } from '../telemetry/telemetry-utils.js';
|
||||
import { getSpecificMimeType } from '../utils/fileUtils.js';
|
||||
|
||||
export function applyReplacement(
|
||||
currentContent: string | null,
|
||||
@@ -345,12 +350,21 @@ class EditToolInvocation implements ToolInvocation<EditToolParams, ToolResult> {
|
||||
.writeTextFile(this.params.file_path, editData.newContent);
|
||||
|
||||
let displayResult: ToolResultDisplay;
|
||||
const fileName = path.basename(this.params.file_path);
|
||||
const originallyProposedContent =
|
||||
this.params.ai_proposed_string || this.params.new_string;
|
||||
const diffStat = getDiffStat(
|
||||
fileName,
|
||||
editData.currentContent ?? '',
|
||||
originallyProposedContent,
|
||||
this.params.new_string,
|
||||
);
|
||||
|
||||
if (editData.isNewFile) {
|
||||
displayResult = `Created ${shortenPath(makeRelative(this.params.file_path, this.config.getTargetDir()))}`;
|
||||
} else {
|
||||
// Generate diff for display, even though core logic doesn't technically need it
|
||||
// The CLI wrapper will use this part of the ToolResult
|
||||
const fileName = path.basename(this.params.file_path);
|
||||
const fileDiff = Diff.createPatch(
|
||||
fileName,
|
||||
editData.currentContent ?? '', // Should not be null here if not isNewFile
|
||||
@@ -359,14 +373,6 @@ class EditToolInvocation implements ToolInvocation<EditToolParams, ToolResult> {
|
||||
'Proposed',
|
||||
DEFAULT_DIFF_OPTIONS,
|
||||
);
|
||||
const originallyProposedContent =
|
||||
this.params.ai_proposed_string || this.params.new_string;
|
||||
const diffStat = getDiffStat(
|
||||
fileName,
|
||||
editData.currentContent ?? '',
|
||||
originallyProposedContent,
|
||||
this.params.new_string,
|
||||
);
|
||||
displayResult = {
|
||||
fileDiff,
|
||||
fileName,
|
||||
@@ -387,6 +393,26 @@ class EditToolInvocation implements ToolInvocation<EditToolParams, ToolResult> {
|
||||
);
|
||||
}
|
||||
|
||||
const lines = editData.newContent.split('\n').length;
|
||||
const mimetype = getSpecificMimeType(this.params.file_path);
|
||||
const extension = path.extname(this.params.file_path);
|
||||
const programming_language = getProgrammingLanguage({
|
||||
file_path: this.params.file_path,
|
||||
});
|
||||
|
||||
logFileOperation(
|
||||
this.config,
|
||||
new FileOperationEvent(
|
||||
EditTool.Name,
|
||||
editData.isNewFile ? FileOperation.CREATE : FileOperation.UPDATE,
|
||||
lines,
|
||||
mimetype,
|
||||
extension,
|
||||
diffStat,
|
||||
programming_language,
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
llmContent: llmSuccessMessageParts.join(' '),
|
||||
returnDisplay: displayResult,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import { ReadFileTool, ReadFileToolParams } from './read-file.js';
|
||||
import { ToolErrorType } from './tool-error.js';
|
||||
import path from 'path';
|
||||
@@ -17,6 +17,10 @@ import { StandardFileSystemService } from '../services/fileSystemService.js';
|
||||
import { createMockWorkspaceContext } from '../test-utils/mockWorkspaceContext.js';
|
||||
import { ToolInvocation, ToolResult } from './tools.js';
|
||||
|
||||
vi.mock('../telemetry/loggers.js', () => ({
|
||||
logFileOperation: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('ReadFileTool', () => {
|
||||
let tempRootDir: string;
|
||||
let tool: ReadFileTool;
|
||||
|
||||
@@ -21,10 +21,10 @@ import {
|
||||
getSpecificMimeType,
|
||||
} from '../utils/fileUtils.js';
|
||||
import { Config } from '../config/config.js';
|
||||
import {
|
||||
recordFileOperationMetric,
|
||||
FileOperation,
|
||||
} from '../telemetry/metrics.js';
|
||||
import { FileOperation } from '../telemetry/metrics.js';
|
||||
import { getProgrammingLanguage } from '../telemetry/telemetry-utils.js';
|
||||
import { logFileOperation } from '../telemetry/loggers.js';
|
||||
import { FileOperationEvent } from '../telemetry/types.js';
|
||||
|
||||
/**
|
||||
* Parameters for the ReadFile tool
|
||||
@@ -112,12 +112,20 @@ ${result.llmContent}`;
|
||||
? result.llmContent.split('\n').length
|
||||
: undefined;
|
||||
const mimetype = getSpecificMimeType(this.params.absolute_path);
|
||||
recordFileOperationMetric(
|
||||
const programming_language = getProgrammingLanguage({
|
||||
absolute_path: this.params.absolute_path,
|
||||
});
|
||||
logFileOperation(
|
||||
this.config,
|
||||
FileOperation.READ,
|
||||
lines,
|
||||
mimetype,
|
||||
path.extname(this.params.absolute_path),
|
||||
new FileOperationEvent(
|
||||
ReadFileTool.Name,
|
||||
FileOperation.READ,
|
||||
lines,
|
||||
mimetype,
|
||||
path.extname(this.params.absolute_path),
|
||||
undefined,
|
||||
programming_language,
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -47,6 +47,10 @@ vi.mock('mime-types', () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../telemetry/loggers.js', () => ({
|
||||
logFileOperation: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('ReadManyFilesTool', () => {
|
||||
let tool: ReadManyFilesTool;
|
||||
let tempRootDir: string;
|
||||
|
||||
@@ -25,10 +25,10 @@ import {
|
||||
} from '../utils/fileUtils.js';
|
||||
import { PartListUnion } from '@google/genai';
|
||||
import { Config, DEFAULT_FILE_FILTERING_OPTIONS } from '../config/config.js';
|
||||
import {
|
||||
recordFileOperationMetric,
|
||||
FileOperation,
|
||||
} from '../telemetry/metrics.js';
|
||||
import { FileOperation } from '../telemetry/metrics.js';
|
||||
import { getProgrammingLanguage } from '../telemetry/telemetry-utils.js';
|
||||
import { logFileOperation } from '../telemetry/loggers.js';
|
||||
import { FileOperationEvent } from '../telemetry/types.js';
|
||||
import { ToolErrorType } from './tool-error.js';
|
||||
|
||||
/**
|
||||
@@ -468,12 +468,20 @@ ${finalExclusionPatternsForDescription
|
||||
? fileReadResult.llmContent.split('\n').length
|
||||
: undefined;
|
||||
const mimetype = getSpecificMimeType(filePath);
|
||||
recordFileOperationMetric(
|
||||
const programming_language = getProgrammingLanguage({
|
||||
absolute_path: filePath,
|
||||
});
|
||||
logFileOperation(
|
||||
this.config,
|
||||
FileOperation.READ,
|
||||
lines,
|
||||
mimetype,
|
||||
path.extname(filePath),
|
||||
new FileOperationEvent(
|
||||
ReadManyFilesTool.Name,
|
||||
FileOperation.READ,
|
||||
lines,
|
||||
mimetype,
|
||||
path.extname(filePath),
|
||||
undefined,
|
||||
programming_language,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -88,6 +88,11 @@ const mockConfigInternal = {
|
||||
}) as unknown as ToolRegistry,
|
||||
};
|
||||
const mockConfig = mockConfigInternal as unknown as Config;
|
||||
|
||||
vi.mock('../telemetry/loggers.js', () => ({
|
||||
logFileOperation: vi.fn(),
|
||||
}));
|
||||
|
||||
// --- END MOCKS ---
|
||||
|
||||
describe('WriteFileTool', () => {
|
||||
|
||||
@@ -30,11 +30,11 @@ import {
|
||||
import { DEFAULT_DIFF_OPTIONS, getDiffStat } from './diffOptions.js';
|
||||
import { ModifiableDeclarativeTool, ModifyContext } from './modifiable-tool.js';
|
||||
import { getSpecificMimeType } from '../utils/fileUtils.js';
|
||||
import {
|
||||
recordFileOperationMetric,
|
||||
FileOperation,
|
||||
} from '../telemetry/metrics.js';
|
||||
import { FileOperation } from '../telemetry/metrics.js';
|
||||
import { IDEConnectionStatus } from '../ide/ide-client.js';
|
||||
import { getProgrammingLanguage } from '../telemetry/telemetry-utils.js';
|
||||
import { logFileOperation } from '../telemetry/loggers.js';
|
||||
import { FileOperationEvent } from '../telemetry/types.js';
|
||||
|
||||
/**
|
||||
* Parameters for the WriteFile tool
|
||||
@@ -314,23 +314,32 @@ class WriteFileToolInvocation extends BaseToolInvocation<
|
||||
const lines = fileContent.split('\n').length;
|
||||
const mimetype = getSpecificMimeType(file_path);
|
||||
const extension = path.extname(file_path); // Get extension
|
||||
const programming_language = getProgrammingLanguage({ file_path });
|
||||
if (isNewFile) {
|
||||
recordFileOperationMetric(
|
||||
logFileOperation(
|
||||
this.config,
|
||||
FileOperation.CREATE,
|
||||
lines,
|
||||
mimetype,
|
||||
extension,
|
||||
diffStat,
|
||||
new FileOperationEvent(
|
||||
WriteFileTool.Name,
|
||||
FileOperation.CREATE,
|
||||
lines,
|
||||
mimetype,
|
||||
extension,
|
||||
diffStat,
|
||||
programming_language,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
recordFileOperationMetric(
|
||||
logFileOperation(
|
||||
this.config,
|
||||
FileOperation.UPDATE,
|
||||
lines,
|
||||
mimetype,
|
||||
extension,
|
||||
diffStat,
|
||||
new FileOperationEvent(
|
||||
WriteFileTool.Name,
|
||||
FileOperation.UPDATE,
|
||||
lines,
|
||||
mimetype,
|
||||
extension,
|
||||
diffStat,
|
||||
programming_language,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user