Skip to content

Migration: v0.1.9 → v0.1.11

Overview

v0.1.11 includes a complete execution plan rewrite (task → node model), native SDK tool approval flow, stream rejoin infrastructure, and several bug fixes.

Breaking Changes

Execution Plan Schema Rewrite

The execution plan model was rewritten from a flat task list to a DAG-based node/run architecture.

Type Renames (@lota-sdk/shared/schemas/execution-plan)

v0.1.9v0.1.11
ExecutionPlanStatusPlanRunStatus
ExecutionPlanTaskStatusPlanNodeRunStatus
ExecutionPlanTaskResultStatusRemoved (use PlanAttemptStatus)
ExecutionPlanTaskKindPlanNodeType
ExecutionPlanTaskOwnerTypePlanNodeExecutorType
SerializableExecutionPlanTaskSerializablePlanNode
SerializableExecutionPlanEventRemoved (use SerializablePlanApproval)

Status Enum Changes

v0.1.9v0.1.11
draftRemoved
executingrunning
awaiting-human (new)
failed (new)
blockedblocked
completedcompleted
abortedaborted

Task Status → Node Run Status

v0.1.9v0.1.11
pendingpending
in-progressrunning
completedcompleted
blockedblocked
skippedskipped
failedfailed

Owner Model Change

typescript
// v0.1.9
task.ownerType  // 'agent' | 'plugin' | 'user'
task.ownerRef   // string

// v0.1.11
node.owner.executorType  // 'agent' | 'plugin' | 'user' | 'system'
node.owner.ref           // string

Tool Name Constants (@lota-sdk/shared/schemas/tools)

v0.1.9v0.1.11
SET_EXECUTION_TASK_STATUS_TOOL_NAME (setExecutionTaskStatus)SUBMIT_EXECUTION_NODE_RESULT_TOOL_NAME (submitExecutionNodeResult)
RESTART_EXECUTION_TASK_TOOL_NAME (restartExecutionTask)RESUME_EXECUTION_PLAN_RUN_TOOL_NAME (resumeExecutionPlanRun)

Tool Arg Schemas (@lota-sdk/shared/schemas/tools)

v0.1.9v0.1.11
SetExecutionTaskStatusArgsSchemaSubmitExecutionNodeResultArgsSchema
RestartExecutionTaskArgsSchemaResumeExecutionPlanRunArgsSchema
SetExecutionTaskStatusArgsSubmitExecutionNodeResultArgs
RestartExecutionTaskArgsResumeExecutionPlanRunArgs

Chat Request Routing (@lota-sdk/core/runtime/chat-request-routing)

RoutedChatRequest has a new discriminant:

typescript
// v0.1.11 — new kind
| { kind: 'native-tool-approval'; messages: ChatMessage[] }

If your chat handler uses routeWorkstreamChatMessages, add a branch:

typescript
if (routed.kind === 'native-tool-approval') {
  const stream = await runtime.services.createWorkstreamNativeToolApprovalStream({
    workstream,
    workstreamRef,
    orgRef,
    userRef,
    userName,
    approvalMessages: routed.messages,
  })
  return createUIMessageStreamResponse({ stream })
}

Without this, native tool approval responses fall through to the regular turn handler, which creates a new turn instead of continuing the existing one.

UI Helpers (@lota-sdk/ui/tools/execution-plan)

v0.1.9v0.1.11
getExecutionPlanOwnerLabel(task)getExecutionPlanOwnerLabel(node) — reads node.owner.executorType / node.owner.ref
getExecutionPlanStatusLabel('executing')getExecutionPlanStatusLabel('running') — new statuses: running, awaiting-human, failed
getExecutionPlanActionLabel('task-status-updated')getExecutionPlanActionLabel('node-result-submitted')
getExecutionPlanActionLabel('task-restarted')getExecutionPlanActionLabel('run-resumed')

New Features

Native SDK Tool Approval (needsApproval)

Tools can now declare needsApproval: true and the SDK handles the full approval lifecycle:

typescript
import { tool } from 'ai'

const myTool = tool({
  description: 'Does something sensitive',
  inputSchema: z.object({ input: z.string() }),
  needsApproval: true,
  execute: async ({ input }) => { /* runs after approval */ },
})

The client renders approve/deny UI via addToolApprovalResponse from useChat. The SDK routes the approval response through createWorkstreamNativeToolApprovalStream which re-executes the agent turn with the approval attached.

Stream Rejoin Infrastructure

New server-side infrastructure for reconnecting clients to in-progress LLM streams after page refresh:

  • createWorkstreamResumableContext() — creates a Redis-backed resumable stream context
  • workstreamService.setActiveStreamId() / getActiveStreamId() / clearActiveStreamIdIfMatches() — track the active stream per workstream
  • activeStreamId field added to workstream schema
  • consumeSseStream callback on createUIMessageStreamResponse publishes SSE data to Redis
  • GET endpoint replays the buffered stream via resumeExistingStream

Important: The useThreadChat hook's resume option now uses a ref guard to prevent React StrictMode from firing two concurrent GET requests. If you were calling resumeStream() manually, switch to passing resume: true to useThreadChat / useLotaChat.

New Exports (@lota-sdk/core)

ExportPurpose
createWorkstreamNativeToolApprovalStreamOn runtime.services — handles native tool approval continuation
createWorkstreamResumableContextCreates Redis-backed resumable stream context
createLogHelloWorldToolDemo tool with needsApproval: true

Bug Fixes

  • CONFLICT error on rapid messages: clearActiveRunId now runs before compaction assessment in finalizeTurnRun, preventing "A chat run is already active" when sending messages shortly after a run completes
  • "custom:" prefix in user questions: Free-text answers no longer include the custom: prefix
  • Tool label: Active tools now show "Running" instead of "Pending"

Required Consumer Changes

Server-side chat handler

Add the native-tool-approval branch to your chat message router (see Chat Request Routing above).

Client-side execution plan rendering

Update all references to the old plan types. Search your codebase for:

SerializableExecutionPlanTask → SerializablePlanNode
task.ownerType → node.owner.executorType
task.ownerRef → node.owner.ref
setExecutionTaskStatus → submitExecutionNodeResult
restartExecutionTask → resumeExecutionPlanRun
SET_EXECUTION_TASK_STATUS_TOOL_NAME → SUBMIT_EXECUTION_NODE_RESULT_TOOL_NAME
RESTART_EXECUTION_TASK_TOOL_NAME → RESUME_EXECUTION_PLAN_RUN_TOOL_NAME

Dependencies

diff
- "@lota-sdk/core": "0.1.9"
+ "@lota-sdk/core": "0.1.11"
- "@lota-sdk/shared": "0.1.9"
+ "@lota-sdk/shared": "0.1.11"
- "@lota-sdk/ui": "0.1.9"
+ "@lota-sdk/ui": "0.1.11"

Optional: Stream rejoin

If you want stream rejoin support:

  1. Pass streamId to createWorkstreamTurnStream / createWorkstreamApprovalContinuationStream / createWorkstreamNativeToolApprovalStream
  2. Wrap createUIMessageStreamResponse with consumeSseStream that calls streamContext.createNewResumableStream
  3. Add a GET endpoint that reads workstreamService.getActiveStreamId and replays via streamContext.resumeExistingStream
  4. Pass resume: true to useLotaChat / useThreadChat
  5. Configure prepareReconnectToStreamRequest on your DefaultChatTransport to point to your GET endpoint