@lota-sdk/core 0.2.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/infrastructure/schema/00_identity.surql +2 -2
  2. package/infrastructure/schema/00_thread.surql +73 -0
  3. package/infrastructure/schema/02_execution_plan.surql +10 -11
  4. package/infrastructure/schema/04_runtime_bootstrap.surql +1 -0
  5. package/infrastructure/schema/10_autonomous_job.surql +3 -3
  6. package/package.json +2 -2
  7. package/src/ai/definitions.ts +1 -1
  8. package/src/config/agent-defaults.ts +5 -5
  9. package/src/config/index.ts +1 -1
  10. package/src/config/thread-defaults.ts +72 -0
  11. package/src/create-runtime.ts +90 -94
  12. package/src/db/record-id.ts +21 -21
  13. package/src/db/service.ts +44 -40
  14. package/src/db/tables.ts +3 -3
  15. package/src/db/{workstream-message-row.ts → thread-message-row.ts} +3 -3
  16. package/src/queues/context-compaction.queue.ts +6 -6
  17. package/src/queues/plan-agent-heartbeat.queue.ts +3 -3
  18. package/src/queues/post-chat-memory.queue.ts +1 -1
  19. package/src/queues/title-generation.queue.ts +10 -13
  20. package/src/redis/index.ts +1 -1
  21. package/src/redis/stream-context.ts +1 -1
  22. package/src/runtime/agent-identity-overrides.ts +1 -1
  23. package/src/runtime/agent-runtime-policy.ts +19 -21
  24. package/src/runtime/chat-request-routing.ts +1 -1
  25. package/src/runtime/context-compaction-constants.ts +1 -1
  26. package/src/runtime/context-compaction.ts +1 -1
  27. package/src/runtime/execution-plan.ts +1 -1
  28. package/src/runtime/index.ts +1 -1
  29. package/src/runtime/memory-digest-policy.ts +1 -1
  30. package/src/runtime/plugin-types.ts +1 -1
  31. package/src/runtime/post-turn-side-effects.ts +35 -35
  32. package/src/runtime/runtime-config.ts +24 -21
  33. package/src/runtime/runtime-extensions.ts +11 -11
  34. package/src/runtime/social-chat-agent-runner.ts +3 -3
  35. package/src/runtime/social-chat-history.ts +1 -1
  36. package/src/runtime/social-chat.ts +6 -6
  37. package/src/runtime/team-consultation-orchestrator.ts +1 -1
  38. package/src/runtime/{workstream-chat-helpers.ts → thread-chat-helpers.ts} +7 -7
  39. package/src/runtime/{workstream-plan-turn.ts → thread-plan-turn.ts} +11 -17
  40. package/src/runtime/{workstream-turn-context.ts → thread-turn-context.ts} +10 -10
  41. package/src/services/agent-activity.service.ts +39 -44
  42. package/src/services/agent-executor.service.ts +17 -19
  43. package/src/services/attachment.service.ts +4 -8
  44. package/src/services/autonomous-job.service.ts +29 -28
  45. package/src/services/context-compaction.service.ts +19 -29
  46. package/src/services/execution-plan.service.ts +58 -70
  47. package/src/services/global-orchestrator.service.ts +5 -5
  48. package/src/services/index.ts +6 -6
  49. package/src/services/memory.service.ts +1 -1
  50. package/src/services/monitoring-window.service.ts +2 -2
  51. package/src/services/mutating-approval.service.ts +7 -10
  52. package/src/services/node-workspace.service.ts +8 -7
  53. package/src/services/notification.service.ts +1 -1
  54. package/src/services/organization.service.ts +9 -9
  55. package/src/services/ownership-dispatcher.service.ts +13 -19
  56. package/src/services/plan-agent-heartbeat.service.ts +13 -13
  57. package/src/services/plan-agent-query.service.ts +7 -7
  58. package/src/services/plan-artifact.service.ts +1 -2
  59. package/src/services/plan-coordination.service.ts +4 -4
  60. package/src/services/plan-cycle.service.ts +7 -7
  61. package/src/services/plan-deadline.service.ts +4 -4
  62. package/src/services/plan-event-delivery.service.ts +8 -12
  63. package/src/services/plan-executor.service.ts +25 -39
  64. package/src/services/plan-run-data.ts +27 -8
  65. package/src/services/plan-run.service.ts +7 -9
  66. package/src/services/plan-scheduler.service.ts +4 -4
  67. package/src/services/plan-template.service.ts +2 -2
  68. package/src/services/plan-validator.service.ts +0 -11
  69. package/src/services/plugin-executor.service.ts +1 -1
  70. package/src/services/queue-job.service.ts +1 -1
  71. package/src/services/recent-activity-title.service.ts +1 -1
  72. package/src/services/recent-activity.service.ts +4 -4
  73. package/src/services/system-executor.service.ts +2 -2
  74. package/src/services/{workstream-message.service.ts → thread-message.service.ts} +72 -76
  75. package/src/services/thread-plan-registry.service.ts +22 -0
  76. package/src/services/thread-title.service.ts +39 -0
  77. package/src/services/{workstream-turn-preparation.service.ts → thread-turn-preparation.service.ts} +148 -171
  78. package/src/services/{workstream-turn.ts → thread-turn.ts} +27 -31
  79. package/src/services/thread.service.ts +853 -0
  80. package/src/services/thread.types.ts +17 -0
  81. package/src/storage/attachment-storage.service.ts +4 -4
  82. package/src/system-agents/index.ts +1 -1
  83. package/src/system-agents/memory.agent.ts +1 -1
  84. package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
  85. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  86. package/src/system-agents/researcher.agent.ts +3 -3
  87. package/src/system-agents/{workstream-router.agent.ts → thread-router.agent.ts} +68 -135
  88. package/src/system-agents/title-generator.agent.ts +8 -8
  89. package/src/tools/execution-plan.tool.ts +39 -40
  90. package/src/tools/memory-block.tool.ts +4 -4
  91. package/src/tools/research-topic.tool.ts +1 -0
  92. package/src/tools/search-web.tool.ts +1 -1
  93. package/src/tools/search.tool.ts +4 -4
  94. package/src/tools/team-think.tool.ts +9 -9
  95. package/src/utils/async.ts +6 -7
  96. package/src/workers/regular-chat-memory-digest.helpers.ts +1 -1
  97. package/src/workers/regular-chat-memory-digest.runner.ts +43 -43
  98. package/src/workers/skill-extraction.runner.ts +9 -13
  99. package/src/workers/utils/{workstream-message-query.ts → thread-message-query.ts} +21 -21
  100. package/infrastructure/schema/00_workstream.surql +0 -64
  101. package/src/config/workstream-defaults.ts +0 -72
  102. package/src/services/workstream-plan-registry.service.ts +0 -22
  103. package/src/services/workstream-title.service.ts +0 -42
  104. package/src/services/workstream.service.ts +0 -803
  105. package/src/services/workstream.types.ts +0 -17
  106. /package/src/services/{workstream-constants.ts → thread-constants.ts} +0 -0
