SDK 教學 · 2 / 10

建立並延續對話

當產品要自行掌控互動介面,但仍希望由 Heddle 負責耐久的對話語意時,就從 terminal quickstart 移到 conversation engine。

客製化深度

層級 2 · 產品端對話流程

託管深度

Process 內的 Node.js host

文件狀態

支援的 SDK 邊界

前置假設

  • 產品自行決定何時建立對話,以及何時送出使用者訊息。
  • 每個進行中的 turn 由單一 process 負責;遠端重新連線會在 hosting 章節加入。
  • 現階段可以接受預設的本機 session repository。
Heddle 負責
  • 持久化 message、turn、continuation state、compaction metadata 與 session lease。
  • 執行 model/tool loop,並在每個 turn 後回傳 structured result。
  • 從 stateRoot 解析預設的 session、trace、memory 與 artifact 路徑。
產品端負責
  • 把穩定的 product conversation ID 對應到 Heddle session ID,並執行 access policy。
  • 決定何時建立、重新開啟、重新命名、封存或刪除 session。
  • 在產品原本的 presentation layer 呈現 activity 與 result。

在 host boundary 建立一次 engine

請在 application composition root 建立 engine,而不是每個 request 都重新建立。Engine 會解析一次 storage 與 extension dependencies,並在 session 與 turn service 之間共用。

TypeScript
import { join } from 'node:path'
import {
  createConversationEngine,
  createConversationTextHost,
} from '@roackb2/heddle'

const workspaceRoot = process.cwd()
const stateRoot = join(workspaceRoot, '.heddle')

const engine = createConversationEngine({
  workspaceRoot,
  stateRoot,
  model: process.env.HEDDLE_MODEL ?? 'gpt-5.4',
  reasoningEffort: 'medium',
})

Heddle 預設會推導出:

  • stateRoot/chat-sessions.catalog.json 的 session catalog;
  • stateRoot/chat-sessions 下的 session body;
  • stateRoot/memory 下的 memory;
  • stateRoot/traces 下的 trace;
  • stateRoot/artifacts 下的 artifact。

建立可持久化的 session

所有 session operations 都是非同步:

TypeScript
const session = await engine.sessions.create({
  name: 'Product assistant',
})

請把 session.id 儲存在產品自己的 conversation record 旁。Heddle 刻意不接管你的 account、tenant 或 domain relationships。

送出多個使用者 turn

每一則新的使用者訊息都使用 submit,並沿用同一個 session ID:

TypeScript
const textHost = createConversationTextHost()

const first = await engine.turns.submit({
  sessionId: session.id,
  prompt: 'Summarize the workspace in three bullets.',
  host: textHost.host,
})

textHost.renderTurnResult(first)

const second = await engine.turns.submit({
  sessionId: session.id,
  prompt: 'Expand the second bullet with supporting evidence.',
  host: textHost.host,
})

textHost.renderTurnResult(second)

Heddle 會重新載入持久化歷史、在必要時執行 compaction、為 turn 取得 session lease,最後儲存新的 messages。不要在產品端重建歷史再貼進每個 prompt;那會形成另一套彼此競爭的 conversation model。

重新開啟既有 session

TypeScript
const existing = await engine.sessions.readExisting(savedHeddleSessionId)

if (!existing) {
  throw new Error('Conversation no longer exists')
}

檢查持久化狀態時請使用 readExisting。它與相容性導向的 read 不同,不會在空 repository 中具體化 Heddle 的 fallback session。

其他支援的 lifecycle operations 包含 listCatalogrenamesetPinnedsetArchiveddelete。請先在這些 calls 外完成使用者授權,解析出已授權的 product record 後,才查找對應的 Heddle session。

Submit 與 continue 的差異

  • engine.turns.submit({ sessionId, prompt }) 會在現有對話中開始新的使用者 turn。
  • engine.turns.continue({ sessionId }) 會在中斷或既有 run 後,重新使用上一個 continuation prompt。
  • 若 session 沒有可延續的 prior run,continue 會丟出錯誤。

不要把 continue 當成一般的第二則訊息 API。

何時加入 hosted run layer

Conversation engine call 會等待單一 process 內的 turn 完成。若 turn 必須超過 HTTP request 的生命週期、需要可定址的 cancellation 或 approval lifecycle,或需要讓 client 中斷後重播排序事件,就加入 ConversationRunService

權威來源