mirror of
https://github.com/cline/cline.git
synced 2026-08-29 03:52:41 +08:00
refactor: centralize client tool availability (#13451)
This commit is contained in:
@@ -13,6 +13,7 @@ export function getToolCatalog(
|
||||
): ToolCatalogEntry[] {
|
||||
const modelToolSettings = resolveModelToolSettings();
|
||||
return getCoreBuiltinToolCatalog({
|
||||
clientType: "cli",
|
||||
disabledToolIds: resolveDisabledToolNames(),
|
||||
enabledModelToolIds: new Set(
|
||||
Object.entries(modelToolSettings)
|
||||
|
||||
@@ -75,9 +75,12 @@ export {
|
||||
getCoreBuiltinToolCatalog,
|
||||
getCoreDefaultEnabledToolIds,
|
||||
getCoreHeadlessToolNames,
|
||||
isCoreBuiltinToolAvailable,
|
||||
isSkillsToolAvailable,
|
||||
resolveCoreSelectedToolIds,
|
||||
resolveToolClientType,
|
||||
type ToolCatalogEntry,
|
||||
type ToolClientType,
|
||||
} from "./runtime";
|
||||
// Schemas
|
||||
export {
|
||||
|
||||
@@ -28,6 +28,16 @@ describe("builtin tool catalog", () => {
|
||||
(entry) => entry.id === "tasks",
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
getCoreBuiltinToolCatalog({ mode: "act", clientType: "cli" }).some(
|
||||
(entry) => entry.id === "tasks",
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
getCoreBuiltinToolCatalog({ mode: "act", clientType: "vscode" }).some(
|
||||
(entry) => entry.id === "tasks",
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("marks teams enabled by default in act mode", () => {
|
||||
|
||||
@@ -14,10 +14,22 @@ export interface ToolCatalogEntry {
|
||||
description: string;
|
||||
defaultEnabled: boolean;
|
||||
headlessToolNames: string[];
|
||||
unavailableClientTypes?: readonly ToolClientType[];
|
||||
}
|
||||
|
||||
export type ToolClientType = "cli" | "vscode";
|
||||
|
||||
export function resolveToolClientType(
|
||||
source?: string,
|
||||
): ToolClientType | undefined {
|
||||
if (source === "vscode") return "vscode";
|
||||
if (source === "cli" || source?.startsWith("cline-cli")) return "cli";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface BuiltinToolAvailabilityContext {
|
||||
mode?: CoreAgentMode;
|
||||
clientType?: ToolClientType;
|
||||
providerId?: string;
|
||||
modelId?: string;
|
||||
enableSpawnAgent?: boolean;
|
||||
@@ -82,6 +94,7 @@ const BASE_TOOL_CATALOG: readonly RuntimeToolCatalogEntry[] = [
|
||||
description:
|
||||
"Create and manage durable Todo items or explicitly requested one-time and recurring agent schedules.",
|
||||
headlessToolNames: ["tasks"],
|
||||
unavailableClientTypes: ["cli", "vscode"],
|
||||
},
|
||||
{
|
||||
id: "spawn_agent",
|
||||
@@ -173,6 +186,19 @@ function resolvePresetFlags(context: BuiltinToolAvailabilityContext): {
|
||||
};
|
||||
}
|
||||
|
||||
export function isCoreBuiltinToolAvailable(
|
||||
toolName: string,
|
||||
clientType?: ToolClientType,
|
||||
): boolean {
|
||||
if (!clientType) return true;
|
||||
const entry = BASE_TOOL_CATALOG.find(
|
||||
(candidate) =>
|
||||
candidate.id === toolName ||
|
||||
candidate.headlessToolNames.includes(toolName),
|
||||
);
|
||||
return !entry?.unavailableClientTypes?.includes(clientType);
|
||||
}
|
||||
|
||||
function isEntryEnabledByDefault(
|
||||
entryId: string,
|
||||
context: BuiltinToolAvailabilityContext,
|
||||
@@ -228,6 +254,7 @@ export function getCoreBuiltinToolCatalog(
|
||||
): ToolCatalogEntry[] {
|
||||
return BASE_TOOL_CATALOG.filter(
|
||||
(entry) =>
|
||||
isCoreBuiltinToolAvailable(entry.id, context.clientType) &&
|
||||
(entry.id !== "tasks" || resolveContextMode(context.mode) !== "yolo") &&
|
||||
(entry.id !== "web_search" ||
|
||||
supportsModelTool(
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
const tool = (name: string) => ({ name });
|
||||
|
||||
describe("selectSessionTools", () => {
|
||||
it("excludes tasks in yolo mode only", () => {
|
||||
it("excludes tasks in yolo mode and CLI/VS Code sessions", () => {
|
||||
const tools = [tool("read_files"), tool("tasks")];
|
||||
|
||||
expect(selectSessionTools(tools, "act").map(({ name }) => name)).toEqual([
|
||||
@@ -26,6 +26,15 @@ describe("selectSessionTools", () => {
|
||||
expect(selectSessionTools(tools, "yolo").map(({ name }) => name)).toEqual([
|
||||
"read_files",
|
||||
]);
|
||||
expect(
|
||||
selectSessionTools(tools, "act", "cli").map(({ name }) => name),
|
||||
).toEqual(["read_files"]);
|
||||
expect(
|
||||
selectSessionTools(tools, "act", "cline-cli-zen").map(({ name }) => name),
|
||||
).toEqual(["read_files"]);
|
||||
expect(
|
||||
selectSessionTools(tools, "act", "vscode").map(({ name }) => name),
|
||||
).toEqual(["read_files"]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@ import {
|
||||
parseRuntimeConfigExtensions,
|
||||
ReasoningEffortSchema,
|
||||
} from "@cline/shared";
|
||||
import {
|
||||
isCoreBuiltinToolAvailable,
|
||||
resolveToolClientType,
|
||||
} from "../../../extensions/tools/runtime";
|
||||
import { normalizeConnectionUpdate } from "../../../runtime/config/connection-update";
|
||||
import type {
|
||||
RuntimeSessionConfig,
|
||||
@@ -44,10 +48,14 @@ const CAPABILITY_OWNER_METADATA_KEY = "hubCapabilityOwnerClientId";
|
||||
export function selectSessionTools<T extends { name: string }>(
|
||||
tools: readonly T[],
|
||||
mode: string,
|
||||
source?: string,
|
||||
): T[] {
|
||||
return mode === "yolo"
|
||||
? tools.filter((tool) => tool.name !== TASKS_TOOL_NAME)
|
||||
: [...tools];
|
||||
const clientType = resolveToolClientType(source);
|
||||
return tools.filter(
|
||||
(tool) =>
|
||||
(mode !== "yolo" || tool.name !== TASKS_TOOL_NAME) &&
|
||||
isCoreBuiltinToolAvailable(tool.name, clientType),
|
||||
);
|
||||
}
|
||||
|
||||
function readConnectionString(value: unknown): string | undefined {
|
||||
@@ -321,6 +329,7 @@ export async function handleSessionCreate(
|
||||
...(clientContributionRuntime.localRuntime.extraTools ?? []),
|
||||
],
|
||||
sessionMode,
|
||||
typeof metadata.source === "string" ? metadata.source : undefined,
|
||||
),
|
||||
},
|
||||
capabilities: {
|
||||
@@ -602,6 +611,7 @@ export async function handleSessionRestore(
|
||||
...(clientContributionRuntime.localRuntime.extraTools ?? []),
|
||||
],
|
||||
sessionMode,
|
||||
typeof metadata.source === "string" ? metadata.source : undefined,
|
||||
),
|
||||
},
|
||||
capabilities: {
|
||||
|
||||
@@ -931,18 +931,21 @@ export {
|
||||
getCoreBuiltinToolCatalog,
|
||||
getCoreDefaultEnabledToolIds,
|
||||
getCoreHeadlessToolNames,
|
||||
isCoreBuiltinToolAvailable,
|
||||
isSkillsToolAvailable,
|
||||
MAX_COMMAND_OUTPUT_CHARS,
|
||||
PATCH_MARKERS,
|
||||
PatchActionType,
|
||||
type PatchFileChange,
|
||||
resolveCoreSelectedToolIds,
|
||||
resolveToolClientType,
|
||||
type ShellExecutor,
|
||||
type ShellExecutorOptions,
|
||||
type StructuredCommandInput,
|
||||
StructuredCommandInputSchema,
|
||||
TEAM_TOOL_NAMES,
|
||||
type ToolCatalogEntry,
|
||||
type ToolClientType,
|
||||
type ToolExecutors,
|
||||
type ToolPolicyPresetName,
|
||||
type ToolPresetName,
|
||||
|
||||
@@ -75,6 +75,7 @@ export {
|
||||
export type {
|
||||
BuiltinToolAvailabilityContext,
|
||||
ToolCatalogEntry,
|
||||
ToolClientType,
|
||||
} from "./extensions/tools";
|
||||
export {
|
||||
getCoreAcpToolNames,
|
||||
|
||||
Reference in New Issue
Block a user