Dropstone Docs

Dropstone SDK

Типобезопасный JS-клиент для агентной среды выполнения Dropstone. Сессии SDK наследуют кросс-поверхностную память Dropstone (Continuity) — одну постоянную память, общую с CLI, чатом и SDK.

SDK Dropstone для JS/TS предоставляет типобезопасный клиент для взаимодействия с агентной средой выполнения Dropstone. Он запускает dropstone serve как подпроцесс и предоставляет типизированный HTTP-клиент, указывающий на него. Поскольку он использует того же локального агента, что и CLI, каждая сессия SDK наследует память вашей учетной записи — обучите его один раз в CLI, чате или SDK, и каждая поверхность уже будет это знать (см. Память (Continuity)).

Нужен headless-доступ к API в CI?:

Для чисто программного использования (CI-пайплайны, автоматизация, serverless) предпочтительнее использовать HTTP API с DROPSTONE_API_KEY. SDK на этой странице предназначен для встраивания интерактивного агента в процесс Node, где рядом установлен бинарный файл CLI.

См. страницу Сервер для получения информации о том, как работает базовый HTTP API.


Установка

Установите SDK из npm:

npm install @blankline/dropstone-sdk

Headless-клиент API

Для CI-пайплайнов, автоматизации и serverless CLI вообще не нужен. Используйте headless-клиент, который напрямую общается с HTTP API Dropstone с помощью API-ключа:

import { createDropstoneApi } from "@blankline/dropstone-sdk"

// Автоматически считывает DROPSTONE_API_KEY из окружения.
const dropstone = createDropstoneApi()

const resp = await dropstone.chat.completions.create({
  model: "dropstone-fast", // или "dropstone-pro" / "dropstone-heavy"
  messages: [{ role: "user", content: "Напиши хайку об отладке." }],
})

console.log(resp.choices[0].message.content)
console.log("Стоимость: $" + resp.usage?.cost) // списанная сумма, в долларах США

Получение API-ключа

  1. Войдите на dropstone.io/dashboard.
  2. Откройте Настройки → API на dropstone.io/dashboard/settings и создайте ключ — он выглядит как dsk_live_<43 символа>.
  3. Установите его как переменную окружения (или передайте apiKey в createDropstoneApi):
export DROPSTONE_API_KEY=dsk_live_...

Note:

Относитесь к своему API-ключу как к паролю. Никогда не коммитьте его в git и не встраивайте во фронтенд-бандл. Запросы с API-ключом тарифицируются по мере использования с вашего предоплаченного баланса — лимиты тарифных планов не применяются. См. Использование и лимиты.

Стриминг работает так же, и клиент совместим с OpenAI — вы можете указать базовый URL Dropstone в OpenAI SDK:

const stream = await dropstone.chat.completions.create({
  model: "dropstone-fast",
  stream: true,
  messages: [{ role: "user", content: "Посчитай до 5." }],
})

for await (const chunk of stream) {
  process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "")
}

Полную справочную информацию см. на странице HTTP API.


Создание клиента

Создайте экземпляр dropstone:

import { createDropstone } from "@blankline/dropstone-sdk"

const { client } = await createDropstone()

Это запускает и сервер, и клиент. Каждый метод SDK возвращает { data, request, response }, поэтому доступ к полезной нагрузке осуществляется через .data.

По умолчанию сервер входит в систему как тот, кто выполнял dropstone auth login на этой машине. На необслуживаемом хосте такой учетной записи нет, поэтому передайте API-ключ и явный список разрешений через 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" },
  },
})

Обе части обязательны. API-ключи отклоняются на /v1, а агент build по умолчанию спрашивает разрешение перед каждым вызовом инструмента, поэтому без списка разрешений запуск будет ждать одобрения, которое никто не может дать, и зависнет, а не завершится ошибкой. Отправка "agent": "accept all" в промпте — альтернатива списку разрешений. См. Сервер и Разрешения.

Параметры