@@ -1,5 +1,5 @@
1
1
  import {
2
- WORKSTREAM,
2
+ THREAD,
3
3
  dataPartsSchemas,
4
4
  messageMetadataSchema,
5
5
  PlanNodeResultSubmissionSchema,
@@ -11,13 +11,13 @@ import type { ChatMessage, MessageMetadata, PlanNodeSpecRecord } from '@lota-sdk
11
11
  import { convertToModelMessages, stepCountIs, tool as createTool, validateUIMessages } from 'ai'
12
12
  import type { PrepareStepFunction, StopCondition, ToolLoopAgent, ToolSet, UIMessageStreamWriter } from 'ai'
13
13
 
14
- import type { CoreWorkstreamProfile } from '../config/agent-defaults'
14
+ import type { CoreThreadProfile } from '../config/agent-defaults'
15
15
  import {
16
16
  agentRoster,
17
17
  buildAgentTools,
18
18
  createAgent,
19
19
  getLeadAgentId,
20
- getCoreWorkstreamProfile,
20
+ getCoreThreadProfile,
21
21
  getAgentRuntimeConfig,
22
22
  } from '../config/agent-defaults'
23
23
  import { lotaDebugLogger } from '../config/debug-logger'
@@ -26,7 +26,7 @@ import type { RecordIdRef } from '../db/record-id'
26
26
  import { recordIdToString } from '../db/record-id'
27
27
  import { TABLES } from '../db/tables'
28
28
  import { enqueueContextCompaction } from '../queues/context-compaction.queue'
29
- import { enqueueWorkstreamTitleGeneration } from '../queues/title-generation.queue'
29
+ import { enqueueThreadTitleGeneration } from '../queues/title-generation.queue'
30
30
  import { readRuntimeAgentIdentityOverrides, resolveRuntimeAgentDisplayName } from '../runtime/agent-identity-overrides'
31
31
  import { OWNERSHIP_DISPATCH_BLOCKED_TOOL_NAMES } from '../runtime/agent-runtime-policy'
32
32
  import { createAgentMessageMetadata, createServerRunAbortController } from '../runtime/agent-stream-helpers'
@@ -39,7 +39,6 @@ import { createExecutionPlanInstructionSectionCache } from '../runtime/execution
39
39
  import { mergeInstructionSections } from '../runtime/instruction-sections'
40
40
  import { runPostTurnSideEffects } from '../runtime/post-turn-side-effects'
41
41
  import { getRuntimeAdapters, getToolProviders, getTurnHooks } from '../runtime/runtime-extensions'
42
- import { finalizeTurnRun } from '../runtime/turn-lifecycle'
43
42
  import {
44
43
  asRecord,
45
44
  collectToolOutputErrors,
@@ -47,17 +46,18 @@ import {
47
46
  readInstructionSections,
48
47
  readOptionalString,
49
48
  toOptionalTrimmedString,
50
- } from '../runtime/workstream-chat-helpers'
49
+ } from '../runtime/thread-chat-helpers'
51
50
  import {
52
51
  buildPlanTurnInstructionSections,
53
52
  buildPlanTurnPromptMessage,
54
53
  buildPlanTurnSubmitToolDescription,
55
- } from '../runtime/workstream-plan-turn'
56
- import type { WorkstreamPlanTurnContext } from '../runtime/workstream-plan-turn'
57
- import { assembleWorkstreamTurnContext } from '../runtime/workstream-turn-context'
54
+ } from '../runtime/thread-plan-turn'
55
+ import type { ThreadPlanTurnContext } from '../runtime/thread-plan-turn'
56
+ import { assembleThreadTurnContext } from '../runtime/thread-turn-context'
57
+ import { finalizeTurnRun } from '../runtime/turn-lifecycle'
58
58
  import { chatRunRegistry } from '../services/chat-run-registry.service'
59
- import type { NormalizedWorkstream, WorkstreamRecord } from '../services/workstream.types'
60
- import { triageWorkstreamMessage, checkForNextAgent } from '../system-agents/workstream-router.agent'
59
+ import type { NormalizedThread, ThreadRecord } from '../services/thread.types'
60
+ import { triageThreadMessage, checkForNextAgent } from '../system-agents/thread-router.agent'
61
61
  import { safeEnqueue } from '../utils/async'
62
62
  import { AppError } from '../utils/errors'
63
63
  import { attachmentService } from './attachment.service'
@@ -67,8 +67,8 @@ import { executionPlanService } from './execution-plan.service'
67
67
  import { learnedSkillService } from './learned-skill.service'
68
68
  import { memoryService } from './memory.service'
69
69
  import { planRunService } from './plan-run.service'
70
- import { workstreamMessageService } from './workstream-message.service'
71
- import { ActiveWorkstreamRunConflictError, workstreamService } from './workstream.service'
70
+ import { threadMessageService } from './thread-message.service'
71
+ import { ActiveThreadRunConflictError, threadService } from './thread.service'
72
72
 
73
73
  type ChatStreamChunk = Parameters<UIMessageStreamWriter<ChatMessage>['write']>[0]
74
74
 
