- Startseite
- Documentation
- Laufzeitwerkzeuge
- Benutzerdefinierte Werkzeuge
Benutzerdefinierte Werkzeuge
Benutzerdefinierte Werkzeuge sind modellabrufbare Funktionen, die sich in dieselbe Werkzeugausführungs-Pipeline wie eingebaute Werkzeuge einklinken.
Ein benutzerdefiniertes Werkzeug ist ein TypeScript/JavaScript-Modul, das eine Factory exportiert. Die Factory empfängt eine Host-API (CustomToolAPI) und gibt ein Werkzeug oder ein Array von Werkzeugen zurück.
Was dies ist (und was nicht)
Abschnitt betitelt „Was dies ist (und was nicht)“- Benutzerdefiniertes Werkzeug: vom Modell während eines Durchlaufs aufrufbar (
execute+ TypeBox-Schema). - Erweiterung: Lebenszyklus-/Ereignisframework, das Werkzeuge registrieren und Ereignisse abfangen/modifizieren kann.
- Hook: externe Pre/Post-Befehlsskripte.
- Skill: statisches Leitfaden-/Kontextpaket, kein ausführbarer Werkzeugcode.
Wenn das Modell Code direkt aufrufen soll, verwenden Sie ein benutzerdefiniertes Werkzeug.
Integrationspfade im aktuellen Code
Abschnitt betitelt „Integrationspfade im aktuellen Code“Es gibt zwei aktive Integrationsstile:
-
SDK-bereitgestellte benutzerdefinierte Werkzeuge (
options.customTools)- Werden über
CustomToolAdapteroder Erweiterungskapselungen in Agentenwerkzeuge umgewandelt. - Immer im initialen aktiven Werkzeugsatz beim SDK-Bootstrap enthalten.
- Werden über
-
Dateisystem-erkannte Module über Loader-API (
discoverAndLoadCustomTools/loadCustomTools)- Als Bibliotheks-APIs in
src/extensibility/custom-tools/loader.tsverfügbar. - Host-Code kann diese aufrufen, um Werkzeugmodule aus Konfigurations-/Provider-/Plugin-Pfaden zu entdecken und zu laden.
- Als Bibliotheks-APIs in
Model tool call flow
LLM tool call │ ▼Tool registry (built-ins + custom tool adapters) │ ▼CustomTool.execute(toolCallId, params, onUpdate, ctx, signal) │ ├─ onUpdate(...) -> streamed partial result └─ return result -> final tool content/detailsErkennungsorte (Loader-API)
Abschnitt betitelt „Erkennungsorte (Loader-API)“discoverAndLoadCustomTools(configuredPaths, cwd, builtInToolNames) führt folgende Quellen zusammen:
- Capability-Provider (
toolCapability), einschließlich:- Native OMP-Konfiguration (
~/.xcsh/agent/tools,.xcsh/tools) - Claude-Konfiguration (
~/.claude/tools,.claude/tools) - Codex-Konfiguration (
~/.codex/tools,.codex/tools) - Claude-Marktplatz-Plugin-Cache-Provider
- Native OMP-Konfiguration (
- Installierte Plugin-Manifeste (
~/.xcsh/plugins/node_modules/*über Plugin-Loader) - Explizit konfigurierte Pfade, die an den Loader übergeben werden
Wichtiges Verhalten
Abschnitt betitelt „Wichtiges Verhalten“- Doppelt aufgelöste Pfade werden dedupliziert.
- Werkzeugnamenkonflikte werden gegenüber eingebauten Werkzeugen und bereits geladenen benutzerdefinierten Werkzeugen abgelehnt.
.md- und.json-Dateien werden von einigen Providern als Werkzeugmetadaten erkannt, aber der ausführbare Modullader lehnt sie als ausführbare Werkzeuge ab.- Relative konfigurierte Pfade werden ausgehend von
cwdaufgelöst;~wird expandiert.
Modulvertrag
Abschnitt betitelt „Modulvertrag“Ein benutzerdefiniertes Werkzeugmodul muss eine Funktion exportieren (Standard-Export bevorzugt):
import type { CustomToolFactory } from "@f5-sales-demo/xcsh";
const factory: CustomToolFactory = (pi) => ({ name: "repo_stats", label: "Repo Stats", description: "Counts tracked TypeScript files", parameters: pi.typebox.Type.Object({ glob: pi.typebox.Type.Optional(pi.typebox.Type.String({ default: "**/*.ts" })), }),
async execute(toolCallId, params, onUpdate, ctx, signal) { onUpdate?.({ content: [{ type: "text", text: "Scanning files..." }], details: { phase: "scan" }, });
const result = await pi.exec("git", ["ls-files", params.glob ?? "**/*.ts"], { signal, cwd: pi.cwd }); if (result.killed) { throw new Error("Scan was cancelled"); } if (result.code !== 0) { throw new Error(result.stderr || "git ls-files failed"); }
const files = result.stdout.split("\n").filter(Boolean); return { content: [{ type: "text", text: `Found ${files.length} files` }], details: { count: files.length, sample: files.slice(0, 10) }, }; },
onSession(event) { if (event.reason === "shutdown") { // cleanup resources if needed } },});
export default factory;Factory-Rückgabetyp:
CustomToolCustomTool[]Promise<CustomTool | CustomTool[]>
API-Oberfläche, die an Factories übergeben wird (CustomToolAPI)
Abschnitt betitelt „API-Oberfläche, die an Factories übergeben wird (CustomToolAPI)“Aus types.ts und loader.ts:
cwd: Host-Arbeitsverzeichnisexec(command, args, options?): Hilfsfunktion zur Prozessausführungui: UI-Kontext (kann im Headless-Modus ein No-Op sein)hasUI:falsein nicht-interaktiven Abläufenlogger: gemeinsam genutzter Datei-Loggertypebox: injiziertes@sinclair/typeboxpi: injizierte@f5-sales-demo/xcsh-ExportepushPendingAction(action): registriert eine Vorschauaktion für das versteckteresolve-Werkzeug (docs/resolve-tool-runtime.md)
Der Loader startet mit einem No-Op-UI-Kontext und erfordert, dass der Host-Code setUIContext(...) aufruft, sobald die tatsächliche UI bereit ist.
Ausführungsvertrag und Typisierung
Abschnitt betitelt „Ausführungsvertrag und Typisierung“CustomTool.execute-Signatur:
execute(toolCallId, params, onUpdate, ctx, signal)paramsist aus Ihrem TypeBox-Schema überStatic<TParams>statisch typisiert.- Die Laufzeitargumentvalidierung erfolgt vor der Ausführung in der Agentenschleife.
onUpdategibt partielle Ergebnisse für UI-Streaming aus.ctxenthält den Sitzungs-/Modellzustand und eineabort()-Hilfsfunktion.signalüberträgt den Abbruch.
CustomToolAdapter vermittelt dies an die Agentenwerkzeugschnittstelle und leitet Aufrufe in der richtigen Argumentreihenfolge weiter.
Wie Werkzeuge dem Modell bereitgestellt werden
Abschnitt betitelt „Wie Werkzeuge dem Modell bereitgestellt werden“- Werkzeuge werden in
AgentTool-Instanzen umgewandelt (CustomToolAdapteroder Erweiterungskapselungen). - Sie werden nach Namen in die Sitzungswerkzeugregistrierung eingefügt.
- Beim SDK-Bootstrap werden benutzerdefinierte und erweiterungsregistrierte Werkzeuge zwingend in den initialen aktiven Satz aufgenommen.
- CLI
--toolsvalidiert derzeit nur eingebaute Werkzeugnamen; die Einbindung benutzerdefinierter Werkzeuge erfolgt über Erkennungs-/Registrierungspfade und SDK-Optionen.
Rendering-Hooks
Abschnitt betitelt „Rendering-Hooks“Optionale Rendering-Hooks:
renderCall(args, theme)renderResult(result, options, theme, args?)
Laufzeitverhalten in der TUI:
- Wenn Hooks vorhanden sind, wird die Werkzeugausgabe in einem
Box-Container gerendert. renderResultempfängt{ expanded, isPartial, spinnerFrame? }.- Renderer-Fehler werden abgefangen und protokolliert; die UI fällt auf Standard-Textrendering zurück.
Sitzungs-/Zustandsbehandlung
Abschnitt betitelt „Sitzungs-/Zustandsbehandlung“Das optionale onSession(event, ctx) empfängt Sitzungslebenszyklus-Ereignisse, einschließlich:
start,switch,branch,tree,shutdownauto_compaction_start,auto_compaction_endauto_retry_start,auto_retry_endttsr_triggered,todo_reminder
Verwenden Sie ctx.sessionManager, um den Zustand aus dem Verlauf wiederherzustellen, wenn sich der Branch-/Sitzungskontext ändert.
Fehler und Abbruchsemantik
Abschnitt betitelt „Fehler und Abbruchsemantik“Synchrone/asynchrone Fehler
Abschnitt betitelt „Synchrone/asynchrone Fehler“- Das Auslösen (oder abgelehnte Promises) in
executewird als Werkzeugfehler behandelt. - Die Agentenlaufzeit wandelt Fehler in Werkzeugergebnismeldungen mit
isError: trueund Fehlertextinhalt um. - Mit Erweiterungskapselungen können
tool_result-Handler Inhalt/Details weiter umschreiben und sogar den Fehlerstatus überschreiben.
Abbruch
Abschnitt betitelt „Abbruch“- Der Agentenabbruch wird über
AbortSignalanexecuteweitergegeben. - Leiten Sie
signalan Subprozessarbeiten weiter (pi.exec(..., { signal })), um kooperativen Abbruch zu ermöglichen. ctx.abort()ermöglicht es einem Werkzeug, den Abbruch der aktuellen Agentenoperation anzufordern.
onSession-Fehler
Abschnitt betitelt „onSession-Fehler“onSession-Fehler werden abgefangen und als Warnungen protokolliert; sie führen nicht zum Absturz der Sitzung.
Reale Einschränkungen beim Design
Abschnitt betitelt „Reale Einschränkungen beim Design“- Werkzeugnamen müssen in der aktiven Registrierung global eindeutig sein.
- Bevorzugen Sie deterministische, schemaförmige Ausgaben in
detailsfür Renderer-/Zustandsrekonstruktion. - Schützen Sie die UI-Nutzung mit
pi.hasUI. - Behandeln Sie
.md/.json-Dateien in Werkzeugverzeichnissen als Metadaten, nicht als ausführbare Module.