mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 16:57:46 +00:00
Zed integration (#4266)
Co-authored-by: Agus Zubiaga <agus@zed.dev> Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com> Co-authored-by: mkorwel <matt.korwel@gmail.com>
This commit is contained in:
@@ -9,9 +9,11 @@ import * as path from 'path';
|
||||
import * as Diff from 'diff';
|
||||
import {
|
||||
BaseTool,
|
||||
Icon,
|
||||
ToolCallConfirmationDetails,
|
||||
ToolConfirmationOutcome,
|
||||
ToolEditConfirmationDetails,
|
||||
ToolLocation,
|
||||
ToolResult,
|
||||
ToolResultDisplay,
|
||||
} from './tools.js';
|
||||
@@ -89,6 +91,7 @@ Expectation for required parameters:
|
||||
4. NEVER escape \`old_string\` or \`new_string\`, that would break the exact literal text requirement.
|
||||
**Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for \`old_string\`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.
|
||||
**Multiple replacements:** Set \`expected_replacements\` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match \`old_string\` exactly. Ensure the number of replacements matches your expectation.`,
|
||||
Icon.Pencil,
|
||||
{
|
||||
properties: {
|
||||
file_path: {
|
||||
@@ -141,6 +144,15 @@ Expectation for required parameters:
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines any file locations affected by the tool execution
|
||||
* @param params Parameters for the tool execution
|
||||
* @returns A list of such paths
|
||||
*/
|
||||
toolLocations(params: EditToolParams): ToolLocation[] {
|
||||
return [{ path: params.file_path }];
|
||||
}
|
||||
|
||||
private _applyReplacement(
|
||||
currentContent: string | null,
|
||||
oldString: string,
|
||||
@@ -306,6 +318,8 @@ Expectation for required parameters:
|
||||
title: `Confirm Edit: ${shortenPath(makeRelative(params.file_path, this.config.getTargetDir()))}`,
|
||||
fileName,
|
||||
fileDiff,
|
||||
originalContent: editData.currentContent,
|
||||
newContent: editData.newContent,
|
||||
onConfirm: async (outcome: ToolConfirmationOutcome) => {
|
||||
if (outcome === ToolConfirmationOutcome.ProceedAlways) {
|
||||
this.config.setApprovalMode(ApprovalMode.AUTO_EDIT);
|
||||
@@ -394,7 +408,12 @@ Expectation for required parameters:
|
||||
'Proposed',
|
||||
DEFAULT_DIFF_OPTIONS,
|
||||
);
|
||||
displayResult = { fileDiff, fileName };
|
||||
displayResult = {
|
||||
fileDiff,
|
||||
fileName,
|
||||
originalContent: editData.currentContent,
|
||||
newContent: editData.newContent,
|
||||
};
|
||||
}
|
||||
|
||||
const llmSuccessMessageParts = [
|
||||
|
||||
@@ -8,7 +8,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { glob } from 'glob';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { BaseTool, Icon, ToolResult } from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import { shortenPath, makeRelative } from '../utils/paths.js';
|
||||
import { isWithinRoot } from '../utils/fileUtils.js';
|
||||
@@ -86,6 +86,7 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
GlobTool.Name,
|
||||
'FindFiles',
|
||||
'Efficiently finds files matching specific glob patterns (e.g., `src/**/*.ts`, `**/*.md`), returning absolute paths sorted by modification time (newest first). Ideal for quickly locating files based on their name or path structure, especially in large codebases.',
|
||||
Icon.FileSearch,
|
||||
{
|
||||
properties: {
|
||||
pattern: {
|
||||
|
||||
@@ -10,7 +10,7 @@ import path from 'path';
|
||||
import { EOL } from 'os';
|
||||
import { spawn } from 'child_process';
|
||||
import { globStream } from 'glob';
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { BaseTool, Icon, ToolResult } from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
import { makeRelative, shortenPath } from '../utils/paths.js';
|
||||
@@ -62,6 +62,7 @@ export class GrepTool extends BaseTool<GrepToolParams, ToolResult> {
|
||||
GrepTool.Name,
|
||||
'SearchText',
|
||||
'Searches for a regular expression pattern within the content of files in a specified directory (or current working directory). Can filter files by a glob pattern. Returns the lines containing matches, along with their file paths and line numbers.',
|
||||
Icon.Regex,
|
||||
{
|
||||
properties: {
|
||||
pattern: {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { BaseTool, Icon, ToolResult } from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
import { makeRelative, shortenPath } from '../utils/paths.js';
|
||||
@@ -74,6 +74,7 @@ export class LSTool extends BaseTool<LSToolParams, ToolResult> {
|
||||
LSTool.Name,
|
||||
'ReadFolder',
|
||||
'Lists the names of files and subdirectories directly within a specified directory path. Can optionally ignore entries matching provided glob patterns.',
|
||||
Icon.Folder,
|
||||
{
|
||||
properties: {
|
||||
path: {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ToolCallConfirmationDetails,
|
||||
ToolConfirmationOutcome,
|
||||
ToolMcpConfirmationDetails,
|
||||
Icon,
|
||||
} from './tools.js';
|
||||
import {
|
||||
CallableTool,
|
||||
@@ -38,6 +39,7 @@ export class DiscoveredMCPTool extends BaseTool<ToolParams, ToolResult> {
|
||||
name,
|
||||
`${serverToolName} (${serverName} MCP Server)`,
|
||||
description,
|
||||
Icon.Hammer,
|
||||
{ type: Type.OBJECT }, // this is a dummy Schema for MCP, will be not be used to construct the FunctionDeclaration
|
||||
true, // isOutputMarkdown
|
||||
false, // canUpdateOutput
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { BaseTool, Icon, ToolResult } from './tools.js';
|
||||
import { FunctionDeclaration, Type } from '@google/genai';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
@@ -105,6 +105,7 @@ export class MemoryTool extends BaseTool<SaveMemoryParams, ToolResult> {
|
||||
MemoryTool.Name,
|
||||
'Save Memory',
|
||||
memoryToolDescription,
|
||||
Icon.LightBulb,
|
||||
memoryToolSchemaData.parameters as Record<string, unknown>,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import path from 'path';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
import { makeRelative, shortenPath } from '../utils/paths.js';
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { BaseTool, Icon, ToolLocation, ToolResult } from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import {
|
||||
isWithinRoot,
|
||||
@@ -51,6 +51,7 @@ export class ReadFileTool extends BaseTool<ReadFileToolParams, ToolResult> {
|
||||
ReadFileTool.Name,
|
||||
'ReadFile',
|
||||
'Reads and returns the content of a specified file from the local filesystem. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), and PDF files. For text files, it can read specific line ranges.',
|
||||
Icon.FileSearch,
|
||||
{
|
||||
properties: {
|
||||
absolute_path: {
|
||||
@@ -118,6 +119,10 @@ export class ReadFileTool extends BaseTool<ReadFileToolParams, ToolResult> {
|
||||
return shortenPath(relativePath);
|
||||
}
|
||||
|
||||
toolLocations(params: ReadFileToolParams): ToolLocation[] {
|
||||
return [{ path: params.absolute_path, line: params.offset }];
|
||||
}
|
||||
|
||||
async execute(
|
||||
params: ReadFileToolParams,
|
||||
_signal: AbortSignal,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { BaseTool, Icon, ToolResult } from './tools.js';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
import { getErrorMessage } from '../utils/errors.js';
|
||||
import * as path from 'path';
|
||||
@@ -196,6 +196,7 @@ This tool is useful when you need to understand or analyze a collection of files
|
||||
- When the user asks to "read all files in X directory" or "show me the content of all Y files".
|
||||
|
||||
Use this tool when the user's query implies needing the content of several files simultaneously for context, analysis, or summarization. For text files, it uses default UTF-8 encoding and a '--- {filePath} ---' separator between file contents. Ensure paths are relative to the target directory. Glob patterns like 'src/**/*.js' are supported. Avoid using for single files if a more specific single-file reading tool is available, unless the user specifically requests to process a list containing just one file via this tool. Other binary files (not explicitly requested as image/PDF) are generally skipped. Default excludes apply to common non-text files (except for explicitly requested images/PDFs) and large dependency directories unless 'useDefaultExcludes' is false.`,
|
||||
Icon.FileSearch,
|
||||
parameterSchema,
|
||||
);
|
||||
this.geminiIgnorePatterns = config
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
ToolCallConfirmationDetails,
|
||||
ToolExecuteConfirmationDetails,
|
||||
ToolConfirmationOutcome,
|
||||
Icon,
|
||||
} from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
@@ -52,6 +53,7 @@ Exit Code: Exit code or \`(none)\` if terminated by signal.
|
||||
Signal: Signal number or \`(none)\` if no signal was received.
|
||||
Background PIDs: List of background processes started or \`(none)\`.
|
||||
Process Group PGID: Process group started or \`(none)\``,
|
||||
Icon.Terminal,
|
||||
{
|
||||
type: Type.OBJECT,
|
||||
properties: {
|
||||
|
||||
@@ -14,14 +14,14 @@ import {
|
||||
afterEach,
|
||||
Mocked,
|
||||
} from 'vitest';
|
||||
import { Config, ConfigParameters, ApprovalMode } from '../config/config.js';
|
||||
import {
|
||||
ToolRegistry,
|
||||
DiscoveredTool,
|
||||
sanitizeParameters,
|
||||
} from './tool-registry.js';
|
||||
import { DiscoveredMCPTool } from './mcp-tool.js';
|
||||
import { Config, ConfigParameters, ApprovalMode } from '../config/config.js';
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { BaseTool, Icon, ToolResult } from './tools.js';
|
||||
import {
|
||||
FunctionDeclaration,
|
||||
CallableTool,
|
||||
@@ -109,7 +109,7 @@ class MockTool extends BaseTool<{ param: string }, ToolResult> {
|
||||
displayName = 'A mock tool',
|
||||
description = 'A mock tool description',
|
||||
) {
|
||||
super(name, displayName, description, {
|
||||
super(name, displayName, description, Icon.Hammer, {
|
||||
type: Type.OBJECT,
|
||||
properties: {
|
||||
param: { type: Type.STRING },
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { FunctionDeclaration, Schema, Type } from '@google/genai';
|
||||
import { Tool, ToolResult, BaseTool } from './tools.js';
|
||||
import { Tool, ToolResult, BaseTool, Icon } from './tools.js';
|
||||
import { Config } from '../config/config.js';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { StringDecoder } from 'node:string_decoder';
|
||||
@@ -44,6 +44,7 @@ Signal: Signal number or \`(none)\` if no signal was received.
|
||||
name,
|
||||
name,
|
||||
description,
|
||||
Icon.Hammer,
|
||||
parameterSchema,
|
||||
false, // isOutputMarkdown
|
||||
false, // canUpdateOutput
|
||||
|
||||
@@ -28,6 +28,11 @@ export interface Tool<
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* The icon to display when interacting via ACP
|
||||
*/
|
||||
icon: Icon;
|
||||
|
||||
/**
|
||||
* Function declaration schema from @google/genai
|
||||
*/
|
||||
@@ -60,6 +65,13 @@ export interface Tool<
|
||||
*/
|
||||
getDescription(params: TParams): string;
|
||||
|
||||
/**
|
||||
* Determines what file system paths the tool will affect
|
||||
* @param params Parameters for the tool execution
|
||||
* @returns A list of such paths
|
||||
*/
|
||||
toolLocations(params: TParams): ToolLocation[];
|
||||
|
||||
/**
|
||||
* Determines if the tool should prompt for confirmation before execution
|
||||
* @param params Parameters for the tool execution
|
||||
@@ -103,6 +115,7 @@ export abstract class BaseTool<
|
||||
readonly name: string,
|
||||
readonly displayName: string,
|
||||
readonly description: string,
|
||||
readonly icon: Icon,
|
||||
readonly parameterSchema: Schema,
|
||||
readonly isOutputMarkdown: boolean = true,
|
||||
readonly canUpdateOutput: boolean = false,
|
||||
@@ -158,6 +171,18 @@ export abstract class BaseTool<
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines what file system paths the tool will affect
|
||||
* @param params Parameters for the tool execution
|
||||
* @returns A list of such paths
|
||||
*/
|
||||
toolLocations(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
params: TParams,
|
||||
): ToolLocation[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method to execute the tool with the given parameters
|
||||
* Must be implemented by derived classes
|
||||
@@ -199,6 +224,8 @@ export type ToolResultDisplay = string | FileDiff;
|
||||
export interface FileDiff {
|
||||
fileDiff: string;
|
||||
fileName: string;
|
||||
originalContent: string | null;
|
||||
newContent: string;
|
||||
}
|
||||
|
||||
export interface ToolEditConfirmationDetails {
|
||||
@@ -210,6 +237,8 @@ export interface ToolEditConfirmationDetails {
|
||||
) => Promise<void>;
|
||||
fileName: string;
|
||||
fileDiff: string;
|
||||
originalContent: string | null;
|
||||
newContent: string;
|
||||
isModifying?: boolean;
|
||||
}
|
||||
|
||||
@@ -258,3 +287,21 @@ export enum ToolConfirmationOutcome {
|
||||
ModifyWithEditor = 'modify_with_editor',
|
||||
Cancel = 'cancel',
|
||||
}
|
||||
|
||||
export enum Icon {
|
||||
FileSearch = 'fileSearch',
|
||||
Folder = 'folder',
|
||||
Globe = 'globe',
|
||||
Hammer = 'hammer',
|
||||
LightBulb = 'lightBulb',
|
||||
Pencil = 'pencil',
|
||||
Regex = 'regex',
|
||||
Terminal = 'terminal',
|
||||
}
|
||||
|
||||
export interface ToolLocation {
|
||||
// Absolute path to the file
|
||||
path: string;
|
||||
// Which line (if known)
|
||||
line?: number;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ToolResult,
|
||||
ToolCallConfirmationDetails,
|
||||
ToolConfirmationOutcome,
|
||||
Icon,
|
||||
} from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import { getErrorMessage } from '../utils/errors.js';
|
||||
@@ -70,6 +71,7 @@ export class WebFetchTool extends BaseTool<WebFetchToolParams, ToolResult> {
|
||||
WebFetchTool.Name,
|
||||
'WebFetch',
|
||||
"Processes content from URL(s), including local and private network addresses (e.g., localhost), embedded in a prompt. Include up to 20 URLs and instructions (e.g., summarize, extract specific data) directly in the 'prompt' parameter.",
|
||||
Icon.Globe,
|
||||
{
|
||||
properties: {
|
||||
prompt: {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { GroundingMetadata } from '@google/genai';
|
||||
import { BaseTool, ToolResult } from './tools.js';
|
||||
import { BaseTool, Icon, ToolResult } from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
|
||||
@@ -69,6 +69,7 @@ export class WebSearchTool extends BaseTool<
|
||||
WebSearchTool.Name,
|
||||
'GoogleSearch',
|
||||
'Performs a web search using Google Search (via the Gemini API) and returns the results. This tool is useful for finding information on the internet based on a query.',
|
||||
Icon.Globe,
|
||||
{
|
||||
type: Type.OBJECT,
|
||||
properties: {
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
ToolEditConfirmationDetails,
|
||||
ToolConfirmationOutcome,
|
||||
ToolCallConfirmationDetails,
|
||||
Icon,
|
||||
} from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
@@ -72,9 +73,10 @@ export class WriteFileTool
|
||||
super(
|
||||
WriteFileTool.Name,
|
||||
'WriteFile',
|
||||
`Writes content to a specified file in the local filesystem.
|
||||
|
||||
`Writes content to a specified file in the local filesystem.
|
||||
|
||||
The user has the ability to modify \`content\`. If modified, this will be stated in the response.`,
|
||||
Icon.Pencil,
|
||||
{
|
||||
properties: {
|
||||
file_path: {
|
||||
@@ -184,6 +186,8 @@ export class WriteFileTool
|
||||
title: `Confirm Write: ${shortenPath(relativePath)}`,
|
||||
fileName,
|
||||
fileDiff,
|
||||
originalContent,
|
||||
newContent: correctedContent,
|
||||
onConfirm: async (outcome: ToolConfirmationOutcome) => {
|
||||
if (outcome === ToolConfirmationOutcome.ProceedAlways) {
|
||||
this.config.setApprovalMode(ApprovalMode.AUTO_EDIT);
|
||||
@@ -269,7 +273,12 @@ export class WriteFileTool
|
||||
);
|
||||
}
|
||||
|
||||
const displayResult: FileDiff = { fileDiff, fileName };
|
||||
const displayResult: FileDiff = {
|
||||
fileDiff,
|
||||
fileName,
|
||||
originalContent: correctedContentResult.originalContent,
|
||||
newContent: correctedContentResult.correctedContent,
|
||||
};
|
||||
|
||||
const lines = fileContent.split('\n').length;
|
||||
const mimetype = getSpecificMimeType(params.file_path);
|
||||
|
||||
Reference in New Issue
Block a user