ПараметрТипОписаниеПо умолчанию
hostnamestringИмя хоста сервера127.0.0.1
portnumberПорт сервера4096
signalAbortSignalСигнал отмены для прерыванияundefined
timeoutnumberТаймаут в мс для запуска сервера5000
configConfigОбъект конфигурации{}

Конфигурация

Вы можете передать объект конфигурации для настройки поведения. Экземпляр по-прежнему подхватывает ваш dropstone.json, но вы можете переопределить или дополнить конфигурацию встроенно:

import { createDropstone } from "@blankline/dropstone-sdk"

const dropstone = await createDropstone({
  hostname: "127.0.0.1",
  port: 4096,
  config: {
    model: "dropstone/dropstone-pro",
  },
})

console.log(`Сервер запущен на ${dropstone.server.url}`)

dropstone.server.close()

Память (Continuity)

Dropstone хранит одну постоянную память на учетную запись. Мы называем это Continuity — кросс-поверхностная память, общая для CLI, чата, VS Code и SDK. Обучите его один раз где угодно, и каждая поверхность уже будет это знать.

Сессии, которые вы запускаете через SDK, используют ту же память учетной записи, что и CLI. То, чему вы научили CLI, уже известно сессиям SDK, а то, что записала сессия SDK, доступно обратно в CLI и чате. На каждом ходу агент автоматически вспоминает релевантную память перед ответом, поэтому ему не нужно заново учить то, что он уже знает.

Агент SDK также может напрямую читать и записывать память, используя те же инструменты, что и CLI:

ИнструментНазначение
memory_recallВспомнить наиболее релевантные уроки для текущей задачи
record_lessonСохранить долговременный урок (правило или факт)
list_lessonsПоказать все, что он узнал о вас
forget_lessonУдалить урок

Note:

Память требует входа в Dropstone. Сервер SDK читает тот же auth.json, что и CLI, поэтому войдите один раз с помощью dropstone, и сессии SDK унаследуют ту же память учетной записи. Если вы не вошли, ничего не сохраняется.

Пример

Укажите предпочтение из кода, и оно будет записано так же, как в CLI — видимо в CLI и чате впоследствии:

const { client } = await createDropstone()

const session = await client.session.create({ body: { title: "Обучить память" } })

await client.session.prompt({
  path: { id: session.data.id },
  body: {
    parts: [{ type: "text", text: "Запомни это как постоянное правило: всегда используй bun, а не npm." }],
  },
})

Continuity против AGENTS.md

AGENTS.md — это проектный файл, который вы коммитите в Git для командных соглашений — стабильный, ограниченный репозиторием и доступный всем, кто его клонирует. Continuity — это ваша личная память учетной записи: то, чему вы учите в CLI, чате или SDK, следует за вашей учетной записью по поверхностям и проектам. Они решают разные задачи и лучше всего работают вместе — правила проекта в AGENTS.md, личная кросс-поверхностная память в Continuity. См. Правила и Память.

Что запоминается

Память хранит только те правила и факты, которым вы явно ее обучаете — предпочтения, соглашения и исправления, которые стоит переносить между сессиями. Она отличается от эфемерного контекста отдельной сессии, который не сохраняется после ее завершения.

См. страницу Память для получения информации о том, как Dropstone решает, что сохранять.


Только клиент

Если у вас уже есть запущенный экземпляр dropstone, вы можете создать клиентский экземпляр для подключения к нему:

import { createDropstoneClient } from "@blankline/dropstone-sdk"

const client = createDropstoneClient({
  baseUrl: "http://localhost:4096",
})

Параметры

ПараметрТипОписаниеПо умолчанию
baseUrlstringURL сервераhttp://localhost:4096
fetchfunctionПользовательская реализация fetchglobalThis.fetch
parseAsstringМетод разбора ответаauto
responseStylestringСтиль возврата: data или fieldsfields
throwOnErrorbooleanВыбрасывать ошибки вместо возвратаfalse

