Dropstone CLI

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

  1. Melden Sie sich unter dropstone.io/dashboard an.
  2. Öffnen Sie Einstellungen → API unter dropstone.io/dashboard/settings und erstellen Sie einen Schlüssel – er sieht aus wie dsk_live_<43 Zeichen>.
  3. Setzen Sie ihn als Umgebungsvariable (oder übergeben Sie apiKey an createDropstoneApi):
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

OptionTypBeschreibungStandard
hostnamestringServer-Hostname127.0.0.1
portnumberServer-Port4096
signalAbortSignalAbbruchsignal für die Stornierungundefined
timeoutnumberTimeout in ms für den Serverstart5000
configConfigKonfigurationsobjekt{}

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:

ToolZweck
memory_recallRuft die relevantesten Lektionen für die aktuelle Aufgabe ab
record_lessonSpeichert eine dauerhafte Lektion (eine Regel oder eine Tatsache)
list_lessonsZeigt alles, was er über Sie gelernt hat
forget_lessonEntfernt 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

OptionTypBeschreibungStandard
baseUrlstringURL des Servershttp://localhost:4096
fetchfunctionBenutzerdefinierte fetch-ImplementierungglobalThis.fetch
parseAsstringAntwort-Parsing-Methodeauto
responseStylestringRückgabestil: data oder fieldsfields
throwOnErrorbooleanFehler werfen statt zurückgebenfalse

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

TypBeschreibung
textStandard. Standardtextantwort (keine strukturierte Ausgabe)
json_schemaGibt validiertes JSON zurück, das dem bereitgestellten Schema entspricht

JSON-Schema-Format

Bei Verwendung von type: 'json_schema' geben Sie an:

FeldTypBeschreibung
type'json_schema'Erforderlich. Gibt den JSON-Schema-Modus an
schemaobjectErforderlich. JSON-Schema-Objekt, das die Ausgabestruktur definiert
retryCountnumberOptional. 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

  1. Geben Sie klare Beschreibungen in Ihren Schema-Eigenschaften an, damit das Modell versteht, welche Daten extrahiert werden sollen
  2. Verwenden Sie required, um anzugeben, welche Felder vorhanden sein müssen
  3. Halten Sie Schemas fokussiert – komplexe verschachtelte Schemas können für das Modell schwerer korrekt auszufüllen sein
  4. 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

MethodeBeschreibungAntwort
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

MethodeBeschreibungAntwort
app.log()Einen Log-Eintrag schreibenboolean
app.agents()Alle verfügbaren Agenten auflistenAgent[]

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

MethodeBeschreibungAntwort
project.list()Alle Projekte auflistenProject[]
project.current()Aktuelles Projekt abrufenProject

Beispiele

// Alle Projekte auflisten
const projects = await client.project.list()

// Aktuelles Projekt abrufen
const currentProject = await client.project.current()

Pfad

MethodeBeschreibungAntwort
path.get()Aktuellen Pfad abrufenPath

Beispiele

// Aktuelle Pfadinformationen abrufen
const pathInfo = await client.path.get()

Konfiguration

MethodeBeschreibungAntwort
config.get()Konfigurationsinfo abrufenConfig

Beispiele

const config = await client.config.get()

Sitzungen

MethodeBeschreibungHinweise
session.list()Sitzungen auflistenGibt Session[] zurück
session.get({ path })Sitzung abrufenGibt Session zurück
session.children({ path })Untersitzungen auflistenGibt Session[] zurück
session.create({ body })Sitzung erstellenGibt Session zurück
session.delete({ path })Sitzung löschenGibt boolean zurück
session.update({ path, body })Sitzungseigenschaften aktualisierenGibt Session zurück
session.init({ path, body })App analysieren und AGENTS.md erstellenGibt boolean zurück
session.abort({ path })Eine laufende Sitzung abbrechenGibt boolean zurück
session.summarize({ path, body })Sitzung zusammenfassenGibt boolean zurück
session.messages({ path })Nachrichten in einer Sitzung auflistenGibt { info: Message, parts: Part[]}[] zurück
session.message({ path })Nachrichtendetails abrufenGibt { info: Message, parts: Part[]} zurück
session.prompt({ path, body })Eingabeaufforderungsnachricht sendenbody.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 sendenGibt { info: AssistantMessage, parts: Part[]} zurück
session.shell({ path, body })Shell-Befehl ausführenGibt AssistantMessage zurück
session.revert({ path, body })Eine Nachricht zurücknehmenGibt Session zurück
session.unrevert({ path })Zurückgenommene Nachrichten wiederherstellenGibt Session zurück
postSessionByIdPermissionsByPermissionId({ path, body })Auf eine Berechtigungsanfrage antwortenGibt 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

MethodeBeschreibungAntwort
find.text({ query })Nach Text in Dateien suchenArray von Übereinstimmungsobjekten mit path, lines, line_number, absolute_offset, submatches
find.files({ query })Dateien und Verzeichnisse nach Namen findenstring[] (Pfade)
find.symbols({ query })Workspace-Symbole findenSymbol[]
file.read({ query })Eine Datei lesen{ type: "raw" | "patch", content: string }
file.status({ query? })Status für verfolgte Dateien abrufenFile[]

find.files unterstützt einige optionale Abfragefelder:

  • type: "file" oder "directory"
  • directory: Projektstamm für die Suche überschreiben
  • limit: 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

MethodeBeschreibungAntwort
auth.set({ ... })Authentifizierungsdaten festlegenboolean

Beispiele

await client.auth.set({
  path: { id: "dropstone" },
  body: { type: "api", key: "ihr-dropstone-api-schluessel" },
})

Ereignisse

MethodeBeschreibungAntwort
event.subscribe()Server-Sent-Events-StreamServer-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.

Strg+I