SDK do Dropstone
Cliente JS com tipagem segura para o runtime do agente Dropstone. As sessões do SDK herdam a memória entre superfícies do Dropstone (Continuity) — uma memória persistente compartilhada com a CLI, o chat e o SDK.
O SDK JS/TS do Dropstone fornece um cliente com tipagem segura para interagir com o runtime do agente Dropstone. Ele inicia o dropstone serve como um subprocesso e fornece um cliente HTTP tipado apontando para ele. Como ele executa o mesmo agente local que a CLI usa, cada sessão do SDK herda a memória da sua conta — ensine uma vez na CLI, no chat ou no SDK e todas as superfícies já saberão (veja Memória (Continuity)).
Precisa de acesso headless à API em CI?:
Para uso puramente programático (pipelines de CI, automação, serverless), prefira a API HTTP com uma DROPSTONE_API_KEY. O SDK desta página é destinado a incorporar o agente interativo em um processo Node onde o binário da CLI está instalado junto.
Veja a página do Servidor para entender como a API HTTP subjacente funciona.
Instalação
Instale o SDK a partir do npm:
npm install @blankline/dropstone-sdk
Cliente headless de API
Para pipelines de CI, automação e serverless, você não precisa da CLI. Use o cliente headless, que fala diretamente com a API HTTP do Dropstone usando uma chave de API:
import { createDropstoneApi } from "@blankline/dropstone-sdk"
// Lê DROPSTONE_API_KEY do ambiente automaticamente.
const dropstone = createDropstoneApi()
const resp = await dropstone.chat.completions.create({
model: "dropstone-fast", // ou "dropstone-pro" / "dropstone-heavy"
messages: [{ role: "user", content: "Escreva um haicai sobre depuração." }],
})
console.log(resp.choices[0].message.content)
console.log("Custo: $" + resp.usage?.cost) // valor cobrado, em USD
Obter uma chave de API
- Entre em dropstone.io/dashboard.
- Abra Configurações → API em dropstone.io/dashboard/settings e crie uma chave — ela se parece com
dsk_live_<43 caracteres>. - Defina-a como uma variável de ambiente (ou passe
apiKeyparacreateDropstoneApi):
export DROPSTONE_API_KEY=dsk_live_...
Note:
Trate sua chave de API como uma senha. Nunca a envie para o git nem a incorpore em um bundle de frontend. As solicitações com chave de API são cobradas conforme o uso a partir do seu saldo de crédito pré-pago — as franquias do plano não se aplicam. Veja Uso e limites.
O streaming funciona da mesma forma, e o cliente é compatível com OpenAI — você pode apontar o SDK da OpenAI para a URL base do Dropstone:
const stream = await dropstone.chat.completions.create({
model: "dropstone-fast",
stream: true,
messages: [{ role: "user", content: "Conte até 5." }],
})
for await (const chunk of stream) {
process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "")
}
Veja a página da API HTTP para a referência completa.
Criar cliente
Crie uma instância do dropstone:
import { createDropstone } from "@blankline/dropstone-sdk"
const { client } = await createDropstone()
Isso inicia tanto um servidor quanto um cliente. Cada método do SDK retorna { data, request, response }, então acesse o payload via .data.
Opções
| Opção | Tipo | Descrição | Padrão |
|---|---|---|---|
hostname | string | Hostname do servidor | 127.0.0.1 |
port | number | Porta do servidor | 4096 |
signal | AbortSignal | Sinal de abortamento para cancelamento | undefined |
timeout | number | Tempo limite em ms para iniciar o servidor | 5000 |
config | Config | Objeto de configuração | {} |
Configuração
Você pode passar um objeto de configuração para personalizar o comportamento. A instância ainda capta o seu dropstone.json, mas você pode substituir ou adicionar configuração 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(`Servidor rodando em ${dropstone.server.url}`)
dropstone.server.close()
Memória (Continuity)
O Dropstone mantém uma memória persistente por conta. Chamamos isso de Continuity — uma memória entre superfícies compartilhada pela CLI, chat, VS Code e SDK. Ensine uma vez em qualquer lugar e todas as superfícies já saberão.
As sessões que você executa pelo SDK usam a mesma memória de conta da CLI. O que você ensina à CLI já é conhecido pelas sessões do SDK, e o que uma sessão do SDK registra fica disponível de volta na CLI e no chat. A cada turno, o agente recupera automaticamente a memória relevante antes de responder, para não reaprender o que já sabe.
O agente do SDK também pode ler e escrever memória diretamente, com as mesmas ferramentas da CLI:
| Ferramenta | Finalidade |
|---|---|
memory_recall | Recuperar as lições mais relevantes para a tarefa atual |
record_lesson | Salvar uma lição durável (uma regra ou um fato) |
list_lessons | Mostrar tudo o que ele aprendeu sobre você |
forget_lesson | Remover uma lição |
Note:
A memória exige que você esteja conectado ao Dropstone. O servidor do SDK lê o mesmo auth.json que a CLI, então entre uma vez com dropstone e as sessões do SDK herdarão a mesma memória de conta. Nada é armazenado se você não estiver conectado.
Exemplo
Declare uma preferência a partir do código e ela será registrada da mesma forma que seria na CLI — visível na CLI e no chat depois:
const { client } = await createDropstone()
const session = await client.session.create({ body: { title: "Ensinar memória" } })
await client.session.prompt({
path: { id: session.data.id },
body: {
parts: [{ type: "text", text: "Lembre-se disso como uma regra permanente: use sempre bun, não npm." }],
},
})
Continuity vs AGENTS.md
O AGENTS.md é um arquivo de projeto que você envia para o Git para convenções de equipe — estável, com escopo no repositório e compartilhado com qualquer pessoa que o clone. Continuity é a sua memória privada de conta: o que você ensina na CLI, no chat ou no SDK acompanha sua conta entre superfícies e projetos. Eles resolvem problemas diferentes e funcionam melhor juntos — regras de projeto no AGENTS.md, memória pessoal entre superfícies no Continuity. Veja Regras e Memória.
O que é lembrado
A memória armazena apenas as regras e os fatos que você ensina explicitamente — preferências, convenções e correções que valem a pena carregar entre sessões. Ela é distinta do contexto efêmero de uma única sessão, que não é mantido após o término da sessão.
Veja a página Memória para saber como o Dropstone decide o que manter.
Somente cliente
Se você já tem uma instância do dropstone em execução, pode criar uma instância de cliente para se conectar a ela:
import { createDropstoneClient } from "@blankline/dropstone-sdk"
const client = createDropstoneClient({
baseUrl: "http://localhost:4096",
})
Opções
| Opção | Tipo | Descrição | Padrão |
|---|---|---|---|
baseUrl | string | URL do servidor | http://localhost:4096 |
fetch | function | Implementação de fetch personalizada | globalThis.fetch |
parseAs | string | Método de análise da resposta | auto |
responseStyle | string | Estilo de retorno: data ou fields | fields |
throwOnError | boolean | Lançar erros em vez de retornar | false |
Tipos
O SDK inclui definições TypeScript para todos os tipos de API. Importe-os diretamente:
import type { Session, Message, Part } from "@blankline/dropstone-sdk"
Todos os tipos são gerados a partir da especificação OpenAPI do servidor, então os nomes que você vê no TypeScript correspondem um a um às formas de solicitação e resposta do servidor.
Erros
O SDK pode lançar erros que você pode capturar e tratar:
try {
await client.session.get({ path: { id: "invalid-id" } })
} catch (error) {
console.error("Falha ao obter a sessão:", (error as Error).message)
}
Saída estruturada
Você pode solicitar saída JSON estruturada do modelo especificando um format com um schema JSON. O modelo usará uma ferramenta StructuredOutput para retornar JSON validado que corresponde ao seu schema.
Uso básico
const result = await client.session.prompt({
path: { id: sessionId },
body: {
parts: [{ type: "text", text: "Pesquise o Dropstone e forneça informações da empresa" }],
format: {
type: "json_schema",
schema: {
type: "object",
properties: {
company: { type: "string", description: "Nome da empresa" },
founded: { type: "number", description: "Ano de fundação" },
products: {
type: "array",
items: { type: "string" },
description: "Principais produtos",
},
},
required: ["company", "founded"],
},
},
},
})
// Acesse a saída estruturada
console.log(result.data.info.structured_output)
// { company: "Dropstone", founded: 2024, products: ["Dropstone CLI"] }
Tipos de formato de saída
| Tipo | Descrição |
|---|---|
text | Padrão. Resposta de texto padrão (sem saída estruturada) |
json_schema | Retorna JSON validado correspondente ao schema fornecido |
Formato do schema JSON
Ao usar type: 'json_schema', forneça:
| Campo | Tipo | Descrição |
|---|---|---|
type | 'json_schema' | Obrigatório. Especifica o modo de schema JSON |
schema | object | Obrigatório. Objeto de schema JSON que define a estrutura de saída |
retryCount | number | Opcional. Número de tentativas de validação (padrão: 2) |
Tratamento de erros
Se o modelo falhar ao produzir saída estruturada válida após todas as tentativas, a resposta incluirá um StructuredOutputError:
if (result.data.info.error?.name === "StructuredOutputError") {
console.error("Falha ao produzir saída estruturada:", result.data.info.error.message)
console.error("Tentativas:", result.data.info.error.retries)
}
Melhores práticas
- Forneça descrições claras nas propriedades do seu schema para ajudar o modelo a entender quais dados extrair
- Use
requiredpara especificar quais campos devem estar presentes - Mantenha os schemas focados — schemas aninhados complexos podem ser mais difíceis para o modelo preencher corretamente
- Defina um
retryCountadequado — aumente para schemas complexos, diminua para os simples
APIs
O SDK expõe todas as APIs do servidor por meio de um cliente com tipagem segura.
Global
| Método | Descrição | Resposta |
|---|---|---|
global.health() | Verificar saúde e versão do servidor | { healthy: true, version: string } |
Exemplos
const health = await client.global.health()
console.log(health.data.version)
App
| Método | Descrição | Resposta |
|---|---|---|
app.log() | Escrever uma entrada de log | boolean |
app.agents() | Listar todos os agentes disponíveis | Agent[] |
Exemplos
// Escrever uma entrada de log
await client.app.log({
body: {
service: "my-app",
level: "info",
message: "Operação concluída",
},
})
// Listar agentes disponíveis
const agents = await client.app.agents()
Projeto
| Método | Descrição | Resposta |
|---|---|---|
project.list() | Listar todos os projetos | Project[] |
project.current() | Obter o projeto atual | Project |
Exemplos
// Listar todos os projetos
const projects = await client.project.list()
// Obter o projeto atual
const currentProject = await client.project.current()
Caminho
| Método | Descrição | Resposta |
|---|---|---|
path.get() | Obter o caminho atual | Path |
Exemplos
// Obter informações do caminho atual
const pathInfo = await client.path.get()
Configuração
| Método | Descrição | Resposta |
|---|---|---|
config.get() | Obter informações de configuração | Config |
Exemplos
const config = await client.config.get()
Sessões
| Método | Descrição | Notas |
|---|---|---|
session.list() | Listar sessões | Retorna Session[] |
session.get({ path }) | Obter sessão | Retorna Session |
session.children({ path }) | Listar sessões filhas | Retorna Session[] |
session.create({ body }) | Criar sessão | Retorna Session |
session.delete({ path }) | Excluir sessão | Retorna boolean |
session.update({ path, body }) | Atualizar propriedades da sessão | Retorna Session |
session.init({ path, body }) | Analisar o app e criar AGENTS.md | Retorna boolean |
session.abort({ path }) | Abortar uma sessão em execução | Retorna boolean |
session.summarize({ path, body }) | Resumir sessão | Retorna boolean |
session.messages({ path }) | Listar mensagens em uma sessão | Retorna { info: Message, parts: Part[]}[] |
session.message({ path }) | Obter detalhes da mensagem | Retorna { info: Message, parts: Part[]} |
session.prompt({ path, body }) | Enviar mensagem de prompt | body.noReply: true retorna UserMessage (somente contexto). O padrão retorna AssistantMessage com resposta da IA. Suporta body.outputFormat para saída estruturada |
session.command({ path, body }) | Enviar comando para a sessão | Retorna { info: AssistantMessage, parts: Part[]} |
session.shell({ path, body }) | Executar um comando de shell | Retorna AssistantMessage |
session.revert({ path, body }) | Reverter uma mensagem | Retorna Session |
session.unrevert({ path }) | Restaurar mensagens revertidas | Retorna Session |
postSessionByIdPermissionsByPermissionId({ path, body }) | Responder a uma solicitação de permissão | Retorna boolean |
Exemplos
// Criar e gerenciar sessões
const session = await client.session.create({
body: { title: "Minha sessão" },
})
const sessions = await client.session.list()
// Enviar uma mensagem de prompt
const result = await client.session.prompt({
path: { id: session.data.id },
body: {
model: { providerID: "dropstone", modelID: "dropstone-pro" },
parts: [{ type: "text", text: "Olá!" }],
},
})
// Injetar contexto sem acionar resposta da IA (útil para plugins)
await client.session.prompt({
path: { id: session.data.id },
body: {
noReply: true,
parts: [{ type: "text", text: "Você é um assistente útil." }],
},
})
Arquivos
| Método | Descrição | Resposta |
|---|---|---|
find.text({ query }) | Buscar texto em arquivos | Matriz de objetos de correspondência com path, lines, line_number, absolute_offset, submatches |
find.files({ query }) | Encontrar arquivos e diretórios por nome | string[] (caminhos) |
find.symbols({ query }) | Encontrar símbolos do workspace | Symbol[] |
file.read({ query }) | Ler um arquivo | { type: "raw" | "patch", content: string } |
file.status({ query? }) | Obter status de arquivos rastreados | File[] |
find.files suporta alguns campos de consulta opcionais:
type:"file"ou"directory"directory: substituir a raiz do projeto para a buscalimit: máximo de resultados (1–200)
Exemplos
// Buscar e ler arquivos
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" },
})
Autenticação
| Método | Descrição | Resposta |
|---|---|---|
auth.set({ ... }) | Definir credenciais de autenticação | boolean |
Exemplos
await client.auth.set({
path: { id: "dropstone" },
body: { type: "api", key: "sua-chave-de-api-do-dropstone" },
})
Eventos
| Método | Descrição | Resposta |
|---|---|---|
event.subscribe() | Fluxo de eventos enviados pelo servidor | Fluxo de eventos enviados pelo servidor |
Exemplos
// Ouvir eventos em tempo real
const events = await client.event.subscribe()
for await (const event of events.stream) {
console.log("Evento:", event.type, event.properties)
}
API v2
O SDK inclui uma superfície v1 estável (usada nos exemplos acima) e uma superfície v2 que espelha o contrato mais recente do Effect HttpApi. Prefira v2 para novas integrações:
import { createDropstone } from "@blankline/dropstone-sdk/v2"
const { client, server } = await createDropstone()
// v2 expõe uma hierarquia de recursos mais rica: workspace, worktree, file, find, etc.
const files = await client.file.list({ path: "src" })
A superfície v1 é mantida para compatibilidade com versões anteriores. Novos endpoints só são adicionados na v2.