@@ -86,22 +86,22 @@ function hasUIMessageStream(value: unknown): value is UIMessageStreamResult {
86
86
 
87
87
  const PRESEEDED_MEMORY_LOOKUP_LIMIT = 3
88
88
 
89
- async function waitForWorkstreamCompactionIfNeeded(workstreamId: RecordIdRef): Promise<WorkstreamRecord> {
89
+ async function waitForThreadCompactionIfNeeded(threadId: RecordIdRef): Promise<ThreadRecord> {
90
90
  return waitForCompactionIfNeeded({
91
- entityId: recordIdToString(workstreamId, TABLES.WORKSTREAM),
92
- entityLabel: 'Workstream',
93
- loadEntity: () => workstreamService.getById(workstreamId),
94
- isCompacting: (workstream) => workstream.isCompacting === true,
91
+ entityId: recordIdToString(threadId, TABLES.THREAD),
92
+ entityLabel: 'Thread',
93
+ loadEntity: () => threadService.getById(threadId),
94
+ isCompacting: (thread) => thread.isCompacting === true,
95
95
  })
96
96
  }
97
97
 
98
- class WorkstreamTurnError extends AppError {
98
+ class ThreadTurnError extends AppError {
99
99
  constructor(
100
100
  message: string,
101
101
  readonly statusCode: 400 | 409,
102
102
  ) {
103
103
  super(message, statusCode === 409 ? 'CONFLICT' : 'BAD_REQUEST', statusCode)
104
- this.name = 'WorkstreamTurnError'
104
+ this.name = 'ThreadTurnError'
105
105
  }
106
106
  }
107
107
 
@@ -122,12 +122,13 @@ function writeMultiAgentEvent(
122
122
  ): void {
123
123
  if (!writer) return
124
124
 
125
- writer.write({
125
+ const chunk: ChatStreamChunk = {
126
126
  type: 'data-multi-agent-event',
127
127
  id: `multi-agent-${Bun.randomUUIDv7()}`,
128
128
  data: event,
129
129
  transient: true,
130
- } as unknown as ChatStreamChunk)
130
+ }
131
+ writer.write(chunk)
131
132
  }
132
133
 
133
134
  function applyPlanTurnToolPolicy(tools: ToolSet, nodeSpec: PlanNodeSpecRecord): ToolSet {
@@ -143,9 +144,9 @@ function applyPlanTurnToolPolicy(tools: ToolSet, nodeSpec: PlanNodeSpecRecord):
143
144
  )
144
145
  }
145
146
 
146
- export interface WorkstreamTurnParams {
147
- workstream: NormalizedWorkstream
148
- workstreamRef: RecordIdRef
147
+ export interface ThreadTurnParams {
148
+ thread: NormalizedThread
149
+ threadRef: RecordIdRef
149
150
  orgRef: RecordIdRef
150
151
  userRef: RecordIdRef
151
152
  userName?: string | null
@@ -156,9 +157,9 @@ export interface WorkstreamTurnParams {
156
157
  streamId?: string
157
158
  }
158
159
 
159
- export interface WorkstreamApprovalContinuationParams {
160
- workstream: NormalizedWorkstream
161
- workstreamRef: RecordIdRef
160
+ export interface ThreadApprovalContinuationParams {
161
+ thread: NormalizedThread
162
+ threadRef: RecordIdRef
162
163
  orgRef: RecordIdRef
163
164
  userRef: RecordIdRef
164
165
  userName?: string | null
@@ -167,20 +168,20 @@ export interface WorkstreamApprovalContinuationParams {
167
168
  streamId?: string
168
169
  }
169
170
 
170
- export interface WorkstreamPlanTurnParams {
171
- workstream: NormalizedWorkstream
172
- workstreamRef: RecordIdRef
171
+ export interface ThreadPlanTurnParams {
172
+ thread: NormalizedThread
173
+ threadRef: RecordIdRef
173
174
  orgRef: RecordIdRef
174
175
  userRef: RecordIdRef
175
176
  userName?: string | null
176
- planTurn: WorkstreamPlanTurnContext
177
+ planTurn: ThreadPlanTurnContext
177
178
  abortSignal?: AbortSignal
178
179
  streamId?: string
179
180
  }
180
181
 
181
- type WorkstreamRunCoreParams = {
182
- workstream: NormalizedWorkstream
183
- workstreamRef: RecordIdRef
182
+ type ThreadRunCoreParams = {
183
+ thread: NormalizedThread
184
+ threadRef: RecordIdRef
184
185
  orgRef: RecordIdRef
185
186
  userRef: RecordIdRef
186
187
  userName?: string | null
@@ -191,15 +192,15 @@ type WorkstreamRunCoreParams = {
191
192
  | { kind: 'userTurn'; inputMessage: ChatMessage; skipInputMessagePersistence?: boolean }
192
193
  | { kind: 'approvalContinuation'; approvalMessages: ChatMessage[] }
193
194
  | { kind: 'nativeToolApprovalTurn'; approvalMessages: ChatMessage[] }
194
- | { kind: 'planTurn'; planTurn: WorkstreamPlanTurnContext }
195
+ | { kind: 'planTurn'; planTurn: ThreadPlanTurnContext }
195
196
  )
196
197
 
197
- interface PreparedWorkstreamTurn {
198
+ interface PreparedThreadTurn {
198
199
  originalMessages: ChatMessage[]
199
- run: (writer?: UIMessageStreamWriter<ChatMessage>) => Promise<PreparedWorkstreamTurnResult>
200
+ run: (writer?: UIMessageStreamWriter<ChatMessage>) => Promise<PreparedThreadTurnResult>
200
201
  }
201
202
 
202
- export interface PreparedWorkstreamTurnResult {
203
+ export interface PreparedThreadTurnResult {
203
204
  inputMessageId?: string
204
205
  assistantMessages: ChatMessage[]
205
206
  }
@@ -217,8 +218,8 @@ function upsertChatHistoryMessage(messages: ChatMessage[], nextMessage: ChatMess
217
218
 
218
219
  interface StreamAgentResponseContext {
219
220
  turnHooks: ReturnType<typeof getTurnHooks>
220
- workstream: NormalizedWorkstream
221
- workstreamRef: RecordIdRef
221
+ thread: NormalizedThread
222
+ threadRef: RecordIdRef
222
223
  orgRef: RecordIdRef
223
224
  userRef: RecordIdRef
224
225
  userName?: string | null
@@ -238,7 +239,7 @@ interface StreamAgentResponseContext {
238
239
 
239
240
  interface StreamAgentResponseParams {
240
241
  agentId: string
241
- mode: 'direct' | 'fixedWorkstreamMode' | 'workstreamMode'
242
+ mode: 'direct' | 'fixedThreadMode' | 'threadMode'
242
243
  messages: ChatMessage[]
243
244
  tools: ToolSet
244
245
  observer: {
@@ -269,8 +270,8 @@ async function streamAgentResponse(
269
270
  await ctx.turnHooks.resolveAgent?.({
270
271
  agentId: streamParams.agentId,
271
272
  mode: streamParams.mode,
272
- workstream: ctx.workstream,
273
- workstreamRef: ctx.workstreamRef,
273
+ thread: ctx.thread,
274
+ threadRef: ctx.threadRef,
274
275
  orgRef: ctx.orgRef,
275
276
  userRef: ctx.userRef,
276
277
  userName: ctx.userName,
@@ -306,7 +307,7 @@ async function streamAgentResponse(
306
307
  resolvedAgentId === 'mentor'
307
308
  const config = getAgentRuntimeConfig({
308
309
  agentId: resolvedAgentId,
309
- workstreamMode: ctx.workstream.mode,
310
+ threadType: ctx.thread.type,
310
311
  mode: streamParams.mode,
311
312
  skills: streamParams.skills,
312
313
  onboardingActive: ctx.onboardingActive,
@@ -314,7 +315,7 @@ async function streamAgentResponse(
314
315
  systemWorkspaceDetails: ctx.promptContext.systemWorkspaceDetails,
315
316
  preSeededMemoriesSection,
316
317
  retrievedKnowledgeSection: ctx.retrievedKnowledgeSection,
317
- workstreamMemoryBlock: ctx.memoryBlock,
318
+ threadMemoryBlock: ctx.memoryBlock,
318
319
  learnedSkillsSection,
319
320
  userMessageText: latestUserMessageText,
320
321
  ruleOptions: { includeMemr3Rule: hasRetrievalTools, includeDomainReasoningFallbackRule: hasDomainRoutingSkills },
@@ -342,32 +343,20 @@ async function streamAgentResponse(
342
343
  const agentAbortSignal = streamParams.abortSignal ?? ctx.runAbortSignal
343
344
  agentTimer.step('agent-construction')
344
345
 
345
- const MAX_STREAM_RETRIES = 3
346
346
  let result: unknown
347
- for (let attempt = 0; ; attempt++) {
348
- try {
349
- result = await streamParams.observer.run(() =>
350
- agent.stream({ messages: modelMessages, abortSignal: agentAbortSignal }),
351
- )
352
- agentTimer.step('agent.stream()-resolved')
353
- break
354
- } catch (error) {
355
- if (agentAbortSignal.aborted) {
356
- streamParams.observer.recordAbort(error)
357
- throw error
358
- }
359
- const errorMessage = error instanceof Error ? error.message : String(error)
360
- const isTransient =
361
- errorMessage.includes('client disconnected') ||
362
- errorMessage.includes('ECONNRESET') ||
363
- errorMessage.includes('socket hang up') ||
364
- errorMessage.includes('fetch failed')
365
- if (!isTransient || attempt >= MAX_STREAM_RETRIES - 1) {
366
- streamParams.observer.recordError(error)
367
- throw error
368
- }
369
- aiLogger.warn`Transient stream error (attempt ${attempt + 1}/${MAX_STREAM_RETRIES}): ${errorMessage} — retrying`
347
+ try {
348
+ result = await streamParams.observer.run(() =>
349
+ agent.stream({ messages: modelMessages, abortSignal: agentAbortSignal }),
350
+ )
351
+ agentTimer.step('agent.stream()-resolved')
352
+ } catch (error) {
353
+ if (agentAbortSignal.aborted) {
354
+ streamParams.observer.recordAbort(error)
355
+ throw error
370
356
  }
357
+
358
+ streamParams.observer.recordError(error)
359
+ throw error
371
360
  }
372
361
  if (!hasUIMessageStream(result)) {
373
362
  throw new Error(`Agent run for ${resolvedAgentId} did not expose a UI message stream.`)
@@ -426,15 +415,15 @@ async function streamAgentResponse(
426
415
  return responseMessage
427
416
  }
428
417
 
429
- export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams): Promise<PreparedWorkstreamTurn> {
430
- const { workstream, workstreamRef, orgRef, userRef, userName } = params
418
+ export async function prepareThreadRunCore(params: ThreadRunCoreParams): Promise<PreparedThreadTurn> {
419
+ const { thread, threadRef, orgRef, userRef, userName } = params
431
420
  const runtimeAdapters = getRuntimeAdapters()
432
421
  const turnHooks = getTurnHooks()
433
422
  const toolProviders = getToolProviders()
434
423
  const workspaceProvider = runtimeAdapters.workspaceProvider
435
424
  const orgIdString = recordIdToString(orgRef, TABLES.ORGANIZATION)
436
425
  const userIdString = recordIdToString(userRef, TABLES.USER)
437
- const workstreamIdString = recordIdToString(workstreamRef, TABLES.WORKSTREAM)
426
+ const threadIdString = recordIdToString(threadRef, TABLES.THREAD)
438
427
 
439
428
  const hydrateMessageFileUrls = (message: ChatMessage): ChatMessage => ({
440
429
  ...message,
@@ -453,13 +442,13 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
453
442
  if (params.kind === 'userTurn') {
454
443
  inputMessage = hydrateMessageFileUrls(withMessageCreatedAt(params.inputMessage, Date.now()))
455
444
  if (inputMessage.role !== 'user') {
456
- throw new WorkstreamTurnError('Only user messages can be submitted to the workstream runtime.', 400)
445
+ throw new ThreadTurnError('Only user messages can be submitted to the thread runtime.', 400)
457
446
  }
458
447
  if (!hasMessageContent(inputMessage.parts)) {
459
- throw new WorkstreamTurnError('Workstream messages must include text or attachments.', 400)
448
+ throw new ThreadTurnError('Thread messages must include text or attachments.', 400)
460
449
  }
461
- if (workstream.mode === 'direct' && !workstream.agentId) {
462
- throw new WorkstreamTurnError('Direct workstreams require an assigned agent.', 400)
450
+ if (thread.type === 'default' && !thread.agentId) {
451
+ throw new ThreadTurnError('Default threads require an assigned agent.', 400)
463
452
  }
464
453
  }
465
454
 
@@ -471,17 +460,14 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
471
460
  ? workspaceProvider.getWorkspace(orgRef)
472
461
  : Promise.resolve({})
473
462
 
474
- const workstreamRecord = await waitForWorkstreamCompactionIfNeeded(workstreamRef)
463
+ const threadRecord = await waitForThreadCompactionIfNeeded(threadRef)
475
464
  timer.step('compaction-gate')
476
465
  // Plan turns run without the chat lease — they must not block or be blocked by user messages.
477
466
  if (params.kind !== 'planTurn') {
478
- if (
479
- (await workstreamService.hasActiveRunLease(workstreamRef)) ||
480
- toOptionalTrimmedString(workstreamRecord.activeRunId)
481
- ) {
482
- const clearedStaleRun = await workstreamService.clearStaleActiveRunIfMissingFromRegistry(workstreamRef)
467
+ if ((await threadService.hasActiveRunLease(threadRef)) || toOptionalTrimmedString(threadRecord.activeRunId)) {
468
+ const clearedStaleRun = await threadService.clearStaleActiveRunIfMissingFromRegistry(threadRef)
483
469
  if (!clearedStaleRun) {
484
- throw new WorkstreamTurnError('A chat run is already active.', 409)
470
+ throw new ThreadTurnError('A chat run is already active.', 409)
485
471
  }
486
472
  }
487
473
  }
@@ -491,22 +477,19 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
491
477
  .reverse()
492
478
  .find((m) => m.role === 'assistant' && hasApprovalRespondedParts(m))
493
479
  if (!approvedAssistantMessage) {
494
- throw new WorkstreamTurnError('No approval-responded message found.', 400)
480
+ throw new ThreadTurnError('No approval-responded message found.', 400)
495
481
  }
496
- await workstreamMessageService.upsertMessages({ workstreamId: workstreamRef, messages: [approvedAssistantMessage] })
482
+ await threadMessageService.upsertMessages({ threadId: threadRef, messages: [approvedAssistantMessage] })
497
483
  timer.step('persist-approval-message')
498
484
  }
499
485
 
500
- const persistedCompactionCursor = toOptionalTrimmedString(workstreamRecord.lastCompactedMessageId) ?? undefined
501
- const persistedLiveHistoryPromise = workstreamMessageService.listMessagesAfterCursor(
502
- workstreamRef,
503
- persistedCompactionCursor,
504
- )
486
+ const persistedCompactionCursor = toOptionalTrimmedString(threadRecord.lastCompactedMessageId) ?? undefined
487
+ const persistedLiveHistoryPromise = threadMessageService.listMessagesAfterCursor(threadRef, persistedCompactionCursor)
505
488
  let recentHistoryPromise: Promise<ChatMessage[]> | null = null
506
489
  const loadRecentHistory = async (): Promise<ChatMessage[]> => {
507
490
  if (!recentHistoryPromise) {
508
- recentHistoryPromise = workstreamMessageService
509
- .listRecentMessages(workstreamRef, 64)
491
+ recentHistoryPromise = threadMessageService
492
+ .listRecentMessages(threadRef, 64)
510
493
  .then(async (persistedRecentHistory) => {
511
494
  if (persistedRecentHistory.length === 0) {
512
495
  return [] as ChatMessage[]
@@ -547,7 +530,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
547
530
  timer.step('validate+hydrate-history')
548
531
 
549
532
  if (userMessage && shouldPersistInputMessage) {
550
- await workstreamMessageService.upsertMessages({ workstreamId: workstreamRef, messages: [userMessage] })
533
+ await threadMessageService.upsertMessages({ threadId: threadRef, messages: [userMessage] })
551
534
  timer.step('persist-user-message')
552
535
  }
553
536
 
@@ -569,7 +552,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
569
552
  const respondedBy = recordIdToString(userRef, TABLES.USER)
570
553
  if (params.kind === 'approvalContinuation') {
571
554
  await executionPlanService.applyApprovalResponseFromMessages({
572
- workstreamId: workstreamRef,
555
+ threadId: threadRef,
573
556
  approvalMessages: params.approvalMessages,
574
557
  respondedBy,
575
558
  })
@@ -580,31 +563,29 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
580
563
 
581
564
  if (
582
565
  params.kind === 'userTurn' &&
583
- workstream.mode === 'group' &&
584
- !workstream.core &&
585
- workstreamRecord.nameGenerated !== true &&
586
- workstreamRecord.title === WORKSTREAM.DEFAULT_TITLE &&
566
+ thread.type === 'group' &&
567
+ threadRecord.nameGenerated !== true &&
568
+ threadRecord.title === THREAD.DEFAULT_TITLE &&
587
569
  messageText.length > 0
588
570
  ) {
589
- void safeEnqueue(
590
- () => enqueueWorkstreamTitleGeneration({ workstreamId: workstreamIdString, sourceText: messageText }),
591
- { operationName: 'workstream-title-generation' },
592
- )
571
+ void safeEnqueue(() => enqueueThreadTitleGeneration({ threadId: threadIdString, sourceText: messageText }), {
572
+ operationName: 'thread-title-generation',
573
+ })
593
574
  }
594
575
 
595
- if (workstream.core && !workstream.coreType) {
596
- throw new WorkstreamTurnError('Core workstreams require a core type.', 400)
576
+ if (thread.type === 'thread' && !thread.threadType) {
577
+ throw new ThreadTurnError('Core threads require a thread type.', 400)
597
578
  }
598
- const coreWorkstreamProfile: CoreWorkstreamProfile | null =
599
- workstream.core && workstream.coreType ? getCoreWorkstreamProfile(workstream.coreType) : null
579
+ const coreThreadProfile: CoreThreadProfile | null =
580
+ thread.type === 'thread' && thread.threadType ? getCoreThreadProfile(thread.threadType) : null
600
581
  const defaultLeadAgentId = getLeadAgentId()
601
- const visibleWorkstreamAgentId =
582
+ const visibleThreadAgentId =
602
583
  params.agentIdOverride ??
603
- (workstream.mode === 'direct' ? workstream.agentId : (coreWorkstreamProfile?.config.agentId ?? defaultLeadAgentId))
604
- const coreInstructionSections = coreWorkstreamProfile ? [coreWorkstreamProfile.instructions] : undefined
605
- const assembledContext = await assembleWorkstreamTurnContext({
606
- workstream,
607
- workstreamRef,
584
+ (thread.type === 'default' ? thread.agentId : (coreThreadProfile?.config.agentId ?? defaultLeadAgentId))
585
+ const coreInstructionSections = coreThreadProfile ? [coreThreadProfile.instructions] : undefined
586
+ const assembledContext = await assembleThreadTurnContext({
587
+ thread,
588
+ threadRef,
608
589
  orgRef,
609
590
  userRef,
610
591
  userName,
@@ -628,11 +609,11 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
628
609
  hookInstructionSections,
629
610
  } = assembledContext
630
611
 
631
- let memoryBlock = workstreamService.formatMemoryBlockForPrompt(workstreamRecord)
612
+ let memoryBlock = threadService.formatMemoryBlockForPrompt(threadRecord)
632
613
  const executionPlanInstructionSectionCache = createExecutionPlanInstructionSectionCache({
633
614
  disabled: false,
634
615
  loadPlans: async () => {
635
- const runs = await planRunService.getActiveRunRecords(workstreamRef)
616
+ const runs = await planRunService.getActiveRunRecords(threadRef)
636
617
  return Promise.all(runs.map((run) => planRunService.toSerializablePlan(run, { slim: true })))
637
618
  },
638
619
  })
@@ -643,7 +624,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
643
624
  }
644
625
  if (userMessage) {
645
626
  const appliedHumanInput = await executionPlanService.applyHumanInputFromUserMessage({
646
- workstreamId: workstreamRef,
627
+ threadId: threadRef,
647
628
  message: userMessage,
648
629
  respondedBy,
649
630
  })
@@ -684,8 +665,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
684
665
  }
685
666
 
686
667
  const persistedCompactionSummary =
687
- persistedCompactionCursor && typeof workstreamRecord.compactionSummary === 'string'
688
- ? workstreamRecord.compactionSummary
668
+ persistedCompactionCursor && typeof threadRecord.compactionSummary === 'string'
669
+ ? threadRecord.compactionSummary
689
670
  : ''
690
671
  const messagesForContext = userMessage ? upsertChatHistoryMessage(liveHistory, userMessage) : liveHistory
691
672
  let currentMessages = contextCompactionRuntime.prependSummaryMessage(persistedCompactionSummary, messagesForContext)
@@ -704,7 +685,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
704
685
  })
705
686
  const buildTurnToolParams = (toolParams: {
706
687
  agentId: string
707
- mode: 'direct' | 'fixedWorkstreamMode' | 'workstreamMode'
688
+ mode: 'direct' | 'fixedThreadMode' | 'threadMode'
708
689
  memoryBlock: string
709
690
  onAppendMemoryBlock: (value: string) => void
710
691
  extraMessages?: ChatMessage[]
@@ -715,9 +696,9 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
715
696
  orgId: orgRef,
716
697
  userId: userRef,
717
698
  userName: userName ?? 'there',
718
- workstreamId: workstreamRef,
699
+ threadId: threadRef,
719
700
  orgIdString,
720
- workstreamMode: workstream.mode,
701
+ threadType: thread.type,
721
702
  mode: toolParams.mode,
722
703
  linearInstalled,
723
704
  onboardingActive,
@@ -738,7 +719,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
738
719
  return {
739
720
  originalMessages,
740
721
  run: async (writer?: UIMessageStreamWriter<ChatMessage>) => {
741
- const executeRun = async (leaseAbortSignal?: AbortSignal): Promise<PreparedWorkstreamTurnResult | void> => {
722
+ const executeRun = async (leaseAbortSignal?: AbortSignal): Promise<PreparedThreadTurnResult | void> => {
742
723
  const agentIdentityOverrides = readRuntimeAgentIdentityOverrides(buildContextResult)
743
724
  const runTimer = lotaDebugLogger.timer('run')
744
725
  const serverRunId = Bun.randomUUIDv7()
@@ -751,7 +732,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
751
732
  }
752
733
  // Plan turns run without the chat lease — don't claim the active run slot.
753
734
  if (params.kind !== 'planTurn') {
754
- await workstreamService.setActiveTurn(workstreamRef, serverRunId, params.streamId ?? null)
735
+ await threadService.setActiveTurn(threadRef, serverRunId, params.streamId ?? null)
755
736
  chatRunRegistry.register(serverRunId, runAbort.controller)
756
737
  }
757
738
  runTimer.step('set-active-run+stream')
@@ -794,7 +775,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
794
775
  Date.now(),
795
776
  )
796
777
 
797
- await workstreamMessageService.upsertMessages({ workstreamId: workstreamRef, messages: [committed] })
778
+ await threadMessageService.upsertMessages({ threadId: threadRef, messages: [committed] })
798
779
  currentMessages = upsertChatHistoryMessage(currentMessages, committed)
799
780
  allAssistantMessages = upsertChatHistoryMessage(allAssistantMessages, committed)
800
781
  throwIfRunAborted()
@@ -804,8 +785,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
804
785
 
805
786
  const streamCtx: StreamAgentResponseContext = {
806
787
  turnHooks,
807
- workstream,
808
- workstreamRef,
788
+ thread,
789
+ threadRef,
809
790
  orgRef,
810
791
  userRef,
811
792
  userName,
@@ -825,7 +806,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
825
806
 
826
807
  const runVisibleAgent = async (runParams: {
827
808
  agentId: string
828
- mode: 'direct' | 'fixedWorkstreamMode' | 'workstreamMode'
809
+ mode: 'direct' | 'fixedThreadMode' | 'threadMode'
829
810
  skills?: string[]
830
811
  additionalInstructionSections?: string[]
831
812
  extraMessages?: ChatMessage[]
@@ -837,7 +818,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
837
818
  const visibleTimer = lotaDebugLogger.timer(`visible:${runParams.agentId}`)
838
819
  let runMemoryBlock = memoryBlock
839
820
  const includeExecutionPlanTools =
840
- runParams.includeExecutionPlanTools ?? runParams.mode !== 'fixedWorkstreamMode'
821
+ runParams.includeExecutionPlanTools ?? runParams.mode !== 'fixedThreadMode'
841
822
  const rawTools: ToolSet = {
842
823
  ...((await buildAgentTools(
843
824
  buildTurnToolParams({
@@ -889,7 +870,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
889
870
  inputSchema: PlanNodeResultSubmissionSchema,
890
871
  execute: async (result) =>
891
872
  await executionPlanService.submitPlanTurnResult({
892
- workstreamId: workstreamRef,
873
+ threadId: threadRef,
893
874
  runId: planTurn.runId,
894
875
  nodeId: planTurn.nodeId,
895
876
  emittedBy: planTurn.nodeSpec.owner.ref,
@@ -899,7 +880,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
899
880
 
900
881
  await runVisibleAgent({
901
882
  agentId: planTurn.nodeSpec.owner.ref,
902
- mode: workstream.mode === 'direct' ? 'direct' : 'workstreamMode',
883
+ mode: thread.type === 'default' ? 'direct' : 'threadMode',
903
884
  additionalInstructionSections: buildPlanTurnInstructionSections(planTurn),
904
885
  extraMessages: [buildPlanTurnPromptMessage(planTurn)],
905
886
  includeExecutionPlanTools: false,
@@ -908,16 +889,16 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
908
889
  metadataPatch: { trigger: 'plan-turn', planRunId: planTurn.runId, planNodeId: planTurn.nodeId },
909
890
  })
910
891
  } else {
911
- if (workstream.mode === 'direct') {
912
- if (!workstream.agentId) {
913
- throw new WorkstreamTurnError('Direct workstreams require an assigned agent.', 400)
892
+ if (thread.type === 'default') {
893
+ if (!thread.agentId) {
894
+ throw new ThreadTurnError('Direct threads require an assigned agent.', 400)
914
895
  }
915
- await runVisibleAgent({ agentId: workstream.agentId, mode: 'direct' })
896
+ await runVisibleAgent({ agentId: thread.agentId, mode: 'direct' })
916
897
  } else {
917
- // Multi-agent orchestration for group workstreams
918
- const wsMembers = (workstream as { members?: string[] }).members ?? []
898
+ // Multi-agent orchestration for group threads
899
+ const wsMembers = (thread as { members?: string[] }).members ?? []
919
900
  const members = wsMembers.length > 0 ? wsMembers : [...agentRoster]
920
- const fallbackAgentId = coreWorkstreamProfile?.config.agentId ?? defaultLeadAgentId
901
+ const fallbackAgentId = coreThreadProfile?.config.agentId ?? defaultLeadAgentId
921
902
  throwIfRunAborted()
922
903
  writeMultiAgentEvent(writer, { phase: 'routing', note: 'Routing this turn to the right agent.' })
923
904
 
@@ -926,8 +907,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
926
907
  .map((m) => `${m.role}: ${extractMessageText(m).slice(0, 200)}`)
927
908
  .join('\n')
928
909
 
929
- const triageResult = await triageWorkstreamMessage({
930
- workstreamTitle: workstream.title,
910
+ const triageResult = await triageThreadMessage({
911
+ threadTitle: thread.title,
931
912
  members,
932
913
  messageText,
933
914
  recentContext,
@@ -944,13 +925,13 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
944
925
  }
945
926
  // Multi-agent member protocol: be direct, focus on domain
946
927
  additionalSections.push(
947
- '<multi-agent-protocol>\nYou are responding as part of a multi-agent workstream. Focus on your domain expertise. Be direct and concise — another agent may follow up on different aspects.\n</multi-agent-protocol>',
928
+ '<multi-agent-protocol>\nYou are responding as part of a multi-agent thread. Focus on your domain expertise. Be direct and concise — another agent may follow up on different aspects.\n</multi-agent-protocol>',
948
929
  )
949
930
 
950
931
  return await runVisibleAgent({
951
932
  agentId,
952
- mode: 'workstreamMode',
953
- skills: coreWorkstreamProfile?.skills ? [...coreWorkstreamProfile.skills] : undefined,
933
+ mode: 'threadMode',
934
+ skills: coreThreadProfile?.skills ? [...coreThreadProfile.skills] : undefined,
954
935
  additionalInstructionSections: additionalSections,
955
936
  })
956
937
  }
@@ -973,7 +954,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
973
954
  while (respondedAgents.length < 3) {
974
955
  const lastResponseText = extractMessageText(lastResponse).slice(0, 500)
975
956
  const checkResult = await checkForNextAgent({
976
- workstreamTitle: workstream.title,
957
+ threadTitle: thread.title,
977
958
  members,
978
959
  messageText,
979
960
  respondedAgents,
@@ -990,7 +971,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
990
971
  phase: 'waiting-for-agent',
991
972
  agentId: checkResult.agentId,
992
973
  agentName: resolveRuntimeAgentDisplayName(agentIdentityOverrides, checkResult.agentId),
993
- note: checkResult.routingContext,
974
+ note: checkResult.routingContext ?? undefined,
994
975
  })
995
976
 
996
977
  // Insert hidden bridge message between agent turns
@@ -1006,15 +987,12 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
1006
987
  metadata: { hidden: true, createdAt: Date.now() } as MessageMetadata,
1007
988
  }
1008
989
  throwIfRunAborted()
1009
- await workstreamMessageService.upsertMessages({
1010
- workstreamId: workstreamRef,
1011
- messages: [bridgeMessage],
1012
- })
990
+ await threadMessageService.upsertMessages({ threadId: threadRef, messages: [bridgeMessage] })
1013
991
  currentMessages = upsertChatHistoryMessage(currentMessages, bridgeMessage)
1014
992
  throwIfRunAborted()
1015
993
 
1016
994
  lastResponse = await runGroupAgent(checkResult.agentId, {
1017
- routingContext: checkResult.routingContext,
995
+ routingContext: checkResult.routingContext ?? undefined,
1018
996
  })
1019
997
  respondedAgents.push(checkResult.agentId)
1020
998
  throwIfRunAborted()
@@ -1033,13 +1011,12 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
1033
1011
  }
1034
1012
  } finally {
1035
1013
  try {
1036
- const latestWorkstreamRecord = await workstreamService.getById(workstreamRef)
1014
+ const latestThreadRecord = await threadService.getById(threadRef)
1037
1015
 
1038
1016
  await finalizeTurnRun({
1039
1017
  serverRunId,
1040
- getEntity: async () => latestWorkstreamRecord,
1041
- getUncompactedMessages: (cursor) =>
1042
- workstreamMessageService.listMessagesAfterCursor(workstreamRef, cursor),
1018
+ getEntity: async () => latestThreadRecord,
1019
+ getUncompactedMessages: (cursor) => threadMessageService.listMessagesAfterCursor(threadRef, cursor),
1043
1020
  assessCompaction: (summaryText, messages) =>
1044
1021
  contextCompactionRuntime.shouldCompactHistory({
1045
1022
  summaryText,
@@ -1048,34 +1025,34 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
1048
1025
  }),
1049
1026
  enqueueCompaction: async () => {
1050
1027
  await enqueueContextCompaction({
1051
- domain: 'workstream',
1052
- entityId: workstreamIdString,
1028
+ domain: 'thread',
1029
+ entityId: threadIdString,
1053
1030
  contextSize: CONTEXT_WINDOW_TOKENS,
1054
1031
  })
1055
1032
  },
1056
1033
  unregisterRun: (runId) => chatRunRegistry.unregister(runId),
1057
1034
  clearActiveRunId: async (runId) => {
1058
- const activeStreamId = await workstreamService.getActiveStreamId(workstreamRef)
1059
- await workstreamService.clearActiveTurn(workstreamRef, { runId, streamId: activeStreamId })
1035
+ const activeStreamId = await threadService.getActiveStreamId(threadRef)
1036
+ await threadService.clearActiveTurn(threadRef, { runId, streamId: activeStreamId })
1060
1037
  },
1061
1038
  disposeAbort: () => runAbort.dispose(),
1062
1039
  activeStreamId: params.streamId,
1063
1040
  clearActiveStreamId: async (streamId) => {
1064
- const activeRunId = await workstreamService.getActiveRunId(workstreamRef)
1041
+ const activeRunId = await threadService.getActiveRunId(threadRef)
1065
1042
  if (!activeRunId) return
1066
- await workstreamService.clearActiveTurn(workstreamRef, { runId: activeRunId, streamId })
1043
+ await threadService.clearActiveTurn(threadRef, { runId: activeRunId, streamId })
1067
1044
  },
1068
1045
  })
1069
1046
 
1070
1047
  if (allAssistantMessages.length > 0 && shouldProcessPostRunSideEffects) {
1071
1048
  await runPostTurnSideEffects({
1072
- workstream,
1073
- workstreamRef,
1049
+ thread,
1050
+ threadRef,
1074
1051
  orgRef,
1075
1052
  userRef,
1076
1053
  userName,
1077
1054
  orgIdString,
1078
- workstreamIdString,
1055
+ threadIdString,
1079
1056
  onboardingActive,
1080
1057
  workspace,
1081
1058
  allAssistantMessages,
@@ -1084,9 +1061,9 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
1084
1061
  loadRecentHistory,
1085
1062
  listReadableUploads: () => listReadableUploads(),
1086
1063
  memoryBlock,
1087
- visibleWorkstreamAgentId,
1064
+ visibleThreadAgentId,
1088
1065
  defaultLeadAgentId,
1089
- latestWorkstreamRecord,
1066
+ latestThreadRecord,
1090
1067
  isUserTurn: params.kind === 'userTurn',
1091
1068
  agentDisplayNamesById: agentIdentityOverrides.displayNamesById,
1092
1069
  })
@@ -1094,20 +1071,20 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
1094
1071
 
1095
1072
  if (allAssistantMessages.length > 0 && params.kind !== 'planTurn') {
1096
1073
  await turnHooks.afterTurn?.({
1097
- workstream,
1098
- workstreamRef,
1074
+ thread,
1075
+ threadRef,
1099
1076
  orgRef,
1100
1077
  userRef,
1101
1078
  userName,
1102
1079
  onboardingActive,
1103
1080
  referenceUserMessage,
1104
1081
  assistantMessages: allAssistantMessages,
1105
- latestWorkstreamRecord,
1082
+ latestThreadRecord,
1106
1083
  context: buildContextResult,
1107
1084
  })
1108
1085
  }
1109
1086
  } catch (postRunError) {
1110
- aiLogger.error`Workstream post-run cleanup failed: ${postRunError}`
1087
+ aiLogger.error`Thread post-run cleanup failed: ${postRunError}`
1111
1088
  }
1112
1089
  }
1113
1090
  }
@@ -1123,7 +1100,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
1123
1100
  }
1124
1101
 
1125
1102
  try {
1126
- return await workstreamService.withActiveRunLease(workstreamRef, async (leaseAbortSignal) => {
1103
+ return await threadService.withActiveRunLease(threadRef, async (leaseAbortSignal) => {
1127
1104
  const runResult = await executeRun(leaseAbortSignal)
1128
1105
  if (runResult) {
1129
1106
  return runResult
@@ -1132,8 +1109,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
1132
1109
  return { inputMessageId: referenceUserMessage?.id, assistantMessages: [...allAssistantMessages] }
1133
1110
  })
1134
1111
  } catch (error) {
1135
- if (error instanceof ActiveWorkstreamRunConflictError) {
1136
- throw new WorkstreamTurnError(error.message, 409)
1112
+ if (error instanceof ActiveThreadRunConflictError) {
1113
+ throw new ThreadTurnError(error.message, 409)
1137
1114
  }
1138
1115
  throw error
1139
1116
  }