SDK tutorial · 2 of 10
Create and continue conversations
Move from the terminal quickstart to the conversation engine when your product owns the interaction surface but still wants durable Heddle conversation semantics.
Customization depth
Level 2 · Product-owned conversation flow
Hosting depth
In-process Node.js host
Documentation status
Supported SDK boundary
Assumptions
- The product owns when a conversation is created and when a user submits a message.
- One process owns each in-flight turn; remote reconnection is introduced in the hosting section.
- The default local session repository is acceptable for this stage.
- Persist messages, turns, continuation state, compaction metadata, and session leases.
- Run the model/tool loop and return a structured result after every turn.
- Resolve default session, trace, memory, and artifact paths from stateRoot.
- Map a stable product conversation ID to a Heddle session ID and enforce access policy.
- Choose when to create, reopen, rename, archive, or delete a session.
- Render activities and results in the product's normal presentation layer.
Create an engine once at the host boundary
Construct the engine in your application composition root rather than once per request. The engine resolves storage and extension dependencies once and shares them across session and turn services.
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',
})By default Heddle derives:
- the session catalog at
stateRoot/chat-sessions.catalog.json; - session bodies beneath
stateRoot/chat-sessions; - memory beneath
stateRoot/memory; - traces beneath
stateRoot/traces; - artifacts beneath
stateRoot/artifacts.
Create a persisted session
Session operations are asynchronous:
const session = await engine.sessions.create({
name: 'Product assistant',
})Persist session.id beside the product's conversation record. Heddle deliberately does not own your account, tenant, or domain relationships.
Submit multiple user turns
Use submit for every new user message and keep the same session ID:
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 reloads the persisted history, performs compaction when needed, acquires a session lease for the turn, and saves the resulting messages. Do not rebuild product history and paste it into every prompt; that creates a competing conversation model.
Reopen an existing session
const existing = await engine.sessions.readExisting(savedHeddleSessionId)
if (!existing) {
throw new Error('Conversation no longer exists')
}Use readExisting when checking persisted state. Unlike the compatibility-oriented read, it does not materialize Heddle's fallback session in an empty repository.
Other supported lifecycle operations include listCatalog, rename, setPinned, setArchived, and delete. Keep user authorization outside these calls and resolve the authorized product record before looking up its Heddle session.
Submit versus continue
engine.turns.submit({ sessionId, prompt })starts a new user turn in the existing conversation.engine.turns.continue({ sessionId })reuses the last continuation prompt after an interrupted or prior run.continuethrows when the session has no prior run to continue.
Do not use continue as the ordinary second-message API.
When to add the hosted run layer
The conversation engine call awaits one in-process turn. Add ConversationRunService when a turn must outlive an HTTP request, have an addressable cancellation or approval lifecycle, or allow clients to disconnect and replay ordered events.