Skip to content

ClineToolSet: Werkzeugdefinition und Schema-Konvertierung

源码版本v4.0.10

Verantwortung

ClineToolSet ist Clines zentrale Verwaltung für das Konzept «Werkzeug (tool)» auf drei Ebenen. Die erste Ebene ist «Registrierung»: Jedes Werkzeug wird pro Modellfamilie (ModelFamily) als ein ClineToolSpec registriert, wobei die Generic-Familie als Rückfall dient (register:19). Die zweite Ebene ist «Auswahl»: getEnabledTools filtert anhand der von der variant deklarierten tool-id-Liste + Kontextanforderungen (contextRequirements) die aktuell zu aktivierenden Werkzeuge (getEnabledTools:87). Die dritte Ebene ist «Konvertierung»: getNativeConverter wählt anhand der providerId verschiedene Konverter, die ClineToolSpec in Anthropic Tool / OpenAI ChatCompletionTool / Google FunctionDeclaration übersetzen (getNativeConverter:151).

Seine Ausgabe hat zwei Wege: ein «Text-Pfad», bei dem das Werkzeug-Schema in XML-Abschnitte der Form <tool_name>...<param>...</param></tool_name> in den Systemprompt eingebettet wird, für Modelle, die kein native tool calling unterstützen (PromptBuilder.tool:146); der andere «native Pfad», bei dem getNativeTools das konvertierte Schema-Array als tools-Parameter an createMessage an den ApiHandler übergibt (getNativeTools:170).

Entwurfsmotivation

  • Dualer Schema-Ausgang: Derselbe ClineToolSpec lässt sich sowohl in XML-Text als auch in natives tool-Schema konvertieren, da unter den von Cline unterstützten Modellen einige native function calling unterstützen (Anthropic / OpenAI / Gemini), andere nicht (viele lokale Modelle); letztere können nur über in den Systemprompt eingebettetes XML dazu gebracht werden, im richtigen Format auszugeben.
  • variant-Fallback-Kette: getToolByNameWithFallback sucht zuerst die exakte family → dann GENERIC → dann iteriert über alle Varianten (fallback:48), um sicherzustellen, dass ein Werkzeug, das nur in next-gen registriert ist, aber nicht in generic, trotzdem von der generic variant genutzt werden kann.
  • contextRequirements dynamisches Filtern: Ein Werkzeug kann contextRequirements: (ctx) => boolean deklarieren; z. B. verlangt browser_action supportsBrowserUse=true; wird der Kontext nicht erfüllt, wird es herausgefiltert (ctx filter:101), was flexibler ist als eine hartcodierte variant-Liste.
  • Dynamische Subagent-Werkzeuge: getDynamicSubagentToolSpecs generiert zur Laufzeit anhand der von AgentConfigLoader geladenen Subagent-Konfiguration mehrere Varianten des USE_SUBAGENTS-Werkzeugs (dynamic subagent:108); pro Subagent ein Name, daher ist der Werkzeugsatz nicht statisch.
  • MCP-Werkzeuge einheitlich im Toolset: mcpToolToClineToolSpec wandelt die von MCP-Servern exponierten tools in das ClineToolSpec-Format um; die id ist immer use_mcp_tool, der Name serverUid__mcp__toolName (mcp name:238); MCP-Werkzeuge und eingebaute Werkzeuge werden über denselben Mechanismus verwaltet.
  • Name-Längen-Rückfall: MCP-Werkzeug-Namen über 64 Zeichen werden direkt übersprungen und nicht registriert (length check:243), da Provider-APIs zu lange tool-Namen ablehnen.

