Dropstone SDK
Client JS type-safe per il runtime dell'agente Dropstone. Le sessioni SDK ereditano la memoria cross-surface di Dropstone (Continuity) — una memoria persistente condivisa con CLI, chat e SDK.
L'SDK JS/TS di Dropstone fornisce un client type-safe per interagire con il runtime dell'agente Dropstone. Avvia dropstone serve come sottoprocesso e ti offre un client HTTP tipizzato puntato su di esso. Poiché esegue lo stesso agente locale usato dalla CLI, ogni sessione SDK eredita la memoria del tuo account — insegnagli una volta nella CLI, nella chat o nell'SDK e ogni superficie la conoscerà già (vedi Memoria (Continuity)).
Ti serve accesso API headless in CI?:
Per uso puramente programmatico (pipeline CI, automazione, serverless), preferisci l'API HTTP con una DROPSTONE_API_KEY. L'SDK in questa pagina è pensato per incorporare l'agente interattivo in un processo Node dove il binario CLI è installato accanto.
Vedi la pagina Server per come funziona l'API HTTP sottostante.
Installazione
Installa l'SDK da npm:
npm install @blankline/dropstone-sdk
Client API headless
Per pipeline CI, automazione e serverless non ti serve affatto la CLI. Usa il client headless, che parla direttamente con l'API HTTP di Dropstone con una chiave API:
import { createDropstoneApi } from "@blankline/dropstone-sdk"
// Legge DROPSTONE_API_KEY dall'ambiente automaticamente.
const dropstone = createDropstoneApi()
const resp = await dropstone.chat.completions.create({
model: "dropstone-fast", // oppure "dropstone-pro" / "dropstone-heavy"
messages: [{ role: "user", content: "Scrivi un haiku sul debugging." }],
})
console.log(resp.choices[0].message.content)
console.log("Costo: $" + resp.usage?.cost) // importo addebitato, in USD
Ottieni una chiave API
- Accedi su dropstone.io/dashboard.
- Apri Impostazioni → API su dropstone.io/dashboard/settings e crea una chiave — ha questo formato
dsk_live_<43 caratteri>. - Impostala come variabile d'ambiente (oppure passa
apiKeyacreateDropstoneApi):
export DROPSTONE_API_KEY=dsk_live_...
Note:
Tratta la tua chiave API come una password. Non committarla mai in git né incorporarla in un bundle frontend. Le richieste con chiave API vengono addebitate pay-per-use dal tuo saldo di credito prepagato — le quote dei piani non si applicano. Vedi Utilizzo e limiti.
Lo streaming funziona allo stesso modo e il client è compatibile con OpenAI — puoi puntare l'SDK OpenAI all'URL di base di Dropstone:
const stream = await dropstone.chat.completions.create({
model: "dropstone-fast",
stream: true,
messages: [{ role: "user", content: "Conta fino a 5." }],
})
for await (const chunk of stream) {
process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "")
}
Vedi la pagina API HTTP per il riferimento completo.
Crea client
Crea un'istanza di dropstone:
import { createDropstone } from "@blankline/dropstone-sdk"
const { client } = await createDropstone()
Questo avvia sia un server che un client. Ogni metodo SDK restituisce { data, request, response }, quindi accedi al payload tramite .data.
Opzioni
| Opzione | Tipo | Descrizione | Default |
|---|---|---|---|
hostname | string | Hostname del server | 127.0.0.1 |
port | number | Porta del server | 4096 |
signal | AbortSignal | Segnale di annullamento | undefined |
timeout | number | Timeout in ms per l'avvio | 5000 |
config | Config | Oggetto di configurazione | {} |
Config
Puoi passare un oggetto di configurazione per personalizzare il comportamento. L'istanza rileva comunque il tuo dropstone.json, ma puoi sovrascrivere o aggiungere configurazione inline:
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 in esecuzione su ${dropstone.server.url}`)
dropstone.server.close()
Memoria (Continuity)
Dropstone mantiene una memoria persistente per account. La chiamiamo Continuity — una memoria cross-surface condivisa da CLI, chat, VS Code e SDK. Insegnale una volta ovunque e ogni superficie la conoscerà già.
Le sessioni che esegui tramite l'SDK usano la stessa memoria dell'account della CLI. Ciò che insegni alla CLI è già noto alle sessioni SDK, e ciò che una sessione SDK registra è disponibile di nuovo nella CLI e nella chat. A ogni turno, l'agente richiama automaticamente la memoria pertinente prima di rispondere, così non deve re-imparare ciò che già sa.
L'agente SDK può anche leggere e scrivere la memoria direttamente, con gli stessi strumenti della CLI:
| Strumento | Scopo |
|---|---|
memory_recall | Richiama le lezioni più pertinenti per l'attività corrente |
record_lesson | Salva una lezione duratura (una regola o un fatto) |
list_lessons | Mostra tutto ciò che ha imparato su di te |
forget_lesson | Rimuovi una lezione |
Note:
La memoria richiede l'accesso a Dropstone. Il server SDK legge lo stesso auth.json della CLI, quindi accedi una volta con dropstone e le sessioni SDK erediteranno la stessa memoria dell'account. Non viene memorizzato nulla se non hai effettuato l'accesso.
Esempio
Dichiara una preferenza dal codice e verrà registrata nello stesso modo in cui avverrebbe nella CLI — visibile in seguito nella CLI e nella chat:
const { client } = await createDropstone()
const session = await client.session.create({ body: { title: "Insegna memoria" } })
await client.session.prompt({
path: { id: session.data.id },
body: {
parts: [{ type: "text", text: "Ricorda questo come regola fissa: usa sempre bun, non npm." }],
},
})
Continuity vs AGENTS.md
AGENTS.md è un file di progetto che committi in Git per le convenzioni del team — stabile, limitato al repository e condiviso con chiunque lo cloni. Continuity è la tua memoria privata dell'account: ciò che insegni nella CLI, nella chat o nell'SDK segue il tuo account attraverso superfici e progetti. Risolvono problemi diversi e funzionano meglio insieme — regole di progetto in AGENTS.md, memoria personale cross-surface in Continuity. Vedi Regole e Memoria.
Cosa viene ricordato
La memoria memorizza solo le regole e i fatti che le insegni esplicitamente — preferenze, convenzioni e correzioni che vale la pena portare tra le sessioni. È distinta dal contesto effimero di una singola sessione, che non viene conservato dopo la fine della sessione.
Vedi la pagina Memoria per come Dropstone decide cosa conservare.
Solo client
Se hai già un'istanza in esecuzione di dropstone, puoi creare un'istanza client per connetterti ad essa:
import { createDropstoneClient } from "@blankline/dropstone-sdk"
const client = createDropstoneClient({
baseUrl: "http://localhost:4096",
})
Opzioni
| Opzione | Tipo | Descrizione | Default |
|---|---|---|---|
baseUrl | string | URL del server | http://localhost:4096 |
fetch | function | Implementazione fetch personalizzata | globalThis.fetch |
parseAs | string | Metodo di parsing della risposta | auto |
responseStyle | string | Stile di ritorno: data o fields | fields |
throwOnError | boolean | Lancia errori invece di restituirli | false |
Tipi
L'SDK include definizioni TypeScript per tutti i tipi API. Importali direttamente:
import type { Session, Message, Part } from "@blankline/dropstone-sdk"
Tutti i tipi sono generati dalla specifica OpenAPI del server, quindi i nomi che vedi in TypeScript corrispondono uno-a-uno alle forme di richiesta e risposta del server.
Errori
L'SDK può lanciare errori che puoi catturare e gestire:
try {
await client.session.get({ path: { id: "invalid-id" } })
} catch (error) {
console.error("Impossibile ottenere la sessione:", (error as Error).message)
}
Output strutturato
Puoi richiedere output JSON strutturato dal modello specificando un format con uno schema JSON. Il modello userà uno strumento StructuredOutput per restituire JSON validato che corrisponde al tuo schema.
Utilizzo di base
const result = await client.session.prompt({
path: { id: sessionId },
body: {
parts: [{ type: "text", text: "Ricerca Dropstone e fornisci informazioni sull'azienda" }],
format: {
type: "json_schema",
schema: {
type: "object",
properties: {
company: { type: "string", description: "Nome dell'azienda" },
founded: { type: "number", description: "Anno di fondazione" },
products: {
type: "array",
items: { type: "string" },
description: "Prodotti principali",
},
},
required: ["company", "founded"],
},
},
},
})
// Accedi all'output strutturato
console.log(result.data.info.structured_output)
// { company: "Dropstone", founded: 2024, products: ["Dropstone CLI"] }
Tipi di formato di output
| Tipo | Descrizione |
|---|---|
text | Default. Risposta testuale standard (nessun output strutturato) |
json_schema | Restituisce JSON validato che corrisponde allo schema fornito |
Formato schema JSON
Quando usi type: 'json_schema', fornisci:
| Campo | Tipo | Descrizione |
|---|---|---|
type | 'json_schema' | Obbligatorio. Specifica la modalità schema JSON |
schema | object | Obbligatorio. Oggetto schema JSON che definisce la struttura dell'output |
retryCount | number | Opzionale. Numero di tentativi di validazione (default: 2) |
Gestione degli errori
Se il modello non riesce a produrre output strutturato valido dopo tutti i tentativi, la risposta includerà un StructuredOutputError:
if (result.data.info.error?.name === "StructuredOutputError") {
console.error("Impossibile produrre output strutturato:", result.data.info.error.message)
console.error("Tentativi:", result.data.info.error.retries)
}
Best practice
- Fornisci descrizioni chiare nelle proprietà dello schema per aiutare il modello a capire quali dati estrarre
- Usa
requiredper specificare quali campi devono essere presenti - Mantieni gli schemi mirati - schemi annidati complessi possono essere più difficili da compilare correttamente per il modello
- Imposta un
retryCountappropriato - aumentalo per schemi complessi, diminuiscilo per quelli semplici
API
L'SDK espone tutte le API del server tramite un client type-safe.
Global
| Metodo | Descrizione | Risposta |
|---|---|---|
global.health() | Controlla salute e versione del server | { healthy: true, version: string } |
Esempi
const health = await client.global.health()
console.log(health.data.version)
App
| Metodo | Descrizione | Risposta |
|---|---|---|
app.log() | Scrivi una voce di log | boolean |
app.agents() | Elenca tutti gli agenti disponibili | Agent[] |
Esempi
// Scrivi una voce di log
await client.app.log({
body: {
service: "my-app",
level: "info",
message: "Operazione completata",
},
})
// Elenca gli agenti disponibili
const agents = await client.app.agents()
Project
| Metodo | Descrizione | Risposta |
|---|---|---|
project.list() | Elenca tutti i progetti | Project[] |
project.current() | Ottieni il progetto corrente | Project |
Esempi
// Elenca tutti i progetti
const projects = await client.project.list()
// Ottieni il progetto corrente
const currentProject = await client.project.current()
Path
| Metodo | Descrizione | Risposta |
|---|---|---|
path.get() | Ottieni il percorso corrente | Path |
Esempi
// Ottieni informazioni sul percorso corrente
const pathInfo = await client.path.get()
Config
| Metodo | Descrizione | Risposta |
|---|---|---|
config.get() | Ottieni info di configurazione | Config |
Esempi
const config = await client.config.get()
Sessions
| Metodo | Descrizione | Note |
|---|---|---|
session.list() | Elenca le sessioni | Restituisce Session[] |
session.get({ path }) | Ottieni sessione | Restituisce Session |
session.children({ path }) | Elenca le sessioni figlie | Restituisce Session[] |
session.create({ body }) | Crea sessione | Restituisce Session |
session.delete({ path }) | Elimina sessione | Restituisce boolean |
session.update({ path, body }) | Aggiorna proprietà della sessione | Restituisce Session |
session.init({ path, body }) | Analizza l'app e crea AGENTS.md | Restituisce boolean |
session.abort({ path }) | Interrompi una sessione in esecuzione | Restituisce boolean |
session.summarize({ path, body }) | Riepiloga la sessione | Restituisce boolean |
session.messages({ path }) | Elenca i messaggi in una sessione | Restituisce { info: Message, parts: Part[]}[] |
session.message({ path }) | Ottieni dettagli del messaggio | Restituisce { info: Message, parts: Part[]} |
session.prompt({ path, body }) | Invia messaggio di prompt | body.noReply: true restituisce UserMessage (solo contesto). Il default restituisce AssistantMessage con risposta AI. Supporta body.outputFormat per output strutturato |
session.command({ path, body }) | Invia comando alla sessione | Restituisce { info: AssistantMessage, parts: Part[]} |
session.shell({ path, body }) | Esegui un comando shell | Restituisce AssistantMessage |
session.revert({ path, body }) | Annulla un messaggio | Restituisce Session |
session.unrevert({ path }) | Ripristina messaggi annullati | Restituisce Session |
postSessionByIdPermissionsByPermissionId({ path, body }) | Rispondi a una richiesta di permesso | Restituisce boolean |
Esempi
// Crea e gestisci sessioni
const session = await client.session.create({
body: { title: "La mia sessione" },
})
const sessions = await client.session.list()
// Invia un messaggio di prompt
const result = await client.session.prompt({
path: { id: session.data.id },
body: {
model: { providerID: "dropstone", modelID: "dropstone-pro" },
parts: [{ type: "text", text: "Ciao!" }],
},
})
// Inietta contesto senza attivare la risposta AI (utile per i plugin)
await client.session.prompt({
path: { id: session.data.id },
body: {
noReply: true,
parts: [{ type: "text", text: "Sei un assistente utile." }],
},
})
Files
| Metodo | Descrizione | Risposta |
|---|---|---|
find.text({ query }) | Cerca testo nei file | Array di oggetti di corrispondenza con path, lines, line_number, absolute_offset, submatches |
find.files({ query }) | Trova file e directory per nome | string[] (percorsi) |
find.symbols({ query }) | Trova simboli del workspace | Symbol[] |
file.read({ query }) | Leggi un file | { type: "raw" | "patch", content: string } |
file.status({ query? }) | Ottieni stato per file tracciati | File[] |
find.files supporta alcuni campi di query opzionali:
type:"file"o"directory"directory: sovrascrivi la radice del progetto per la ricercalimit: massimo risultati (1–200)
Esempi
// Cerca e leggi file
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" },
})
Auth
| Metodo | Descrizione | Risposta |
|---|---|---|
auth.set({ ... }) | Imposta le credenziali di autenticazione | boolean |
Esempi
await client.auth.set({
path: { id: "dropstone" },
body: { type: "api", key: "la-tua-chiave-api-dropstone" },
})
Events
| Metodo | Descrizione | Risposta |
|---|---|---|
event.subscribe() | Stream di eventi server-sent | Stream di eventi server-sent |
Esempi
// Ascolta eventi in tempo reale
const events = await client.event.subscribe()
for await (const event of events.stream) {
console.log("Evento:", event.type, event.properties)
}
API v2
L'SDK include una superficie v1 stabile (usata negli esempi precedenti) e una superficie v2 che rispecchia il contratto più recente Effect HttpApi. Preferisci v2 per le nuove integrazioni:
import { createDropstone } from "@blankline/dropstone-sdk/v2"
const { client, server } = await createDropstone()
// v2 espone una gerarchia di risorse più ricca: workspace, worktree, file, find, ecc.
const files = await client.file.list({ path: "src" })
La superficie v1 è mantenuta per compatibilità all'indietro. I nuovi endpoint arrivano solo su v2.