Dropstone CLI

Dropstone SDK

適用於 Dropstone 代理執行環境的型別安全 JS 用戶端。SDK 工作階段繼承 Dropstone 的跨介面記憶體(Continuity)——與 CLI、聊天和 SDK 共享的單一持久記憶體。

Dropstone JS/TS SDK 提供一個型別安全的用戶端,用於與 Dropstone 代理執行環境互動。它會將 dropstone serve 啟動為子程序,並提供一個指向它的型別化 HTTP 用戶端。由於它執行的是與 CLI 相同的本機代理,每個 SDK 工作階段都會繼承您的帳戶記憶體——在 CLI、聊天或 SDK 中教一次,每個介面就都知道了(請參閱 記憶體(Continuity))。

需要在 CI 中使用無頭 API 存取?

對於純程式化用途(CI 管線、自動化、無伺服器),請優先使用搭配 DROPSTONE_API_KEYHTTP API。此頁面上的 SDK 適用於在已安裝 CLI 二進位檔的 Node 程序中嵌入互動式代理。

請參閱 伺服器 頁面以了解底層 HTTP API 的運作方式。


安裝

從 npm 安裝 SDK:

npm install @blankline/dropstone-sdk

無頭 API 用戶端

對於 CI 管線、自動化和無伺服器環境,您完全不需要 CLI。請使用無頭用戶端,它會直接使用 API 金鑰與 Dropstone HTTP 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. dropstone.io/dashboard/settings 開啟 設定 → API 並建立金鑰——格式類似 dsk_live_<43 個字元>
  3. 將其設定為環境變數(或將 apiKey 傳遞給 createDropstoneApi):
export DROPSTONE_API_KEY=dsk_live_...

Note

請將您的 API 金鑰視為密碼。切勿將其提交到 Git 或嵌入前端套件中。API 金鑰請求會從您的預付餘額中按使用量計費——方案額度不適用。請參閱 用量與限制

串流運作方式相同,且用戶端與 OpenAI 相容——您可以將 OpenAI SDK 指向 Dropstone 的基礎 URL 來取代:

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 的使用者身分登入。在無人值守的主機上沒有此類帳戶,因此請透過 config 傳遞 API 金鑰和明確的權限允許清單:

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 伺服器讀取與 CLI 相同的 auth.json,因此只要用 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",
})

選項

選項類型描述預設值
baseUrlstring伺服器的 URLhttp://localhost:4096
fetchfunction自訂 fetch 實作globalThis.fetch
parseAsstring回應解析方法auto
responseStylestring回傳樣式:datafieldsfields
throwOnErrorboolean擲回錯誤而非回傳false

型別

SDK 包含所有 API 型別的 TypeScript 定義。直接匯入:

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 schema 的 format 來要求模型輸出結構化的 JSON。模型會使用 StructuredOutput 工具回傳符合您 schema 的驗證 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回傳符合提供 schema 的驗證 JSON

JSON Schema 格式

使用 type: 'json_schema' 時,請提供:

欄位類型描述
type'json_schema'必填。指定 JSON schema 模式
schemaobject必填。定義輸出結構的 JSON Schema 物件
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. 在 schema 屬性中提供清晰的描述,以協助模型了解要擷取什麼資料
  2. 使用 required 指定哪些欄位必須存在
  3. 保持 schema 聚焦 - 複雜的巢狀 schema 可能讓模型更難正確填寫
  4. 設定適當的 retryCount - 複雜 schema 增加,簡單 schema 減少

API

SDK 透過型別安全的用戶端公開所有伺服器 API。


全域

方法描述回應
global.health()檢查伺服器健康狀態和版本{ healthy: true, version: string }

範例

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

應用程式

方法描述回應
app.log()寫入日誌項目boolean
app.agents()列出所有可用的代理Agent[]

範例

// 寫入日誌項目
await client.app.log({
  body: {
    service: "my-app",
    level: "info",
    message: "操作完成",
  },
})

// 列出可用的代理
const agents = await client.app.agents()

專案

方法描述回應
project.list()列出所有專案Project[]
project.current()取得目前專案Project

範例

// 列出所有專案
const projects = await client.project.list()

// 取得目前專案
const currentProject = await client.project.current()

路徑

方法描述回應
path.get()取得目前路徑Path

範例

// 取得目前路徑資訊
const pathInfo = await client.path.get()

設定

方法描述回應
config.get()取得設定資訊Config

範例

const config = await client.config.get()

工作階段

方法描述備註
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 及 AI 回應。支援 body.outputFormat 以進行結構化輸出
session.command({ path, body })傳送指令給工作階段回傳 { info: AssistantMessage, parts: Part[]}
session.shell({ path, body })執行 shell 指令回傳 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: "你好!" }],
  },
})

// 注入內容而不觸發 AI 回應(適用於外掛程式)
await client.session.prompt({
  path: { id: session.data.id },
  body: {
    noReply: true,
    parts: [{ type: "text", text: "您是一位有用的助理。" }],
  },
})

檔案

方法描述回應
find.text({ query })在檔案中搜尋文字包含 pathlinesline_numberabsolute_offsetsubmatches 的比對物件陣列
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.set({ ... })設定驗證憑證boolean

範例

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

事件

方法描述回應
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 介面(用於上述範例)和一個鏡像較新 Effect HttpApi 合約的 v2 介面。新整合請優先使用 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