Типы

SDK включает определения TypeScript для всех типов API. Импортируйте их напрямую:

import type { Session, Message, Part } from "@blankline/dropstone-sdk"

Все типы генерируются из спецификации OpenAPI сервера, поэтому имена, которые вы видите в TypeScript, сопоставляются один к одному с формами запросов и ответов сервера.


Ошибки

SDK может выбрасывать ошибки, которые вы можете перехватывать и обрабатывать:

try {
  await client.session.get({ path: { id: "invalid-id" } })
} catch (error) {
  console.error("Не удалось получить сессию:", (error as Error).message)
}

Структурированный вывод

Вы можете запросить структурированный JSON-вывод от модели, указав format с JSON-схемой. Модель будет использовать инструмент StructuredOutput для возврата проверенного JSON, соответствующего вашей схеме.

Базовое использование

const result = await client.session.prompt({
  path: { id: sessionId },
  body: {
    parts: [{ type: "text", text: "Исследуй Dropstone и предоставь информацию о компании" }],
    format: {
      type: "json_schema",
      schema: {
        type: "object",
        properties: {
          company: { type: "string", description: "Название компании" },
          founded: { type: "number", description: "Год основания" },
          products: {
            type: "array",
            items: { type: "string" },
            description: "Основные продукты",
          },
        },
        required: ["company", "founded"],
      },
    },
  },
})

// Доступ к структурированному выводу
console.log(result.data.info.structured_output)
// { company: "Dropstone", founded: 2024, products: ["Dropstone CLI"] }

Типы форматов вывода

ТипОписание
textПо умолчанию. Стандартный текстовый ответ (без структурированного вывода)
json_schemaВозвращает проверенный JSON, соответствующий предоставленной схеме

Формат JSON-схемы

При использовании type: 'json_schema' укажите:

ПолеТипОписание
type'json_schema'Обязательно. Указывает режим JSON-схемы
schemaobjectОбязательно. Объект JSON-схемы, определяющий структуру вывода
retryCountnumberНеобязательно. Количество попыток проверки (по умолчанию: 2)

Обработка ошибок

Если модели не удается создать корректный структурированный вывод после всех попыток, ответ будет содержать StructuredOutputError:

if (result.data.info.error?.name === "StructuredOutputError") {
  console.error("Не удалось создать структурированный вывод:", result.data.info.error.message)
  console.error("Попытки:", result.data.info.error.retries)
}

Рекомендации

  1. Предоставляйте четкие описания в свойствах схемы, чтобы помочь модели понять, какие данные извлекать
  2. Используйте required, чтобы указать, какие поля должны присутствовать
  3. Держите схемы сфокусированными — сложные вложенные схемы могут быть труднее для корректного заполнения моделью
  4. Устанавливайте подходящий retryCount — увеличьте для сложных схем, уменьшите для простых

API

SDK предоставляет все серверные API через типобезопасный клиент.


Global

МетодОписаниеОтвет
global.health()Проверить здоровье сервера и версию{ healthy: true, version: string }

Примеры

const health = await client.global.health()
console.log(health.data.version)

App

МетодОписаниеОтвет
app.log()Записать запись в журналboolean
app.agents()Список всех доступных агентовAgent[]

Примеры

// Записать запись в журнал
await client.app.log({
  body: {
    service: "my-app",
    level: "info",
    message: "Операция завершена",
  },
})

// Список доступных агентов
const agents = await client.app.agents()

Project

МетодОписаниеОтвет
project.list()Список всех проектовProject[]
project.current()Получить текущий проектProject

Примеры

// Список всех проектов
const projects = await client.project.list()

// Получить текущий проект
const currentProject = await client.project.current()

Path

МетодОписаниеОтвет
path.get()Получить текущий путьPath

Примеры

// Получить информацию о текущем пути
const pathInfo = await client.path.get()

Config

МетодОписаниеОтвет
config.get()Получить информацию о конфигурацииConfig

