mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-04 23:27:00 -07:00
feat(core): Implement parallel FC for read only tools. (#18791)
This commit is contained in:
@@ -247,7 +247,7 @@ export class DiscoveredMCPTool extends BaseDeclarativeTool<
|
||||
override readonly parameterSchema: unknown,
|
||||
messageBus: MessageBus,
|
||||
readonly trust?: boolean,
|
||||
readonly isReadOnly?: boolean,
|
||||
isReadOnly?: boolean,
|
||||
nameOverride?: string,
|
||||
private readonly cliConfig?: Config,
|
||||
override readonly extensionName?: string,
|
||||
@@ -265,6 +265,16 @@ export class DiscoveredMCPTool extends BaseDeclarativeTool<
|
||||
extensionName,
|
||||
extensionId,
|
||||
);
|
||||
this._isReadOnly = isReadOnly;
|
||||
}
|
||||
|
||||
private readonly _isReadOnly?: boolean;
|
||||
|
||||
override get isReadOnly(): boolean {
|
||||
if (this._isReadOnly !== undefined) {
|
||||
return this._isReadOnly;
|
||||
}
|
||||
return super.isReadOnly;
|
||||
}
|
||||
|
||||
getFullyQualifiedPrefix(): string {
|
||||
|
||||
@@ -9,6 +9,8 @@ import type { ToolInvocation, ToolResult } from './tools.js';
|
||||
import { DeclarativeTool, hasCycleInSchema, Kind } from './tools.js';
|
||||
import { ToolErrorType } from './tool-error.js';
|
||||
import { createMockMessageBus } from '../test-utils/mock-message-bus.js';
|
||||
import { ReadFileTool } from './read-file.js';
|
||||
import { makeFakeConfig } from '../test-utils/config.js';
|
||||
|
||||
class TestToolInvocation implements ToolInvocation<object, ToolResult> {
|
||||
constructor(
|
||||
@@ -238,3 +240,30 @@ describe('hasCycleInSchema', () => {
|
||||
expect(hasCycleInSchema({})).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tools Read-Only property', () => {
|
||||
it('should have isReadOnly true for ReadFileTool', () => {
|
||||
const config = makeFakeConfig();
|
||||
const bus = createMockMessageBus();
|
||||
const tool = new ReadFileTool(config, bus);
|
||||
expect(tool.isReadOnly).toBe(true);
|
||||
});
|
||||
|
||||
it('should derive isReadOnly from Kind', () => {
|
||||
const bus = createMockMessageBus();
|
||||
class MyTool extends DeclarativeTool<object, ToolResult> {
|
||||
build(_params: object): ToolInvocation<object, ToolResult> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
const mutator = new MyTool('m', 'M', 'd', Kind.Edit, {}, bus);
|
||||
expect(mutator.isReadOnly).toBe(false);
|
||||
|
||||
const reader = new MyTool('r', 'R', 'd', Kind.Read, {}, bus);
|
||||
expect(reader.isReadOnly).toBe(true);
|
||||
|
||||
const searcher = new MyTool('s', 'S', 'd', Kind.Search, {}, bus);
|
||||
expect(searcher.isReadOnly).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -333,6 +333,11 @@ export interface ToolBuilder<
|
||||
*/
|
||||
canUpdateOutput: boolean;
|
||||
|
||||
/**
|
||||
* Whether the tool is read-only (has no side effects).
|
||||
*/
|
||||
isReadOnly: boolean;
|
||||
|
||||
/**
|
||||
* Validates raw parameters and builds a ready-to-execute invocation.
|
||||
* @param params The raw, untrusted parameters from the model.
|
||||
@@ -363,6 +368,10 @@ export abstract class DeclarativeTool<
|
||||
readonly extensionId?: string,
|
||||
) {}
|
||||
|
||||
get isReadOnly(): boolean {
|
||||
return READ_ONLY_KINDS.includes(this.kind);
|
||||
}
|
||||
|
||||
getSchema(_modelId?: string): FunctionDeclaration {
|
||||
return {
|
||||
name: this.name,
|
||||
@@ -819,6 +828,13 @@ export const MUTATOR_KINDS: Kind[] = [
|
||||
Kind.Execute,
|
||||
] as const;
|
||||
|
||||
// Function kinds that are safe to run in parallel
|
||||
export const READ_ONLY_KINDS: Kind[] = [
|
||||
Kind.Read,
|
||||
Kind.Search,
|
||||
Kind.Fetch,
|
||||
] as const;
|
||||
|
||||
export interface ToolLocation {
|
||||
// Absolute path to the file
|
||||
path: string;
|
||||
|
||||
Reference in New Issue
Block a user