mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
Revert "Make glob tool support abortSignal" (#996)
This commit is contained in:
@@ -29,10 +29,9 @@
|
||||
"@opentelemetry/exporter-trace-otlp-grpc": "^0.52.0",
|
||||
"@opentelemetry/instrumentation-http": "^0.52.0",
|
||||
"@opentelemetry/sdk-node": "^0.52.0",
|
||||
"@types/glob": "^8.1.0",
|
||||
"diff": "^7.0.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"glob": "^10.4.5",
|
||||
"fast-glob": "^3.3.3",
|
||||
"google-auth-library": "^9.11.0",
|
||||
"ignore": "^7.0.0",
|
||||
"open": "^10.1.2",
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { GlobTool, GlobToolParams, GlobPath, sortFileEntries } from './glob.js';
|
||||
import {
|
||||
GlobTool,
|
||||
GlobToolParams,
|
||||
sortFileEntries,
|
||||
GlobFileEntry,
|
||||
} from './glob.js';
|
||||
import { partListUnionToString } from '../core/geminiRequest.js';
|
||||
// import { ToolResult } from './tools.js'; // ToolResult is implicitly used by execute
|
||||
import path from 'path';
|
||||
import fs from 'fs/promises';
|
||||
import { Stats } from 'fs';
|
||||
import os from 'os';
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; // Removed vi
|
||||
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
|
||||
@@ -267,9 +274,9 @@ describe('sortFileEntries', () => {
|
||||
const nowTimestamp = new Date('2024-01-15T12:00:00.000Z').getTime();
|
||||
const oneDayInMs = 24 * 60 * 60 * 1000;
|
||||
|
||||
const createFileEntry = (fullpath: string, mtimeDate: Date): GlobPath => ({
|
||||
fullpath: () => fullpath,
|
||||
mtimeMs: mtimeDate.getTime(),
|
||||
const createFileEntry = (path: string, mtimeDate: Date): GlobFileEntry => ({
|
||||
path,
|
||||
stats: { mtime: mtimeDate } as Stats,
|
||||
});
|
||||
|
||||
it('should sort a mix of recent and older files correctly', () => {
|
||||
@@ -282,7 +289,7 @@ describe('sortFileEntries', () => {
|
||||
nowTimestamp - (oneDayInMs + 2 * 60 * 60 * 1000),
|
||||
); // 26 hours ago
|
||||
|
||||
const entries: GlobPath[] = [
|
||||
const entries: GlobFileEntry[] = [
|
||||
createFileEntry('older_zebra.txt', olderTime2),
|
||||
createFileEntry('recent_alpha.txt', recentTime1),
|
||||
createFileEntry('older_apple.txt', olderTime1),
|
||||
@@ -291,7 +298,7 @@ describe('sortFileEntries', () => {
|
||||
];
|
||||
|
||||
const sorted = sortFileEntries(entries, nowTimestamp, oneDayInMs);
|
||||
const sortedPaths = sorted.map((e) => e.fullpath());
|
||||
const sortedPaths = sorted.map((e) => e.path);
|
||||
|
||||
expect(sortedPaths).toEqual([
|
||||
'recent_alpha.txt', // Recent, newest
|
||||
@@ -307,28 +314,24 @@ describe('sortFileEntries', () => {
|
||||
const recentTime2 = new Date(nowTimestamp - 2000);
|
||||
const recentTime3 = new Date(nowTimestamp - 3000); // Oldest recent
|
||||
|
||||
const entries: GlobPath[] = [
|
||||
const entries: GlobFileEntry[] = [
|
||||
createFileEntry('c.txt', recentTime2),
|
||||
createFileEntry('a.txt', recentTime3),
|
||||
createFileEntry('b.txt', recentTime1),
|
||||
];
|
||||
const sorted = sortFileEntries(entries, nowTimestamp, oneDayInMs);
|
||||
expect(sorted.map((e) => e.fullpath())).toEqual([
|
||||
'b.txt',
|
||||
'c.txt',
|
||||
'a.txt',
|
||||
]);
|
||||
expect(sorted.map((e) => e.path)).toEqual(['b.txt', 'c.txt', 'a.txt']);
|
||||
});
|
||||
|
||||
it('should sort only older files alphabetically by path', () => {
|
||||
const olderTime = new Date(nowTimestamp - 2 * oneDayInMs); // All equally old
|
||||
const entries: GlobPath[] = [
|
||||
const entries: GlobFileEntry[] = [
|
||||
createFileEntry('zebra.txt', olderTime),
|
||||
createFileEntry('apple.txt', olderTime),
|
||||
createFileEntry('banana.txt', olderTime),
|
||||
];
|
||||
const sorted = sortFileEntries(entries, nowTimestamp, oneDayInMs);
|
||||
expect(sorted.map((e) => e.fullpath())).toEqual([
|
||||
expect(sorted.map((e) => e.path)).toEqual([
|
||||
'apple.txt',
|
||||
'banana.txt',
|
||||
'zebra.txt',
|
||||
@@ -336,30 +339,30 @@ describe('sortFileEntries', () => {
|
||||
});
|
||||
|
||||
it('should handle an empty array', () => {
|
||||
const entries: GlobPath[] = [];
|
||||
const entries: GlobFileEntry[] = [];
|
||||
const sorted = sortFileEntries(entries, nowTimestamp, oneDayInMs);
|
||||
expect(sorted).toEqual([]);
|
||||
});
|
||||
|
||||
it('should correctly sort files when mtimes are identical for older files', () => {
|
||||
const olderTime = new Date(nowTimestamp - 2 * oneDayInMs);
|
||||
const entries: GlobPath[] = [
|
||||
const entries: GlobFileEntry[] = [
|
||||
createFileEntry('b.txt', olderTime),
|
||||
createFileEntry('a.txt', olderTime),
|
||||
];
|
||||
const sorted = sortFileEntries(entries, nowTimestamp, oneDayInMs);
|
||||
expect(sorted.map((e) => e.fullpath())).toEqual(['a.txt', 'b.txt']);
|
||||
expect(sorted.map((e) => e.path)).toEqual(['a.txt', 'b.txt']);
|
||||
});
|
||||
|
||||
it('should correctly sort files when mtimes are identical for recent files (maintaining mtime sort)', () => {
|
||||
const recentTime = new Date(nowTimestamp - 1000);
|
||||
const entries: GlobPath[] = [
|
||||
const entries: GlobFileEntry[] = [
|
||||
createFileEntry('b.txt', recentTime),
|
||||
createFileEntry('a.txt', recentTime),
|
||||
];
|
||||
const sorted = sortFileEntries(entries, nowTimestamp, oneDayInMs);
|
||||
expect(sorted.map((e) => e.fullpath())).toContain('a.txt');
|
||||
expect(sorted.map((e) => e.fullpath())).toContain('b.txt');
|
||||
expect(sorted.map((e) => e.path)).toContain('a.txt');
|
||||
expect(sorted.map((e) => e.path)).toContain('b.txt');
|
||||
expect(sorted.length).toBe(2);
|
||||
});
|
||||
|
||||
@@ -368,12 +371,12 @@ describe('sortFileEntries', () => {
|
||||
const justUnderThreshold = new Date(nowTimestamp - (1000 - 1)); // Barely recent
|
||||
const customThresholdMs = 1000; // 1 second
|
||||
|
||||
const entries: GlobPath[] = [
|
||||
const entries: GlobFileEntry[] = [
|
||||
createFileEntry('older_file.txt', justOverThreshold),
|
||||
createFileEntry('recent_file.txt', justUnderThreshold),
|
||||
];
|
||||
const sorted = sortFileEntries(entries, nowTimestamp, customThresholdMs);
|
||||
expect(sorted.map((e) => e.fullpath())).toEqual([
|
||||
expect(sorted.map((e) => e.path)).toEqual([
|
||||
'recent_file.txt',
|
||||
'older_file.txt',
|
||||
]);
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { glob } from 'glob';
|
||||
import fg from 'fast-glob';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { shortenPath, makeRelative } from '../utils/paths.js';
|
||||
import { Config } from '../config/config.js';
|
||||
|
||||
// Subset of 'Path' interface provided by 'glob' that we can implement for testing
|
||||
export interface GlobPath {
|
||||
fullpath(): string;
|
||||
mtimeMs?: number;
|
||||
// Type definition for file entries returned by fast-glob with stats: true
|
||||
export interface GlobFileEntry {
|
||||
path: string;
|
||||
stats?: fs.Stats;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,14 +24,14 @@ export interface GlobPath {
|
||||
* Older files are listed after recent ones, sorted alphabetically by path.
|
||||
*/
|
||||
export function sortFileEntries(
|
||||
entries: GlobPath[],
|
||||
entries: GlobFileEntry[],
|
||||
nowTimestamp: number,
|
||||
recencyThresholdMs: number,
|
||||
): GlobPath[] {
|
||||
): GlobFileEntry[] {
|
||||
const sortedEntries = [...entries];
|
||||
sortedEntries.sort((a, b) => {
|
||||
const mtimeA = a.mtimeMs ?? 0;
|
||||
const mtimeB = b.mtimeMs ?? 0;
|
||||
const mtimeA = a.stats?.mtime?.getTime() ?? 0;
|
||||
const mtimeB = b.stats?.mtime?.getTime() ?? 0;
|
||||
const aIsRecent = nowTimestamp - mtimeA < recencyThresholdMs;
|
||||
const bIsRecent = nowTimestamp - mtimeB < recencyThresholdMs;
|
||||
|
||||
@@ -42,7 +42,7 @@ export function sortFileEntries(
|
||||
} else if (bIsRecent) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.fullpath().localeCompare(b.fullpath());
|
||||
return a.path.localeCompare(b.path);
|
||||
}
|
||||
});
|
||||
return sortedEntries;
|
||||
@@ -201,7 +201,7 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
*/
|
||||
async execute(
|
||||
params: GlobToolParams,
|
||||
signal: AbortSignal,
|
||||
_signal: AbortSignal,
|
||||
): Promise<ToolResult> {
|
||||
const validationError = this.validateToolParams(params);
|
||||
if (validationError) {
|
||||
@@ -223,25 +223,26 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
this.config.getFileFilteringRespectGitIgnore();
|
||||
const fileDiscovery = await this.config.getFileService();
|
||||
|
||||
const entries = (await glob(params.pattern, {
|
||||
const entries = await fg(params.pattern, {
|
||||
cwd: searchDirAbsolute,
|
||||
withFileTypes: true,
|
||||
nodir: true,
|
||||
stat: true,
|
||||
nocase: !params.case_sensitive,
|
||||
absolute: true,
|
||||
onlyFiles: true,
|
||||
stats: true,
|
||||
dot: true,
|
||||
caseSensitiveMatch: params.case_sensitive ?? false,
|
||||
ignore: ['**/node_modules/**', '**/.git/**'],
|
||||
follow: false,
|
||||
signal,
|
||||
})) as GlobPath[];
|
||||
followSymbolicLinks: false,
|
||||
suppressErrors: true,
|
||||
});
|
||||
|
||||
// Apply git-aware filtering if enabled and in git repository
|
||||
let filteredEntries = entries;
|
||||
let gitIgnoredCount = 0;
|
||||
|
||||
if (respectGitIgnore && fileDiscovery.isGitRepository()) {
|
||||
const relativePaths = entries.map((p) =>
|
||||
path.relative(this.rootDirectory, p.fullpath()),
|
||||
const allPaths = entries.map((entry) => entry.path);
|
||||
const relativePaths = allPaths.map((p) =>
|
||||
path.relative(this.rootDirectory, p),
|
||||
);
|
||||
const filteredRelativePaths = fileDiscovery.filterFiles(relativePaths, {
|
||||
respectGitIgnore,
|
||||
@@ -251,7 +252,7 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
);
|
||||
|
||||
filteredEntries = entries.filter((entry) =>
|
||||
filteredAbsolutePaths.has(entry.fullpath()),
|
||||
filteredAbsolutePaths.has(entry.path),
|
||||
);
|
||||
gitIgnoredCount = entries.length - filteredEntries.length;
|
||||
}
|
||||
@@ -273,14 +274,12 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
|
||||
// Sort the filtered entries using the new helper function
|
||||
const sortedEntries = sortFileEntries(
|
||||
filteredEntries,
|
||||
filteredEntries as GlobFileEntry[], // Cast because fast-glob's Entry type is generic
|
||||
nowTimestamp,
|
||||
oneDayInMs,
|
||||
);
|
||||
|
||||
const sortedAbsolutePaths = sortedEntries.map((entry) =>
|
||||
entry.fullpath(),
|
||||
);
|
||||
const sortedAbsolutePaths = sortedEntries.map((entry) => entry.path);
|
||||
const fileListDescription = sortedAbsolutePaths.join('\n');
|
||||
const fileCount = sortedAbsolutePaths.length;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user