Примеры

const config = await client.config.get()

Sessions

МетодОписаниеПримечания
session.list()Список сессийВозвращает Session[]
session.get({ path })Получить сессиюВозвращает Session
session.children({ path })Список дочерних сессийВозвращает Session[]
session.create({ body })Создать сессиюВозвращает Session
session.delete({ path })Удалить сессиюВозвращает boolean
session.update({ path, body })Обновить свойства сессииВозвращает Session
session.init({ path, body })Проанализировать приложение и создать AGENTS.mdВозвращает boolean
session.abort({ path })Прервать запущенную сессиюВозвращает boolean
session.summarize({ path, body })Суммировать сессиюВозвращает boolean
session.messages({ path })Список сообщений в сессииВозвращает { info: Message, parts: Part[]}[]
session.message({ path })Получить детали сообщенияВозвращает { info: Message, parts: Part[]}
session.prompt({ path, body })Отправить промпт-сообщениеbody.noReply: true возвращает UserMessage (только контекст). По умолчанию возвращает AssistantMessage с ответом ИИ. Поддерживает body.outputFormat для структурированного вывода
session.command({ path, body })Отправить команду в сессиюВозвращает { info: AssistantMessage, parts: Part[]}
session.shell({ path, body })Выполнить команду оболочкиВозвращает AssistantMessage
session.revert({ path, body })Откатить сообщениеВозвращает Session
session.unrevert({ path })Восстановить откаченные сообщенияВозвращает Session
postSessionByIdPermissionsByPermissionId({ path, body })Ответить на запрос разрешенияВозвращает boolean

Примеры

// Создание и управление сессиями
const session = await client.session.create({
  body: { title: "Моя сессия" },
})

const sessions = await client.session.list()

// Отправка промпт-сообщения
const result = await client.session.prompt({
  path: { id: session.data.id },
  body: {
    model: { providerID: "dropstone", modelID: "dropstone-pro" },
    parts: [{ type: "text", text: "Привет!" }],
  },
})

// Внедрение контекста без запуска ответа ИИ (полезно для плагинов)
await client.session.prompt({
  path: { id: session.data.id },
  body: {
    noReply: true,
    parts: [{ type: "text", text: "Ты полезный ассистент." }],
  },
})

Files

МетодОписаниеОтвет
find.text({ query })Поиск текста в файлахМассив объектов совпадений с path, lines, line_number, absolute_offset, submatches
find.files({ query })Поиск файлов и каталогов по имениstring[] (пути)
find.symbols({ query })Поиск символов рабочей областиSymbol[]
file.read({ query })Чтение файла{ type: "raw" | "patch", content: string }
file.status({ query? })Получить статус отслеживаемых файловFile[]

find.files поддерживает несколько необязательных полей запроса:

  • type: "file" или "directory"
  • directory: переопределить корень проекта для поиска
  • limit: максимальное количество результатов (1–200)

Примеры

// Поиск и чтение файлов
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

МетодОписаниеОтвет
auth.set({ ... })Установить учетные данныеboolean

Примеры

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

Events

МетодОписаниеОтвет
event.subscribe()Поток событий, отправляемых серверомПоток событий, отправляемых сервером

Примеры

// Прослушивание событий в реальном времени
const events = await client.event.subscribe()
for await (const event of events.stream) {
  console.log("Событие:", event.type, event.properties)
}

v2 API

SDK поставляется со стабильной поверхностью v1 (используется в примерах выше) и поверхностью v2, которая отражает более новый контракт Effect HttpApi. Для новых интеграций предпочтительнее v2:

import { createDropstone } from "@blankline/dropstone-sdk/v2"

const { client, server } = await createDropstone()
// v2 предоставляет более богатую иерархию ресурсов: workspace, worktree, file, find и т.д.
const files = await client.file.list({ path: "src" })

Поверхность v1 сохраняется для обратной совместимости. Новые конечные точки появляются только в v2.

Ctrl+I