ClineToolSet: Werkzeugdefinition und Schema-Konvertierung
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
ClineToolSpeclä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:
getToolByNameWithFallbacksucht 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) => booleandeklarieren; z. B. verlangtbrowser_actionsupportsBrowserUse=true; wird der Kontext nicht erfüllt, wird es herausgefiltert (ctx filter:101), was flexibler ist als eine hartcodierte variant-Liste. - Dynamische Subagent-Werkzeuge:
getDynamicSubagentToolSpecsgeneriert zur Laufzeit anhand der vonAgentConfigLoadergeladenen Subagent-Konfiguration mehrere Varianten desUSE_SUBAGENTS-Werkzeugs (dynamic subagent:108); pro Subagent ein Name, daher ist der Werkzeugsatz nicht statisch. - MCP-Werkzeuge einheitlich im Toolset:
mcpToolToClineToolSpecwandelt die von MCP-Servern exponierten tools in dasClineToolSpec-Format um; die id ist immeruse_mcp_tool, der NameserverUid__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ältvariants: 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, wennvariant.labels.use_native_tools === 1undcontext.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, mitstrict: false,additionalProperties: false.toolSpecInputSchema:145— Konvertierung in Anthropic Tool, Feldname istinput_schemanichtparameters.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:
// 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:
// 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:
// 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 > 64wird direkt übersprungen (length check:243); das Werkzeug erscheint nicht im Toolset und kann vom Modell nicht aufgerufen werden. - variant ohne deklarierte tools:
getEnabledToolsgibt bei leeremvariant.toolsein leeres Array zurück (empty tools:89), was bedeutet, dass die variant reinen Textdialog ohne Werkzeuge führt. - Subagent-Schachtelung:
getDynamicSubagentToolSpecsgibt direkt leer zurück, wenncontext.isSubagentRuntrue ist (subagent guard:109), um zu verhindern, dass ein Subagent erneut Subagent-Werkzeuge generiert und eine Endlosrekursion entsteht. - use_native_tools-Label nicht gesetzt:
getNativeToolsgibt defaultmäßig undefined zurück, wennvariant.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
toolSpecInputSchemawerfen"Tool X does not meet context requirements", wenntool.contextRequirementsnicht erfüllt sind (contextRequirements throw:55); theoretisch wurde bereits durchgetEnabledToolsgefiltert, 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