Schlüsseldateien

  • ClineToolSet class:8 — hält variants: Map<ModelFamily, Set<ClineToolSet>>, die statische Registry.
  • register:19 — statische Methode, erstellt eine Instanz und speichert sie pro family in die Map; gleiche id wird dedupliziert.
  • getToolByNameWithFallback:48 — dreistufige Suche: exakte family → GENERIC → vollständiger Tabellen-Scan.
  • getToolsForVariantWithFallback:73 — batchweise Auflösung nach id-Liste, dedupliziert.
  • getEnabledTools:87 — variant.tools-Liste + contextRequirements-Filter.
  • getDynamicSubagentToolSpecs:108 — wenn subagent aktiviert und nicht in einem subagent-Lauf, werden USE_SUBAGENTS-Varianten dynamisch aus AgentConfigLoader generiert.
  • getEnabledToolSpecs:136 — merged statische Werkzeuge und dynamische Subagent-Werkzeuge; bei dynamischer Generierung wird das statische USE_SUBAGENTS entfernt.
  • getNativeConverter:151 — wählt Konverter nach providerId: anthropic/bedrock/minimax → inputSchema, openai-kompatibel → functionDefinition, gemini → functionDeclarations.
  • getNativeTools:170 — gibt nur dann das native Schema-Array zurück, wenn variant.labels.use_native_tools === 1 und context.enableNativeToolCalls.
  • mcpToolToClineToolSpec:198 — übersetzt das inputSchema des MCP-Servers in ClineToolSpec.parameters, behält zusätzliche Felder wie enum / format.
  • ClineDefaultTool enum:8 — Enumeration aller eingebauten Werkzeug-IDs: execute_command / read_file / write_to_file / replace_in_file / search_files etc.
  • ClineToolSpec:10 — Werkzeug-Spezifikationstyp: id / name / description / parameters / contextRequirements.
  • toolSpecFunctionDefinition:52 — Konvertierung in OpenAI ChatCompletionTool, mit strict: false, additionalProperties: false.
  • toolSpecInputSchema:145 — Konvertierung in Anthropic Tool, Feldname ist input_schema nicht parameters.
  • toolSpecFunctionDeclarations:243 — Konvertierung in Google FunctionDeclaration, type nutzt Großbuchstaben-Konstanten wie STRING / NUMBER / BOOLEAN.
  • registerClineToolSets:32 — registriert beim Start alle Werkzeug-Varianten auf einmal in ClineToolSet.

Datenfluss

Ein Werkzeug durchläuft vier Schritte von der «Registrierung» bis zur «endgültigen Verwendung durch den ApiHandler»: Registrierung → variant-Deklaration → Aktivierungsfilter → Schema-Konvertierung. Die Registrierung erfolgt beim Konstruieren von PromptRegistry:

typescript
// apps/vscode/src/core/prompts/system-prompt/tools/init.ts
export function registerClineToolSets(): void {
	const allToolVariants = [
		...access_mcp_resource_variants,
		...act_mode_respond_variants,
		// ...alle 22 Werkzeug-Varianten-Arrays
		...apply_patch_variants,
	]

	allToolVariants.forEach((v) => {
		ClineToolSet.register(v)
	})
}

Jede Werkzeugdatei exportiert ein _variants-Array mit ClineToolSpec für verschiedene ModelFamily (allToolVariants:34). Nach der Registrierung deklariert die variant selbst, welche Werkzeug-IDs sie nutzen möchte:

typescript
// apps/vscode/src/core/prompts/system-prompt/variants/generic/config.ts
.tools(
	ClineDefaultTool.BASH,
	ClineDefaultTool.FILE_READ,
	ClineDefaultTool.FILE_NEW,
	ClineDefaultTool.FILE_EDIT,
	ClineDefaultTool.SEARCH,
	ClineDefaultTool.LIST_FILES,
	ClineDefaultTool.LIST_CODE_DEF,
	ClineDefaultTool.BROWSER,
	ClineDefaultTool.MCP_USE,
	ClineDefaultTool.MCP_ACCESS,
	ClineDefaultTool.ASK,
	ClineDefaultTool.ATTEMPT,
	ClineDefaultTool.PLAN_MODE,
	ClineDefaultTool.MCP_DOCS,
	ClineDefaultTool.TODO,
	ClineDefaultTool.GENERATE_EXPLANATION,
	ClineDefaultTool.USE_SKILL,
	ClineDefaultTool.USE_SUBAGENTS,
)

