Hinzufügen eines neuen Harness-Pakets
Diese Anleitung behandelt das Erstellen eines neuen @ai-sdk/harness-<name> Pakets für eine Agenten-Harness.
Bevor du eine Laufzeitumgebung evaluierst, lies die Harness-Anforderungen für Durchführbarkeitskriterien und zu dokumentierende Fähigkeitslücken. Folge den Anforderungen während der Implementierung des Harness-Pakets.
Eine Harness kann host-getrieben sein, wobei die Laufzeitumgebung im Host-Prozess läuft und die Sandbox remote verwendet, oder bridge-gestützt, wobei eine kleine Bridge in der Sandbox läuft, weil die Laufzeitumgebung lokalen Zugriff auf das Sandbox-Dateisystem oder die Prozessumgebung benötigt. Bevorzuge host-getrieben, wenn die Laufzeitumgebung dies unterstützt.
Erstanbieter- vs. Drittanbieter-Harnesses
- Drittanbieter-Pakete: Jede Laufzeitumgebung kann ein externes Harness-Paket veröffentlichen.
- Erstanbieter-
@ai-sdk/harness-<name>Pakete: Erstelle zuerst ein Issue, um zu besprechen, ob die Laufzeitumgebung in dieses Repository gehört.
Referenzbeispiel
Siehe https://github.com/vercel/ai/pull/16255/changes für ein vollständiges Beispiel zum Hinzufügen einer neuen Harness.
Harness-Architektur
Das AI SDK verwendet eine geschichtete Harness-Architektur, die dem Adapter-Muster folgt:
- Harness-Spezifikation (
@ai-sdk/harness): Definiert Schnittstellen wieHarnessV1undHarnessV1Session - Hilfsprogramme (
@ai-sdk/harness/utils): Gemeinsam genutzter Code zur Implementierung von Harnesses - Harness-Implementierungen (
@ai-sdk/harness-<name>): Konkrete Adapter für Harnesses - Harness-Agent (
@ai-sdk/harness/agent): Die hochrangige benutzerorientierteHarnessAgent-API
Schritt-für-Schritt-Anleitung
1. Paketstruktur erstellen
Erstelle packages/harness-<name> mit dieser Grundstruktur:
packages/harness-<name>/
├── src/
│ ├── index.ts
│ ├── <name>-harness.ts
│ ├── <name>-harness.test.ts
│ └── <name>-auth.ts # falls die Laufzeitumgebung Auth-Auflösung benötigt
├── package.json
├── tsconfig.json
├── tsconfig.build.json
├── tsdown.config.ts
├── turbo.json
├── vitest.node.config.js
└── README.md
Wenn die Laufzeitumgebung in der Sandbox ausgeführt werden muss, füge auch Bridge-Dateien hinzu:
src/
├── <name>-bridge-protocol.ts
├── <name>-bridge-protocol.test.ts
└── bridge/
├── index.ts
├── package.json
└── pnpm-lock.yaml
Füge eine CHANGELOG.md hinzu, die nur die Paketüberschrift enthält (# @ai-sdk/harness-<name>). Jedes Paket muss eines haben.
2. package.json konfigurieren
Verwende vorhandene Harness-Pakete als Quelle der Wahrheit für Skripte, Exporte, Repository-Metadaten und Veröffentlichungseinstellungen.
Erforderliche Paketgrundlagen:
"name": "@ai-sdk/harness-<name>""type": "module""version": "0.0.0"(Startpunkt für neue Pakete)"license": "Apache-2.0""sideEffects": false- Abhängigkeit von
@ai-sdk/harnessviaworkspace:* - Abhängigkeit von
@ai-sdk/provider-utilsviaworkspace:*, wenn Sandbox/Auth/Schema-Hilfsprogramme verwendet werden - Laufzeit-SDK/CLI-Abhängigkeiten, die von der Harness benötigt werden
- Dev-Abhängigkeiten, die mit vorhandenen Harness-Paketen übereinstimmen
"engines": { "node": ">=22" }
Für Bridge-Pakete füge alle erforderlichen Bridge-Asset-Kopierschritte für Dateien unter src/bridge/ hinzu.
Bridge-Abhängigkeitsregeln (bridge-gestützte Harnesses):
- Die Laufzeitabhängigkeiten der Bridge leben in
src/bridge/package.json(werden beim Bootstrap in der Sandbox installiert), nicht in der Haupt-package.json. Nach Änderungen generieresrc/bridge/pnpm-lock.yamlneu mitpnpm --dir packages/harness-<name>/src/bridge install --lockfile-only --ignore-workspace(vom Repository-Stamm ausführbar). - Füge für jeden Drittanbieter-Import in
src/bridge/die Abhängigkeit zusrc/bridge/package.jsonhinzu, damit sie in der Sandbox installiert wird. tsdown externalisiert automatisch Abhängigkeiten, Peer-Abhängigkeiten und optionale Abhängigkeiten, die von der Haupt-package.jsondeklariert werden; füge Bridge-spezifische Abhängigkeiten, die dort nicht deklariert sind, zudeps.neverBundleintsdown.config.tshinzu. Eine fehlende Abhängigkeit oder erforderliche Ausnahme kann sich erst zur Laufzeit in der Sandbox als Modulauflösungsfehler zeigen. - Füge Pakete, die die Laufzeitumgebung lazy importiert – z. B. Provider-SDKs (
@anthropic-ai/sdk,openai), die zur Laufzeit anhand der Modell-ID aufgelöst werden – insrc/bridge/package.jsonhinzu, auch wenn sie nicht direkt importiert werden. Sie benötigen keinenneverBundle-Eintrag, es sei denn, die Bridge-Quelle importiert sie. Diese schlagen nur fehl, wenn ein Modell dieses Providers tatsächlich verwendet wird. - Gleiche die Versionen gemeinsamer Abhängigkeiten (Transport, Schema, Tooling, Laufzeit-SDKs) mit denen ab, die derzeit von anderen Harness-Paketen verwendet werden – kopiere von einem Schwesterpaket, anstatt eigene Versionen zu wählen. Veraltete Versionen driften von Sicherheitspatches ab und können vom gemeinsamen Bridge-Laufzeitkontext desynchronisieren; überprüfe die aktuellen Versionen zum Zeitpunkt der Erstellung.
3. TypeScript-, Build- und Test-Konfigurationen erstellen
Kopiere die Konfigurationsdateien des nächstgelegenen vorhandenen Harness-Pakets und passe Pfade/Paketnamen an:
tsconfig.jsontsconfig.build.jsontsdown.config.tsturbo.jsonvitest.node.config.js
Harness-Pakete verwenden derzeit nur Node-Tests, es sei denn, die Implementierung hat einen bestimmten Grund, eine andere Laufzeitumgebung hinzuzufügen.
4. Den Harness-Adapter implementieren
Exportiere eine Factory aus <name>-harness.ts und exportiere sie erneut aus src/index.ts.
Verwende das Architekturdokument für Vertragsdetails. Überprüfe zum Zeitpunkt der Implementierung:
- gib eine
HarnessV1mitspecificationVersion: 'harness-v1'zurück; - verwende eine stabile kebab-case
harnessId; - mache adapter-native integrierte Tools über
builtinToolsverfügbar; - halte die Konstruktion synchron und nebenwirkungsfrei;
- verwende
startOpts.sandboxSessionundstartOpts.sessionWorkDir; erstelle niemals eine separate Sandbox; - wirf einen
HarnessCapabilityUnsupportedErrorvon der Methode, die eine nicht unterstützte Laufzeitfähigkeit benötigt; - hardcore kein Standardmodell, es sei denn, die Laufzeitumgebung benötigt technisch eines – einige zugrunde liegende SDKs haben kein eigenes Standardmodell. Andernfalls übergebe das Modell nur, wenn der Verbraucher eines konfiguriert hat, und lasse das Standardmodell des ursprünglichen SDKs unberührt; halte die
modelIdder Sitzung konsistent mit dem, was tatsächlich gesendet wird (melde kein Modell, das die Bridge stillschweigend überschrieben hat); - behandle die
toolsundinstructions, diedoPromptTurn/doContinueTurnerhalten kann: Wenn die Laufzeitumgebung keine benutzerdefiniertentoolsaufnehmen kann, wirfHarnessCapabilityUnsupportedError, damit es offensichtlich ist, anstatt stillschweigend ignoriert zu werden; wenn sie keine nativeinstructions-Eingabe hat, stelle sie der ersten Benutzernachricht voran (die Codex/Claude Code-Workaround); - setze interpolierte Pfade (
workDir, Bridge-Status-Verzeichnis, …) in Anführungszeichen, wenn Shell-Befehle fürsandbox.run/sandbox.spawnerstellt werden – sie können Leerzeichen enthalten.
Wenn die Laufzeitumgebung eine Einrichtung in der Sandbox benötigt, mache getBootstrap() verfügbar.
5. Laufzeitspezifische Belange implementieren
Füge nur die Belange hinzu, die die Laufzeitumgebung benötigt:
- Auth-Auflösung – verwende für die AI-Gateway-Unterstützung den zentralen
getAiGatewayAuthFromEnv()-Helfer, anstatt die Umgebungsvariablen direkt zu lesen. Dadurch wird sichergestellt, dass sowohlVERCEL_OIDC_TOKENals auchAI_GATEWAY_API_KEYals Gateway-Anmeldeinformationen akzeptiert werden. Wenn die Laufzeitumgebung den Provider pro Modell auflöst, löse den Provider aus der Modell-ID auf und setze die Umgebungsvariablen dieses Providers; wenn die Routen über das Gateway erfolgen, beachte, dass die Basis-URL-Konventionen je nach Provider unterschiedlich sind (z. B. hängt ein Anthropic-Client/v1/messagesan eine Stamm-Basis an, ein OpenAI-Client hängt an eine/v1-Basis an); - AI-Gateway-Client-Attribution – befolge die Konvention in vorhandenen Harness-Paketen: Definiere einen versionierten Client-App-Wert wie
ai-sdk/harness-<name>/${VERSION}und verwende ihn für Gateway-Anfragen. Konfiguriere sowohlUser-Agent- als auchx-client-app-Header, wenn die zugrunde liegende Laufzeitumgebung/das SDK beides unterstützt; mindestens einer dieser beiden Header ist erforderlich. Wenn die Laufzeitumgebung keine benutzerdefinierten Header direkt setzen kann, verwende das von der Laufzeitumgebung unterstützte Äquivalent, das einen dieser Header erzeugt (z. B. eine SDK-Client-App-Umgebungsvariable); - Schema-Übersetzung für benutzerdefinierte Tools – wenn du das JSON-Schema der Host-Tools in das Tool-Format der Laufzeitumgebung konvertierst, konvertiere rekursiv (verschachtelte Objekte, Array-
items, Enums, Beschreibungen); eine flache Konvertierung nur auf oberster Ebene lässt die strukturierte Anleitung des Modells stillschweigend weg. Das direkte Übergeben des JSON-Schemas, wenn die Laufzeitumgebung es akzeptiert, vermeidet das Problem; - Materialisierung von Skills oder Erkennungsdateien;
- Übersetzung des nativen Protokolls in Harness-Stream/Steuerung;
- Lebenszyklus-Status-Schema;
- Bridge-Protokoll und Diagnose.
Bestimmte strukturelle Konventionen für Harness-Adapter werden über die konsistent-CLI erzwungen.
Führe pnpm konsistent aus, sobald du fertig bist, um diese zu überprüfen. Behebe alle gemeldeten Verstöße, bevor du fortfährst.
6. Tests schreiben
Füge gezielte Node-Tests hinzu für:
- Factory-Metadaten und -Einstellungen;
- Auth-Auflösung;
- Sandbox-Nutzung und Pfadplatzierung;
- host-getriebene Remote-Operationen oder Bridge-Protokollverhalten;
- Prompt/Steuerungsereignis-Übersetzung;
- Fortsetzung der Sitzung vs. Fortsetzung des Turns;
- Fehler bei nicht unterstützten Fähigkeiten;
- Skill-Materialisierung, falls unterstützt.
Verwende nach Möglichkeit gemockte Sandbox-Sitzungen und Bridge-/Laufzeitgrenzen. Erfordere keine Live-Provider-Anmeldeinformationen in Unit-Tests.
getBootstrap() liest die kompilierten Bridge-Assets (z. B. dist/bridge/index.mjs), die nicht existieren, wenn Tests gegen src ausgeführt werden, daher wird ein Test, der sie aufruft, auf ENOENT stoßen. Mocke node:fs/promises readFile für die Bridge-Asset-Pfade (siehe die Codex/OpenCode-Harness-Tests für das Muster).
7. README hinzufügen
Halte die README kurz:
- Paketzweck;
- Einrichtungsbefehl;
- minimale
HarnessAgent-Nutzung; - erforderliche Sandbox-Fähigkeiten, wie z. B. Ports für bridge-gestützte Laufzeitumgebungen;
- bemerkenswerte Auth-Konfiguration.
Verlinke auf die Haupt-Harness-Dokumentation für weitergehende Konzepte.
8. Beispiele hinzufügen
Füge relevante Beispiele für die neue Harness hinzu.
- Füge erforderliche API/Funktionsbeispiele unter
examples/ai-functions/src/harness-agentund interaktive Beispiele unterexamples/harness-e2e-nexthinzu.
9. Dokumentation hinzufügen
Erstelle Dokumentation in content/providers/02-ai-sdk-harnesses/<nächste Nummer>-<name>.mdx.
Füge hinzu:
- Einrichtungsanweisungen
- Erforderliche Sandbox-Fähigkeiten
- Authentifizierungskonfiguration
- Harness-spezifische Optionen
- Nutzungsbeispiele
- Bekannte Einschränkungen
Aktualisiere content/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx, um die neue Harness aufzulisten, wenn sie veröffentlicht werden soll.
10. Referenzen aktualisieren und validieren
Führe vom Arbeitsbereichsstamm aus:
pnpm konsistent
pnpm update-references
pnpm --filter @ai-sdk/harness-<name> build
pnpm --filter @ai-sdk/harness-<name> test
pnpm type-check:full
Füge ein Changeset mit pnpm changeset hinzu. Verwende für die erste Veröffentlichung eines brandneuen Harness-Pakets major (nicht das übliche patch), passend zu den anderen Harness-Paketen.
Führe relevante Harness-Beispiele frühzeitig gegen eine Live-Sandbox aus – verlasse dich nicht nur auf Unit-Tests und type-check. Laufzeit-API-Einschränkungen (z. B. unerwartete Konfigurationsoption-Ablehnungen, die genauen Streaming-Ereignisnamen, die die Laufzeitumgebung ausgibt, Gateway-Basis-URL-Format) treten nur zutage, wenn die Bridge die Laufzeitumgebung tatsächlich steuert, und sie sind weitaus billiger zu finden, bevor die Dokumentation/Beispiele darauf aufbauen.
Checkliste
- Paketstruktur in
packages/harness-<name>erstellt -
package.jsonmit korrekten Abhängigkeiten konfiguriert - TypeScript-Konfigurationen eingerichtet (
tsconfig.json,tsconfig.build.json) - Build-Konfiguration (
tsdown.config.ts) - Test-Konfiguration (
vitest.node.config.js) - Harness-Adapter-Implementierung abgeschlossen
- Laufzeit-Platzierung ohne Erstellung einer versteckten Sandbox behandelt
- Bridge-Assets während des Builds kopiert, falls bridge-gestützt
- Auth-Auflösung implementiert, falls erforderlich
- AI-Gateway-Anfragen enthalten
User-Agent- und/oderx-client-app-Client-Attribution - Harness-Infrastruktur, Skills, Bridge-Code und Geheimnisse aus
sessionWorkDirferngehalten - Sitzungsfortsetzung und Turn-Fortsetzung getestet
- Unit-Tests geschrieben und bestanden
- README.md geschrieben
-
CHANGELOG.mdhinzugefügt (Paketüberschrift; vonkonsistenterforderlich) - Changeset hinzugefügt (
majorfür eine erste Veröffentlichung) - Beispiele hinzugefügt
- Dokumentation in
content/providers/02-ai-sdk-harnesses/hinzugefügt - Harness-Adapter-Liste aktualisiert, falls öffentlich
- Gegen eine Live-Sandbox validiert (nicht nur Unit-Tests / type-check)
-
pnpm update-referencesausgeführt - Paket-Build erfolgreich
- Paket-Tests erfolgreich
- Typprüfung erfolgreich (
pnpm type-check:fullvom Stamm) - Relevante Beispiele erfolgreich ausgeführt
Verwandte Dokumentation
- Harness-Abstraktionsarchitektur
@ai-sdk/harnessREADME- Vorhandene Harness-Pakete mit ähnlicher Laufzeit-Platzierung