Dropstone SDK
Typsicherer JS-Client für die Dropstone-Agent-Laufzeitumgebung. SDK-Sitzungen erben Dropstones oberflächenübergreifenden Speicher (Continuity) – ein persistenter Speicher, der mit CLI, Chat und SDK geteilt wird.
Das Dropstone JS/TS SDK bietet einen typsicheren Client für die Interaktion mit der Dropstone-Agent-Laufzeitumgebung. Es startet dropstone serve als Unterprozess und gibt Ihnen einen typisierten HTTP-Client, der darauf zeigt. Da es denselben lokalen Agenten verwendet wie die CLI, erbt jede SDK-Sitzung Ihren Kontospeicher – einmal in CLI, Chat oder SDK beigebracht und jede Oberfläche weiß es bereits (siehe Speicher (Continuity)).
Benötigen Sie Headless-API-Zugriff in CI?
Für rein programmatische Nutzung (CI-Pipelines, Automatisierung, Serverless) bevorzugen Sie die HTTP-API mit einem DROPSTONE_API_KEY. Das SDK auf dieser Seite ist für die Einbettung des interaktiven Agenten in einen Node-Prozess gedacht, bei dem die CLI-Binary daneben installiert ist.
Siehe die Seite Server für Details zur zugrunde liegenden HTTP-API.
Installation
Installieren Sie das SDK von npm:
npm install @blankline/dropstone-sdk
Headless-API-Client
Für CI-Pipelines, Automatisierung und Serverless benötigen Sie die CLI überhaupt nicht. Verwenden Sie den Headless-Client, der direkt mit der Dropstone-HTTP-API über einen API-Schlüssel kommuniziert:
import { createDropstoneApi } from "@blankline/dropstone-sdk"
// Liest DROPSTONE_API_KEY automatisch aus der Umgebung.
const dropstone = createDropstoneApi()
const resp = await dropstone.chat.completions.create({
model: "dropstone-fast", // oder "dropstone-pro" / "dropstone-heavy"
messages: [{ role: "user", content: "Schreibe ein Haiku über das Debuggen." }],
})
console.log(resp.choices[0].message.content)
console.log("Kosten: $" + resp.usage?.cost) // abgerechneter Betrag in USD
API-Schlüssel erhalten
- Melden Sie sich unter dropstone.io/dashboard an.
- Öffnen Sie Einstellungen → API unter dropstone.io/dashboard/settings und erstellen Sie einen Schlüssel – er sieht aus wie
dsk_live_<43 Zeichen>. - Setzen Sie ihn als Umgebungsvariable (oder übergeben Sie
apiKeyancreateDropstoneApi):
export DROPSTONE_API_KEY=dsk_live_...
Note
Behandeln Sie Ihren API-Schlüssel wie ein Passwort. Committen Sie ihn niemals in Git und betten Sie ihn nicht in ein Frontend-Bundle ein. API-Schlüssel-Anfragen werden nutzungsbasiert von Ihrem Prepaid-Guthaben abgerechnet – Plan-Kontingente gelten nicht. Siehe Nutzung & Limits.
Streaming funktioniert auf dieselbe Weise, und der Client ist OpenAI-kompatibel – Sie können das OpenAI SDK stattdessen auf die Basis-URL von Dropstone ausrichten:
const stream = await dropstone.chat.completions.create({
model: "dropstone-fast",
stream: true,
messages: [{ role: "user", content: "Zähle bis 5." }],
})
for await (const chunk of stream) {
process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "")
}
Siehe die Seite HTTP-API für die vollständige Referenz.
Client erstellen
Erstellen Sie eine Instanz von dropstone:
import { createDropstone } from "@blankline/dropstone-sdk"
const { client } = await createDropstone()
Dies startet sowohl einen Server als auch einen Client. Jede SDK-Methode gibt { data, request, response } zurück, greifen Sie also über .data auf die Nutzdaten zu.
Standardmäßig meldet sich der Server als derjenige an, der dropstone auth login auf dieser Maschine ausgeführt hat. Auf einem unbeaufsichtigten Host gibt es kein solches Konto, also übergeben Sie einen API-Schlüssel und eine explizite Berechtigungs-Allowlist über config:
const { client } = await createDropstone({
config: {
provider: {
dropstone: {
options: {
apiKey: process.env.DROPSTONE_API_KEY,
baseURL: "https://api.dropstone.io/api/v1",
},
},
},
permission: { "*": "deny", read: "allow", edit: "allow", glob: "allow", grep: "allow", bash: "allow" },
},
})
Beide Teile sind erforderlich. API-Schlüssel werden unter /v1 abgelehnt, und der Standard-build-Agent fragt vor jedem Tool-Aufruf nach, sodass der Lauf ohne Allowlist auf eine Genehmigung wartet, die niemand geben kann, und hängt statt fehlzuschlagen. Das Senden von "agent": "accept all" auf der Eingabeaufforderung ist die Alternative zur Allowlist. Siehe Server und Berechtigungen.
Optionen
| Option | Typ | Beschreibung | Standard |
|---|---|---|---|
hostname | string | Server-Hostname | 127.0.0.1 |
port | number | Server-Port | 4096 |
signal | AbortSignal | Abbruchsignal für die Stornierung | undefined |
timeout | number | Timeout in ms für den Serverstart | 5000 |
config | Config | Konfigurationsobjekt | {} |
Konfiguration
Sie können ein Konfigurationsobjekt übergeben, um das Verhalten anzupassen. Die Instanz übernimmt weiterhin Ihre dropstone.json, aber Sie können Konfiguration inline überschreiben oder hinzufügen:
import { createDropstone } from "@blankline/dropstone-sdk"
const dropstone = await createDropstone({
hostname: "127.0.0.1",
port: 4096,
config: {
model: "dropstone/dropstone-pro",
},
})
console.log(`Server läuft unter ${dropstone.server.url}`)
dropstone.server.close()
Speicher (Continuity)
Dropstone führt einen persistenten Speicher pro Konto. Wir nennen ihn Continuity – einen oberflächenübergreifenden Speicher, der von CLI, Chat, VS Code und dem SDK geteilt wird. Einmal irgendwo beigebracht und jede Oberfläche weiß es bereits.
Sitzungen, die Sie über das SDK ausführen, verwenden denselben Kontospeicher wie die CLI. Was Sie der CLI beibringen, ist SDK-Sitzungen bereits bekannt, und was eine SDK-Sitzung aufzeichnet, ist wieder in CLI und Chat verfügbar. Bei jeder Runde ruft der Agent automatisch relevanten Speicher ab, bevor er antwortet, sodass er nicht neu lernt, was er bereits weiß.
Der SDK-Agent kann Speicher auch direkt lesen und schreiben, mit denselben Tools wie die CLI:
| Tool | Zweck |
|---|---|
memory_recall | Ruft die relevantesten Lektionen für die aktuelle Aufgabe ab |
record_lesson | Speichert eine dauerhafte Lektion (eine Regel oder eine Tatsache) |
list_lessons | Zeigt alles, was er über Sie gelernt hat |
forget_lesson | Entfernt eine Lektion |
Note
Speicher erfordert, dass Sie bei Dropstone angemeldet sind. Der SDK-Server liest dieselbe auth.json wie die CLI, also melden Sie sich einmal mit dropstone an und SDK-Sitzungen erben denselben Kontospeicher. Wenn Sie nicht angemeldet sind, wird nichts gespeichert.
Beispiel
Geben Sie eine Präferenz aus Code an, und sie wird auf dieselbe Weise aufgezeichnet wie in der CLI – danach in CLI und Chat sichtbar:
const { client } = await createDropstone()
const session = await client.session.create({ body: { title: "Speicher beibringen" } })
await client.session.prompt({
path: { id: session.data.id },
body: {
parts: [{ type: "text", text: "Merke dir das als dauerhafte Regel: verwende immer bun, nicht npm." }],
},
})
Continuity vs. AGENTS.md
AGENTS.md ist eine Projektdatei, die Sie für Teamkonventionen in Git committen – stabil, repo-bezogen und für alle geteilt, die sie klonen. Continuity ist Ihr privater Kontospeicher: Was Sie in CLI, Chat oder SDK beibringen, folgt Ihrem Konto über Oberflächen und Projekte hinweg. Sie lösen unterschiedliche Probleme und funktionieren am besten zusammen – Projektregeln in AGENTS.md, persönlicher oberflächenübergreifender Speicher in Continuity. Siehe Regeln und Speicher.
Was gespeichert wird
Der Speicher enthält nur die Regeln und Tatsachen, die Sie ihm explizit beibringen – Präferenzen, Konventionen und Korrekturen, die es wert sind, über Sitzungen hinweg getragen zu werden. Er unterscheidet sich vom ephemeren Kontext einer einzelnen Sitzung, der nach Ende der Sitzung nicht aufbewahrt wird.
Siehe die Seite Speicher für Details, wie Dropstone entscheidet, was behalten wird.
Nur Client
Wenn Sie bereits eine laufende Instanz von dropstone haben, können Sie eine Client-Instanz erstellen, um sich mit ihr zu verbinden:
import { createDropstoneClient } from "@blankline/dropstone-sdk"
const client = createDropstoneClient({
baseUrl: "http://localhost:4096",
})
Optionen
| Option | Typ | Beschreibung | Standard |
|---|---|---|---|
baseUrl | string | URL des Servers | http://localhost:4096 |
fetch | function | Benutzerdefinierte fetch-Implementierung | globalThis.fetch |
parseAs | string | Antwort-Parsing-Methode | auto |
responseStyle | string | Rückgabestil: data oder fields | fields |
throwOnError | boolean | Fehler werfen statt zurückgeben | false |
Typen
Das SDK enthält TypeScript-Definitionen für alle API-Typen. Importieren Sie sie direkt:
import type { Session, Message, Part } from "@blankline/dropstone-sdk"
Alle Typen werden aus der OpenAPI-Spezifikation des Servers generiert, sodass die Namen, die Sie in TypeScript sehen, eins-zu-eins den Server-Anfrage- und Antwortformen entsprechen.
Fehler
Das SDK kann Fehler werfen, die Sie abfangen und behandeln können:
try {
await client.session.get({ path: { id: "invalid-id" } })
} catch (error) {
console.error("Sitzung konnte nicht abgerufen werden:", (error as Error).message)
}
Strukturierte Ausgabe
Sie können strukturierte JSON-Ausgabe vom Modell anfordern, indem Sie ein format mit einem JSON-Schema angeben. Das Modell verwendet ein StructuredOutput-Tool, um validiertes JSON zurückzugeben, das Ihrem Schema entspricht.
Grundlegende Verwendung
const result = await client.session.prompt({
path: { id: sessionId },
body: {
parts: [{ type: "text", text: "Recherchiere Dropstone und gib Firmeninformationen an" }],
format: {
type: "json_schema",
schema: {
type: "object",
properties: {
company: { type: "string", description: "Firmenname" },
founded: { type: "number", description: "Gründungsjahr" },
products: {
type: "array",
items: { type: "string" },
description: "Hauptprodukte",
},
},
required: ["company", "founded"],
},
},
},
})
// Auf die strukturierte Ausgabe zugreifen
console.log(result.data.info.structured_output)
// { company: "Dropstone", founded: 2024, products: ["Dropstone CLI"] }
Ausgabeformat-Typen
| Typ | Beschreibung |
|---|---|
text | Standard. Standardtextantwort (keine strukturierte Ausgabe) |
json_schema | Gibt validiertes JSON zurück, das dem bereitgestellten Schema entspricht |
JSON-Schema-Format
Bei Verwendung von type: 'json_schema' geben Sie an:
| Feld | Typ | Beschreibung |
|---|---|---|
type | 'json_schema' | Erforderlich. Gibt den JSON-Schema-Modus an |
schema | object | Erforderlich. JSON-Schema-Objekt, das die Ausgabestruktur definiert |
retryCount | number | Optional. Anzahl der Validierungswiederholungen (Standard: 2) |
Fehlerbehandlung
Wenn das Modell nach allen Wiederholungen keine gültige strukturierte Ausgabe erzeugt, enthält die Antwort einen StructuredOutputError:
if (result.data.info.error?.name === "StructuredOutputError") {
console.error("Strukturierte Ausgabe fehlgeschlagen:", result.data.info.error.message)
console.error("Versuche:", result.data.info.error.retries)
}
Best Practices
- Geben Sie klare Beschreibungen in Ihren Schema-Eigenschaften an, damit das Modell versteht, welche Daten extrahiert werden sollen
- Verwenden Sie
required, um anzugeben, welche Felder vorhanden sein müssen - Halten Sie Schemas fokussiert – komplexe verschachtelte Schemas können für das Modell schwerer korrekt auszufüllen sein
- Setzen Sie einen angemessenen
retryCount– erhöhen Sie ihn für komplexe Schemas, verringern Sie ihn für einfache
APIs
Das SDK stellt alle Server-APIs über einen typsicheren Client bereit.
Global
| Methode | Beschreibung | Antwort |
|---|---|---|
global.health() | Server-Gesundheit und Version prüfen | { healthy: true, version: string } |
Beispiele
const health = await client.global.health()
console.log(health.data.version)
App
| Methode | Beschreibung | Antwort |
|---|---|---|
app.log() | Einen Log-Eintrag schreiben | boolean |
app.agents() | Alle verfügbaren Agenten auflisten | Agent[] |
Beispiele
// Einen Log-Eintrag schreiben
await client.app.log({
body: {
service: "my-app",
level: "info",
message: "Vorgang abgeschlossen",
},
})
// Verfügbare Agenten auflisten
const agents = await client.app.agents()
Projekt
| Methode | Beschreibung | Antwort |
|---|---|---|
project.list() | Alle Projekte auflisten | Project[] |
project.current() | Aktuelles Projekt abrufen | Project |
Beispiele
// Alle Projekte auflisten
const projects = await client.project.list()
// Aktuelles Projekt abrufen
const currentProject = await client.project.current()
Pfad
| Methode | Beschreibung | Antwort |
|---|---|---|
path.get() | Aktuellen Pfad abrufen | Path |
Beispiele
// Aktuelle Pfadinformationen abrufen
const pathInfo = await client.path.get()
Konfiguration
| Methode | Beschreibung | Antwort |
|---|---|---|
config.get() | Konfigurationsinfo abrufen | Config |
Beispiele
const config = await client.config.get()
Sitzungen
| Methode | Beschreibung | Hinweise |
|---|---|---|
session.list() | Sitzungen auflisten | Gibt Session[] zurück |
session.get({ path }) | Sitzung abrufen | Gibt Session zurück |
session.children({ path }) | Untersitzungen auflisten | Gibt Session[] zurück |
session.create({ body }) | Sitzung erstellen | Gibt Session zurück |
session.delete({ path }) | Sitzung löschen | Gibt boolean zurück |
session.update({ path, body }) | Sitzungseigenschaften aktualisieren | Gibt Session zurück |
session.init({ path, body }) | App analysieren und AGENTS.md erstellen | Gibt boolean zurück |
session.abort({ path }) | Eine laufende Sitzung abbrechen | Gibt boolean zurück |
session.summarize({ path, body }) | Sitzung zusammenfassen | Gibt boolean zurück |
session.messages({ path }) | Nachrichten in einer Sitzung auflisten | Gibt { info: Message, parts: Part[]}[] zurück |
session.message({ path }) | Nachrichtendetails abrufen | Gibt { info: Message, parts: Part[]} zurück |
session.prompt({ path, body }) | Eingabeaufforderungsnachricht senden | body.noReply: true gibt UserMessage zurück (nur Kontext). Standard gibt AssistantMessage mit KI-Antwort zurück. Unterstützt body.outputFormat für strukturierte Ausgabe |
session.command({ path, body }) | Befehl an Sitzung senden | Gibt { info: AssistantMessage, parts: Part[]} zurück |
session.shell({ path, body }) | Shell-Befehl ausführen | Gibt AssistantMessage zurück |
session.revert({ path, body }) | Eine Nachricht zurücknehmen | Gibt Session zurück |
session.unrevert({ path }) | Zurückgenommene Nachrichten wiederherstellen | Gibt Session zurück |
postSessionByIdPermissionsByPermissionId({ path, body }) | Auf eine Berechtigungsanfrage antworten | Gibt boolean zurück |
Beispiele
// Sitzungen erstellen und verwalten
const session = await client.session.create({
body: { title: "Meine Sitzung" },
})
const sessions = await client.session.list()
// Eine Eingabeaufforderungsnachricht senden
const result = await client.session.prompt({
path: { id: session.data.id },
body: {
model: { providerID: "dropstone", modelID: "dropstone-pro" },
parts: [{ type: "text", text: "Hallo!" }],
},
})
// Kontext injizieren, ohne KI-Antwort auszulösen (nützlich für Plugins)
await client.session.prompt({
path: { id: session.data.id },
body: {
noReply: true,
parts: [{ type: "text", text: "Du bist ein hilfreicher Assistent." }],
},
})
Dateien
| Methode | Beschreibung | Antwort |
|---|---|---|
find.text({ query }) | Nach Text in Dateien suchen | Array von Übereinstimmungsobjekten mit path, lines, line_number, absolute_offset, submatches |
find.files({ query }) | Dateien und Verzeichnisse nach Namen finden | string[] (Pfade) |
find.symbols({ query }) | Workspace-Symbole finden | Symbol[] |
file.read({ query }) | Eine Datei lesen | { type: "raw" | "patch", content: string } |
file.status({ query? }) | Status für verfolgte Dateien abrufen | File[] |
find.files unterstützt einige optionale Abfragefelder:
type:"file"oder"directory"directory: Projektstamm für die Suche überschreibenlimit: maximale Ergebnisse (1–200)
Beispiele
// Dateien suchen und lesen
const textResults = await client.find.text({
query: { pattern: "function.*dropstone" },
})
const files = await client.find.files({
query: { query: "*.ts", type: "file" },
})
const directories = await client.find.files({
query: { query: "packages", type: "directory", limit: 20 },
})
const content = await client.file.read({
query: { path: "src/index.ts" },
})
Authentifizierung
| Methode | Beschreibung | Antwort |
|---|---|---|
auth.set({ ... }) | Authentifizierungsdaten festlegen | boolean |
Beispiele
await client.auth.set({
path: { id: "dropstone" },
body: { type: "api", key: "ihr-dropstone-api-schluessel" },
})
Ereignisse
| Methode | Beschreibung | Antwort |
|---|---|---|
event.subscribe() | Server-Sent-Events-Stream | Server-Sent-Events-Stream |
Beispiele
// Auf Echtzeit-Ereignisse hören
const events = await client.event.subscribe()
for await (const event of events.stream) {
console.log("Ereignis:", event.type, event.properties)
}
v2-API
Das SDK enthält eine stabile v1-Oberfläche (in den obigen Beispielen verwendet) und eine v2-Oberfläche, die den neueren Effect HttpApi-Vertrag widerspiegelt. Bevorzugen Sie v2 für neue Integrationen:
import { createDropstone } from "@blankline/dropstone-sdk/v2"
const { client, server } = await createDropstone()
// v2 stellt eine reichhaltigere Ressourcenhierarchie bereit: workspace, worktree, file, find, usw.
const files = await client.file.list({ path: "src" })
Die v1-Oberfläche wird aus Gründen der Abwärtskompatibilität beibehalten. Neue Endpunkte landen nur auf v2.