Die generic variant listet 18 Werkzeug-IDs (generic tools:58); getEnabledTools nimmt diese Liste und löst sie einzeln über getToolByNameWithFallback auf, gefiltert durch contextRequirements. Wenn am Ende native tool calling genutzt werden soll, konvertiert der Konverter den ClineToolSpec in das Schema des jeweiligen Providers:

typescript
// apps/vscode/src/core/prompts/system-prompt/spec.ts
export function toolSpecInputSchema(tool: ClineToolSpec, context: SystemPromptContext): AnthropicTool {
	// ...
	const toolInputSchema: AnthropicTool = {
		name: tool.name,
		description: replacer(tool.description, context),
		input_schema: {
			type: "object",
			properties,
			required,
		},
	}
	return toolInputSchema
}

Beachte, dass die Funktion replacer Template-Variablen wie / / ersetzt (replacer:404); in der description eines Werkzeugs können diese Platzhalter stehen und zur Laufzeit anhand des context gefüllt werden.

Grenzen und Fehler

  • Werkzeug doppelt registriert: Gleiche family + gleiche id wird nicht in das Set aufgenommen; im Code wird explizit some(t => t.config.id === config.id) geprüft (dedup:25).
  • MCP-Werkzeug-Name zu lang: Bei mcpToolName.length > 64 wird direkt übersprungen (length check:243); das Werkzeug erscheint nicht im Toolset und kann vom Modell nicht aufgerufen werden.
  • variant ohne deklarierte tools: getEnabledTools gibt bei leerem variant.tools ein leeres Array zurück (empty tools:89), was bedeutet, dass die variant reinen Textdialog ohne Werkzeuge führt.
  • Subagent-Schachtelung: getDynamicSubagentToolSpecs gibt direkt leer zurück, wenn context.isSubagentRun true ist (subagent guard:109), um zu verhindern, dass ein Subagent erneut Subagent-Werkzeuge generiert und eine Endlosrekursion entsteht.
  • use_native_tools-Label nicht gesetzt: getNativeTools gibt defaultmäßig undefined zurück, wenn variant.labels.use_native_tools !== 1 (label gate:175); auch wenn context.enableNativeToolCalls aktiv ist, wird es nicht wirksam; die variant muss es explizit einschalten.
  • Konverter wirft Fehler: Konverter wie toolSpecInputSchema werfen "Tool X does not meet context requirements", wenn tool.contextRequirements nicht erfüllt sind (contextRequirements throw:55); theoretisch wurde bereits durch getEnabledTools gefiltert, dies ist der Rückfall.
  • MCP server.disabled: Beim Abrufen von MCP-Werkzeugen wird zuerst filter(s => s.disabled !== true) angewandt (disabled filter:183); Werkzeuge deaktivierter Server gelangen gar nicht in das Toolset.

Zusammenfassung

ClineToolSet ist die Drei-in-Eins-Kombination aus «zentralem Register + Selektor + Schema-Übersetzer» für Werkzeuge. Das zentrale Design ist, dass derselbe ClineToolSpec sowohl den «Text-XML-Abschnitts»- als auch den «native tool-Schema»-Ausgang nutzen kann, sodass Cline sowohl Modelle mit native function calling als auch Modelle mit nur Textausgabe bedienen kann. MCP-Werkzeuge werden in dasselbe Format wie eingebaute Werkzeuge übersetzt und über dasselbe Management verwaltet; Subagent-Werkzeuge werden zur Laufzeit aus der Konfiguration dynamisch generiert. All das macht den Toolset keine statische Tabelle, sondern ein dynamisch konstruiertes Gebilde.

  • Wie Werkzeug-Prompts als XML-Abschnitt gebaut werden: /prompts/prompt-builder
  • Werkzeugunterschiede zwischen plan / act-Modi: /prompts/mode
  • Wie der Handler den tools-Parameter verarbeitet: /providers/anthropic

Siehe offizielle Dokumentation: Cline-Dokumentation · README