@lota-sdk/core 0.2.3 → 0.3.0

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 (102) hide show
  1. package/infrastructure/schema/00_identity.surql +2 -2
  2. package/infrastructure/schema/00_thread.surql +75 -0
  3. package/infrastructure/schema/02_execution_plan.surql +10 -11
  4. package/infrastructure/schema/10_autonomous_job.surql +3 -3
  5. package/package.json +2 -2
  6. package/src/ai/definitions.ts +1 -1
  7. package/src/config/agent-defaults.ts +5 -5
  8. package/src/config/index.ts +1 -1
  9. package/src/config/thread-defaults.ts +72 -0
  10. package/src/create-runtime.ts +89 -93
  11. package/src/db/tables.ts +3 -3
  12. package/src/db/{workstream-message-row.ts → thread-message-row.ts} +3 -3
  13. package/src/queues/context-compaction.queue.ts +6 -6
  14. package/src/queues/plan-agent-heartbeat.queue.ts +3 -3
  15. package/src/queues/post-chat-memory.queue.ts +1 -1
  16. package/src/queues/title-generation.queue.ts +10 -13
  17. package/src/redis/index.ts +1 -1
  18. package/src/redis/stream-context.ts +1 -1
  19. package/src/runtime/agent-identity-overrides.ts +1 -1
  20. package/src/runtime/agent-runtime-policy.ts +19 -21
  21. package/src/runtime/chat-request-routing.ts +1 -1
  22. package/src/runtime/context-compaction-constants.ts +1 -1
  23. package/src/runtime/context-compaction.ts +1 -1
  24. package/src/runtime/execution-plan.ts +1 -1
  25. package/src/runtime/index.ts +1 -1
  26. package/src/runtime/memory-digest-policy.ts +1 -1
  27. package/src/runtime/plugin-types.ts +1 -1
  28. package/src/runtime/post-turn-side-effects.ts +35 -35
  29. package/src/runtime/runtime-config.ts +12 -12
  30. package/src/runtime/runtime-extensions.ts +11 -11
  31. package/src/runtime/social-chat-agent-runner.ts +3 -3
  32. package/src/runtime/social-chat-history.ts +1 -1
  33. package/src/runtime/social-chat.ts +6 -6
  34. package/src/runtime/team-consultation-orchestrator.ts +1 -1
  35. package/src/runtime/{workstream-chat-helpers.ts → thread-chat-helpers.ts} +7 -7
  36. package/src/runtime/{workstream-plan-turn.ts → thread-plan-turn.ts} +11 -17
  37. package/src/runtime/{workstream-turn-context.ts → thread-turn-context.ts} +10 -10
  38. package/src/services/agent-activity.service.ts +39 -44
  39. package/src/services/agent-executor.service.ts +17 -19
  40. package/src/services/attachment.service.ts +4 -8
  41. package/src/services/autonomous-job.service.ts +29 -28
  42. package/src/services/context-compaction.service.ts +19 -29
  43. package/src/services/execution-plan.service.ts +58 -70
  44. package/src/services/global-orchestrator.service.ts +5 -5
  45. package/src/services/index.ts +6 -6
  46. package/src/services/memory.service.ts +1 -1
  47. package/src/services/monitoring-window.service.ts +2 -2
  48. package/src/services/mutating-approval.service.ts +7 -10
  49. package/src/services/node-workspace.service.ts +8 -7
  50. package/src/services/notification.service.ts +1 -1
  51. package/src/services/organization.service.ts +9 -9
  52. package/src/services/ownership-dispatcher.service.ts +13 -19
  53. package/src/services/plan-agent-heartbeat.service.ts +13 -13
  54. package/src/services/plan-agent-query.service.ts +7 -7
  55. package/src/services/plan-artifact.service.ts +1 -2
  56. package/src/services/plan-coordination.service.ts +4 -4
  57. package/src/services/plan-cycle.service.ts +7 -7
  58. package/src/services/plan-deadline.service.ts +4 -4
  59. package/src/services/plan-event-delivery.service.ts +8 -12
  60. package/src/services/plan-executor.service.ts +16 -37
  61. package/src/services/plan-run-data.ts +27 -8
  62. package/src/services/plan-run.service.ts +7 -9
  63. package/src/services/plan-scheduler.service.ts +4 -4
  64. package/src/services/plan-template.service.ts +2 -2
  65. package/src/services/plan-validator.service.ts +0 -11
  66. package/src/services/plugin-executor.service.ts +1 -1
  67. package/src/services/queue-job.service.ts +1 -1
  68. package/src/services/recent-activity-title.service.ts +1 -1
  69. package/src/services/recent-activity.service.ts +4 -4
  70. package/src/services/system-executor.service.ts +2 -2
  71. package/src/services/{workstream-message.service.ts → thread-message.service.ts} +72 -76
  72. package/src/services/thread-plan-registry.service.ts +22 -0
  73. package/src/services/thread-title.service.ts +39 -0
  74. package/src/services/{workstream-turn-preparation.service.ts → thread-turn-preparation.service.ts} +131 -143
  75. package/src/services/{workstream-turn.ts → thread-turn.ts} +27 -31
  76. package/src/services/thread.service.ts +707 -0
  77. package/src/services/thread.types.ts +17 -0
  78. package/src/storage/attachment-storage.service.ts +4 -4
  79. package/src/system-agents/index.ts +1 -1
  80. package/src/system-agents/memory.agent.ts +1 -1
  81. package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
  82. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  83. package/src/system-agents/researcher.agent.ts +3 -3
  84. package/src/system-agents/{workstream-router.agent.ts → thread-router.agent.ts} +21 -21
  85. package/src/system-agents/title-generator.agent.ts +8 -8
  86. package/src/tools/execution-plan.tool.ts +39 -40
  87. package/src/tools/memory-block.tool.ts +4 -4
  88. package/src/tools/research-topic.tool.ts +1 -0
  89. package/src/tools/search-web.tool.ts +1 -1
  90. package/src/tools/search.tool.ts +4 -4
  91. package/src/tools/team-think.tool.ts +9 -9
  92. package/src/workers/regular-chat-memory-digest.helpers.ts +1 -1
  93. package/src/workers/regular-chat-memory-digest.runner.ts +43 -43
  94. package/src/workers/skill-extraction.runner.ts +9 -13
  95. package/src/workers/utils/{workstream-message-query.ts → thread-message-query.ts} +21 -21
  96. package/infrastructure/schema/00_workstream.surql +0 -64
  97. package/src/config/workstream-defaults.ts +0 -72
  98. package/src/services/workstream-plan-registry.service.ts +0 -22
  99. package/src/services/workstream-title.service.ts +0 -42
  100. package/src/services/workstream.service.ts +0 -803
  101. package/src/services/workstream.types.ts +0 -17
  102. /package/src/services/{workstream-constants.ts → thread-constants.ts} +0 -0
@@ -4,7 +4,7 @@ import { configureEmbeddingCache } from './ai/embedding-cache'
4
4
  import { configureAgentFactory, configureAgents } from './config/agent-defaults'
5
5
  import { configureBackgroundProcessing } from './config/background-processing'
6
6
  import { configureLotaLogger } from './config/logger'
7
- import { configureWorkstreams } from './config/workstream-defaults'
7
+ import { configureThreads } from './config/thread-defaults'
8
8
  import { ensureRecordId } from './db/record-id'
9
9
  import { computeSchemaFingerprint } from './db/schema-fingerprint'
10
10
  import { LOTA_SDK_DATABASE_NAME } from './db/sdk-database'
@@ -17,7 +17,7 @@ import { createRedisConnectionManager } from './redis/connection'
17
17
  import { setRedisConnectionManager } from './redis/index'
18
18
  import { closeSharedSubscriber } from './redis/stream-context'
19
19
  import type { isApprovalContinuationRequest } from './runtime/approval-continuation'
20
- import { routeWorkstreamChatMessages } from './runtime/chat-request-routing'
20
+ import { routeThreadChatMessages } from './runtime/chat-request-routing'
21
21
  import { configureGraphDesigner } from './runtime/graph-designer'
22
22
  import type { LotaPlugin, SystemNodeExecutor } from './runtime/plugin-types'
23
23
  import { configureRuntimeConfig, LOTA_RUNTIME_ENV_KEYS, parseLotaRuntimeConfig } from './runtime/runtime-config'
@@ -57,41 +57,41 @@ import {
57
57
  socialChatHistoryService as socialChatHistoryServiceSingleton,
58
58
  } from './services/social-chat-history.service'
59
59
  import { getBuiltInSystemExecutors } from './services/system-executor.service'
60
- import type { userService } from './services/user.service'
61
- import { userService as userServiceSingleton } from './services/user.service'
62
- import type { workstreamMessageService } from './services/workstream-message.service'
63
- import { workstreamMessageService as workstreamMessageServiceSingleton } from './services/workstream-message.service'
64
- import type { workstreamTitleService } from './services/workstream-title.service'
65
- import { workstreamTitleService as workstreamTitleServiceSingleton } from './services/workstream-title.service'
60
+ import type { threadMessageService } from './services/thread-message.service'
61
+ import { threadMessageService as threadMessageServiceSingleton } from './services/thread-message.service'
62
+ import type { threadTitleService } from './services/thread-title.service'
63
+ import { threadTitleService as threadTitleServiceSingleton } from './services/thread-title.service'
66
64
  import type {
67
- createWorkstreamApprovalContinuationStream,
68
- createWorkstreamNativeToolApprovalStream,
69
- createWorkstreamTurnStream,
70
- runWorkstreamTurnInBackground,
65
+ createThreadApprovalContinuationStream,
66
+ createThreadNativeToolApprovalStream,
67
+ createThreadTurnStream,
68
+ runThreadTurnInBackground,
71
69
  triggerPlanNodeTurn,
72
- } from './services/workstream-turn'
70
+ } from './services/thread-turn'
73
71
  import {
74
- createWorkstreamApprovalContinuationStream as createWorkstreamApprovalContinuationStreamSingleton,
75
- createWorkstreamNativeToolApprovalStream as createWorkstreamNativeToolApprovalStreamSingleton,
76
- createWorkstreamTurnStream as createWorkstreamTurnStreamSingleton,
72
+ createThreadApprovalContinuationStream as createThreadApprovalContinuationStreamSingleton,
73
+ createThreadNativeToolApprovalStream as createThreadNativeToolApprovalStreamSingleton,
74
+ createThreadTurnStream as createThreadTurnStreamSingleton,
77
75
  isApprovalContinuationRequest as isApprovalContinuationRequestSingleton,
78
- runWorkstreamTurnInBackground as runWorkstreamTurnInBackgroundSingleton,
76
+ runThreadTurnInBackground as runThreadTurnInBackgroundSingleton,
79
77
  triggerPlanNodeTurn as triggerPlanNodeTurnSingleton,
80
- } from './services/workstream-turn'
81
- import type { workstreamService } from './services/workstream.service'
82
- import { workstreamService as workstreamServiceSingleton } from './services/workstream.service'
78
+ } from './services/thread-turn'
79
+ import type { threadService } from './services/thread.service'
80
+ import { threadService as threadServiceSingleton } from './services/thread.service'
81
+ import type { userService } from './services/user.service'
82
+ import { userService as userServiceSingleton } from './services/user.service'
83
83
  import type { generatedDocumentStorageService } from './storage/generated-document-storage.service'
84
84
  import { generatedDocumentStorageService as generatedDocumentStorageServiceSingleton } from './storage/generated-document-storage.service'
85
85
 
86
- type ArchiveSdkWorkstream = (
87
- workstreamId: Parameters<typeof workstreamServiceSingleton.updateStatus>[0],
86
+ type ArchiveSdkThread = (
87
+ threadId: Parameters<typeof threadServiceSingleton.updateStatus>[0],
88
88
  status?: 'archived',
89
- ) => ReturnType<typeof workstreamServiceSingleton.updateStatus>
89
+ ) => ReturnType<typeof threadServiceSingleton.updateStatus>
90
90
 
91
- type UnarchiveSdkWorkstream = (
92
- workstreamId: Parameters<typeof workstreamServiceSingleton.updateStatus>[0],
91
+ type UnarchiveSdkThread = (
92
+ threadId: Parameters<typeof threadServiceSingleton.updateStatus>[0],
93
93
  status?: 'regular',
94
- ) => ReturnType<typeof workstreamServiceSingleton.updateStatus>
94
+ ) => ReturnType<typeof threadServiceSingleton.updateStatus>
95
95
 
96
96
  let activeRuntimeToken: symbol | null = null
97
97
 
@@ -131,14 +131,14 @@ export interface LotaRuntime {
131
131
  socialChatHistoryService: typeof socialChatHistoryServiceSingleton
132
132
  executionPlanService: typeof executionPlanService
133
133
  planAgentQueryService: typeof planAgentQueryService
134
- workstreamMessageService: typeof workstreamMessageService
135
- workstreamService: typeof workstreamService
136
- workstreamTitleService: typeof workstreamTitleService
137
- createWorkstreamApprovalContinuationStream: typeof createWorkstreamApprovalContinuationStream
138
- createWorkstreamNativeToolApprovalStream: typeof createWorkstreamNativeToolApprovalStream
139
- createWorkstreamTurnStream: typeof createWorkstreamTurnStream
134
+ threadMessageService: typeof threadMessageService
135
+ threadService: typeof threadService
136
+ threadTitleService: typeof threadTitleService
137
+ createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
138
+ createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
139
+ createThreadTurnStream: typeof createThreadTurnStream
140
140
  isApprovalContinuationRequest: typeof isApprovalContinuationRequest
141
- runWorkstreamTurnInBackground: typeof runWorkstreamTurnInBackground
141
+ runThreadTurnInBackground: typeof runThreadTurnInBackground
142
142
  triggerPlanNodeTurn: typeof triggerPlanNodeTurn
143
143
  }
144
144
  lota: {
@@ -164,32 +164,32 @@ export interface LotaRuntime {
164
164
  remove: typeof organizationMemberServiceSingleton.removeMembership
165
165
  isMember: typeof organizationMemberServiceSingleton.isMember
166
166
  }
167
- workstreams: {
168
- create: typeof workstreamServiceSingleton.createWorkstream
169
- list: typeof workstreamServiceSingleton.listWorkstreams
170
- get: typeof workstreamServiceSingleton.getWorkstream
171
- update: typeof workstreamServiceSingleton.updateTitle
172
- archive: ArchiveSdkWorkstream
173
- unarchive: UnarchiveSdkWorkstream
174
- delete: typeof workstreamServiceSingleton.deleteWorkstream
175
- stop: typeof workstreamServiceSingleton.stopActiveRun
176
- listMessages: typeof workstreamMessageServiceSingleton.listMessageHistoryPage
177
- getMessage: (params: { workstreamId: string; messageId: string }) => Promise<ChatMessage>
167
+ threads: {
168
+ create: typeof threadServiceSingleton.createThread
169
+ list: typeof threadServiceSingleton.listThreads
170
+ get: typeof threadServiceSingleton.getThread
171
+ update: typeof threadServiceSingleton.updateTitle
172
+ archive: ArchiveSdkThread
173
+ unarchive: UnarchiveSdkThread
174
+ delete: typeof threadServiceSingleton.deleteThread
175
+ stop: typeof threadServiceSingleton.stopActiveRun
176
+ listMessages: typeof threadMessageServiceSingleton.listMessageHistoryPage
177
+ getMessage: (params: { threadId: string; messageId: string }) => Promise<ChatMessage>
178
178
  sendMessage: (params: {
179
- workstreamId: string
179
+ threadId: string
180
180
  organizationId: string
181
181
  userId: string
182
182
  userName: string
183
- messages: Parameters<typeof routeWorkstreamChatMessages>[0]
184
- }) => Promise<Awaited<ReturnType<typeof createWorkstreamTurnStream>>>
183
+ messages: Parameters<typeof routeThreadChatMessages>[0]
184
+ }) => Promise<Awaited<ReturnType<typeof createThreadTurnStream>>>
185
185
  continueApproval: (params: {
186
- workstreamId: string
186
+ threadId: string
187
187
  organizationId: string
188
188
  userId: string
189
189
  userName: string
190
- messages: Parameters<typeof routeWorkstreamChatMessages>[0]
191
- }) => Promise<Awaited<ReturnType<typeof createWorkstreamApprovalContinuationStream>>>
192
- uploadAttachment: typeof attachmentServiceSingleton.uploadWorkstreamAttachment
190
+ messages: Parameters<typeof routeThreadChatMessages>[0]
191
+ }) => Promise<Awaited<ReturnType<typeof createThreadApprovalContinuationStream>>>
192
+ uploadAttachment: typeof attachmentServiceSingleton.uploadThreadAttachment
193
193
  }
194
194
  }
195
195
  redis: {
@@ -253,7 +253,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
253
253
  descriptions: runtimeConfig.agents.descriptions,
254
254
  routerModelId: runtimeConfig.agents.routerModelId,
255
255
  teamConsultParticipants: runtimeConfig.agents.teamConsultParticipants,
256
- getCoreWorkstreamProfile: runtimeConfig.agents.getCoreWorkstreamProfile,
256
+ getCoreThreadProfile: runtimeConfig.agents.getCoreThreadProfile,
257
257
  })
258
258
  configureAgentFactory({
259
259
  createAgent: runtimeConfig.agents.createAgent,
@@ -261,7 +261,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
261
261
  getAgentRuntimeConfig: runtimeConfig.agents.getAgentRuntimeConfig,
262
262
  pluginRuntime: runtimeConfig.pluginRuntime,
263
263
  })
264
- configureWorkstreams({ agentRoster: runtimeConfig.agents.roster, config: runtimeConfig.workstreams })
264
+ configureThreads({ agentRoster: runtimeConfig.agents.roster, config: runtimeConfig.threads })
265
265
  configureNotificationService(runtimeConfig.notificationService ?? null)
266
266
  configureRuntimeExtensions({
267
267
  adapters: runtimeConfig.runtimeAdapters,
@@ -311,65 +311,61 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
311
311
  remove: organizationMemberServiceSingleton.removeMembership.bind(organizationMemberServiceSingleton),
312
312
  isMember: organizationMemberServiceSingleton.isMember.bind(organizationMemberServiceSingleton),
313
313
  },
314
- workstreams: {
315
- create: workstreamServiceSingleton.createWorkstream.bind(workstreamServiceSingleton),
316
- list: workstreamServiceSingleton.listWorkstreams.bind(workstreamServiceSingleton),
317
- get: workstreamServiceSingleton.getWorkstream.bind(workstreamServiceSingleton),
318
- update: workstreamServiceSingleton.updateTitle.bind(workstreamServiceSingleton),
319
- archive: async (workstreamId, status = 'archived') =>
320
- await workstreamServiceSingleton.updateStatus(workstreamId, status),
321
- unarchive: async (workstreamId, status = 'regular') =>
322
- await workstreamServiceSingleton.updateStatus(workstreamId, status),
323
- delete: workstreamServiceSingleton.deleteWorkstream.bind(workstreamServiceSingleton),
324
- stop: workstreamServiceSingleton.stopActiveRun.bind(workstreamServiceSingleton),
325
- listMessages: workstreamMessageServiceSingleton.listMessageHistoryPage.bind(workstreamMessageServiceSingleton),
326
- getMessage: async ({ workstreamId, messageId }) => {
327
- const messages = await workstreamMessageServiceSingleton.listMessages(
328
- ensureRecordId(workstreamId, TABLES.WORKSTREAM),
329
- )
314
+ threads: {
315
+ create: threadServiceSingleton.createThread.bind(threadServiceSingleton),
316
+ list: threadServiceSingleton.listThreads.bind(threadServiceSingleton),
317
+ get: threadServiceSingleton.getThread.bind(threadServiceSingleton),
318
+ update: threadServiceSingleton.updateTitle.bind(threadServiceSingleton),
319
+ archive: async (threadId, status = 'archived') => await threadServiceSingleton.updateStatus(threadId, status),
320
+ unarchive: async (threadId, status = 'regular') => await threadServiceSingleton.updateStatus(threadId, status),
321
+ delete: threadServiceSingleton.deleteThread.bind(threadServiceSingleton),
322
+ stop: threadServiceSingleton.stopActiveRun.bind(threadServiceSingleton),
323
+ listMessages: threadMessageServiceSingleton.listMessageHistoryPage.bind(threadMessageServiceSingleton),
324
+ getMessage: async ({ threadId, messageId }) => {
325
+ const messages = await threadMessageServiceSingleton.listMessages(ensureRecordId(threadId, TABLES.THREAD))
330
326
  const message = messages.find((candidate) => candidate.id === messageId)
331
327
  if (!message) {
332
- throw new Error(`Workstream message not found: ${messageId}`)
328
+ throw new Error(`Thread message not found: ${messageId}`)
333
329
  }
334
330
  return message
335
331
  },
336
- sendMessage: async ({ workstreamId, organizationId, userId, userName, messages }) => {
337
- const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
338
- const workstream = await workstreamServiceSingleton.getWorkstream(workstreamRef)
339
- const routed = routeWorkstreamChatMessages(messages)
332
+ sendMessage: async ({ threadId, organizationId, userId, userName, messages }) => {
333
+ const threadRef = ensureRecordId(threadId, TABLES.THREAD)
334
+ const thread = await threadServiceSingleton.getThread(threadRef)
335
+ const routed = routeThreadChatMessages(messages)
340
336
  if (routed.kind !== 'turn') {
341
337
  throw new Error(routed.kind === 'invalid' ? routed.message : 'Expected a user turn payload.')
342
338
  }
343
339
 
344
- return createWorkstreamTurnStreamSingleton({
345
- workstream,
346
- workstreamRef,
340
+ return createThreadTurnStreamSingleton({
341
+ thread,
342
+ threadRef,
347
343
  orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
348
344
  userRef: ensureRecordId(userId, TABLES.USER),
349
345
  userName,
350
346
  inputMessage: routed.inputMessage,
351
347
  })
352
348
  },
353
- continueApproval: async ({ workstreamId, organizationId, userId, userName, messages }) => {
354
- const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
355
- const workstream = await workstreamServiceSingleton.getWorkstream(workstreamRef)
356
- const routed = routeWorkstreamChatMessages(messages)
349
+ continueApproval: async ({ threadId, organizationId, userId, userName, messages }) => {
350
+ const threadRef = ensureRecordId(threadId, TABLES.THREAD)
351
+ const thread = await threadServiceSingleton.getThread(threadRef)
352
+ const routed = routeThreadChatMessages(messages)
357
353
  if (routed.kind !== 'approval-continuation') {
358
354
  throw new Error(
359
355
  routed.kind === 'invalid' ? routed.message : 'Expected approval continuation messages payload.',
360
356
  )
361
357
  }
362
358
 
363
- return createWorkstreamApprovalContinuationStreamSingleton({
364
- workstream,
365
- workstreamRef,
359
+ return createThreadApprovalContinuationStreamSingleton({
360
+ thread,
361
+ threadRef,
366
362
  orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
367
363
  userRef: ensureRecordId(userId, TABLES.USER),
368
364
  userName,
369
365
  approvalMessages: routed.approvalMessages,
370
366
  })
371
367
  },
372
- uploadAttachment: attachmentServiceSingleton.uploadWorkstreamAttachment.bind(attachmentServiceSingleton),
368
+ uploadAttachment: attachmentServiceSingleton.uploadThreadAttachment.bind(attachmentServiceSingleton),
373
369
  },
374
370
  } satisfies LotaRuntime['lota']
375
371
 
@@ -395,14 +391,14 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
395
391
  socialChatHistoryService: socialChatHistoryServiceSingleton,
396
392
  executionPlanService: executionPlanServiceSingleton,
397
393
  planAgentQueryService: planAgentQueryServiceSingleton,
398
- workstreamMessageService: workstreamMessageServiceSingleton,
399
- workstreamService: workstreamServiceSingleton,
400
- workstreamTitleService: workstreamTitleServiceSingleton,
401
- createWorkstreamApprovalContinuationStream: createWorkstreamApprovalContinuationStreamSingleton,
402
- createWorkstreamNativeToolApprovalStream: createWorkstreamNativeToolApprovalStreamSingleton,
403
- createWorkstreamTurnStream: createWorkstreamTurnStreamSingleton,
394
+ threadMessageService: threadMessageServiceSingleton,
395
+ threadService: threadServiceSingleton,
396
+ threadTitleService: threadTitleServiceSingleton,
397
+ createThreadApprovalContinuationStream: createThreadApprovalContinuationStreamSingleton,
398
+ createThreadNativeToolApprovalStream: createThreadNativeToolApprovalStreamSingleton,
399
+ createThreadTurnStream: createThreadTurnStreamSingleton,
404
400
  isApprovalContinuationRequest: isApprovalContinuationRequestSingleton,
405
- runWorkstreamTurnInBackground: runWorkstreamTurnInBackgroundSingleton,
401
+ runThreadTurnInBackground: runThreadTurnInBackgroundSingleton,
406
402
  triggerPlanNodeTurn: triggerPlanNodeTurnSingleton,
407
403
  },
408
404
  lota,
@@ -456,7 +452,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
456
452
  function getBuiltInSchemaFiles(): URL[] {
457
453
  return [
458
454
  new URL('../infrastructure/schema/00_identity.surql', import.meta.url),
459
- new URL('../infrastructure/schema/00_workstream.surql', import.meta.url),
455
+ new URL('../infrastructure/schema/00_thread.surql', import.meta.url),
460
456
  new URL('../infrastructure/schema/01_memory.surql', import.meta.url),
461
457
  new URL('../infrastructure/schema/02_execution_plan.surql', import.meta.url),
462
458
  new URL('../infrastructure/schema/03_learned_skill.surql', import.meta.url),
package/src/db/tables.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  export const TABLES = {
2
- WORKSTREAM_MESSAGE: 'workstreamMessage',
3
- WORKSTREAM: 'workstream',
2
+ THREAD: 'thread',
3
+ THREAD_MESSAGE: 'threadMessage',
4
+ THREAD_ATTACHMENT: 'threadAttachment',
4
5
  RUNTIME_BOOTSTRAP: 'runtimeBootstrap',
5
- WORKSTREAM_ATTACHMENT: 'workstreamAttachment',
6
6
  MEMORY: 'memory',
7
7
  MEMORY_RELATION: 'memoryRelation',
8
8
  MEMORY_HISTORY: 'memoryHistory',
@@ -1,9 +1,9 @@
1
1
  import { recordIdSchema } from '@lota-sdk/shared'
2
2
  import { z } from 'zod'
3
3
 
4
- export const WorkstreamMessageRowSchema = z.object({
4
+ export const ThreadMessageRowSchema = z.object({
5
5
  id: recordIdSchema,
6
- workstreamId: recordIdSchema,
6
+ threadId: recordIdSchema,
7
7
  messageId: z.string(),
8
8
  role: z.enum(['system', 'user', 'assistant']),
9
9
  parts: z.array(z.record(z.string(), z.unknown())).optional(),
@@ -12,4 +12,4 @@ export const WorkstreamMessageRowSchema = z.object({
12
12
  updatedAt: z.coerce.date().optional(),
13
13
  })
14
14
 
15
- export type WorkstreamMessageRow = z.infer<typeof WorkstreamMessageRowSchema>
15
+ export type ThreadMessageRow = z.infer<typeof ThreadMessageRowSchema>
@@ -4,11 +4,11 @@ import { ensureRecordId } from '../db/record-id'
4
4
  import { databaseService } from '../db/service'
5
5
  import { TABLES } from '../db/tables'
6
6
  import { contextCompactionService } from '../services/context-compaction.service'
7
- import { workstreamService } from '../services/workstream.service'
7
+ import { threadService } from '../services/thread.service'
8
8
  import { createQueueFactory } from './queue-factory'
9
9
 
10
10
  interface ContextCompactionJob {
11
- domain: 'workstream'
11
+ domain: 'thread'
12
12
  entityId: string
13
13
  contextSize?: number
14
14
  }
@@ -17,12 +17,12 @@ async function processContextCompactionJob(job: Job<ContextCompactionJob>): Prom
17
17
  await databaseService.connect()
18
18
 
19
19
  const { entityId, contextSize } = job.data
20
- const workstreamRef = ensureRecordId(entityId, TABLES.WORKSTREAM)
21
- await workstreamService.setCompacting(workstreamRef, true)
20
+ const threadRef = ensureRecordId(entityId, TABLES.THREAD)
21
+ await threadService.setCompacting(threadRef, true)
22
22
  try {
23
- await contextCompactionService.compactWorkstreamHistory({ workstreamId: workstreamRef, contextSize })
23
+ await contextCompactionService.compactThreadHistory({ threadId: threadRef, contextSize })
24
24
  } finally {
25
- await workstreamService.setCompacting(workstreamRef, false)
25
+ await threadService.setCompacting(threadRef, false)
26
26
  }
27
27
  }
28
28
 
@@ -10,7 +10,7 @@ import { createQueueFactory } from './queue-factory'
10
10
  export interface PlanAgentHeartbeatWakeJob {
11
11
  type: 'wake-node'
12
12
  organizationId: string
13
- workstreamId: string
13
+ threadId: string
14
14
  runId: string
15
15
  nodeId: string
16
16
  agentId: string
@@ -58,7 +58,7 @@ const planAgentHeartbeatQueue = createQueueFactory<PlanAgentHeartbeatJob>({
58
58
 
59
59
  function buildWakeJobId(params: {
60
60
  organizationId: string
61
- workstreamId: string
61
+ threadId: string
62
62
  runId: string
63
63
  nodeId: string
64
64
  agentId: string
@@ -70,7 +70,7 @@ function buildWakeJobId(params: {
70
70
 
71
71
  export async function enqueuePlanAgentHeartbeatWake(params: {
72
72
  organizationId: string
73
- workstreamId: string
73
+ threadId: string
74
74
  runId: string
75
75
  nodeId: string
76
76
  agentId: string
@@ -13,7 +13,7 @@ interface PostChatMemoryMessage {
13
13
 
14
14
  interface PostChatMemoryExtractionJob {
15
15
  orgId: string
16
- workstreamId: string
16
+ threadId: string
17
17
  sourceId: string
18
18
  source?: string
19
19
  sourceMetadata?: Record<string, unknown>
@@ -3,18 +3,18 @@ import type { Job } from 'bullmq'
3
3
  import { ensureRecordId } from '../db/record-id'
4
4
  import { databaseService } from '../db/service'
5
5
  import { recentActivityTitleService } from '../services/recent-activity-title.service'
6
- import { workstreamTitleService } from '../services/workstream-title.service'
6
+ import { threadTitleService } from '../services/thread-title.service'
7
7
  import { createQueueFactory } from './queue-factory'
8
8
 
9
9
  export const TITLE_GENERATION_QUEUE = 'title-generation'
10
10
 
11
- // This queue merges workstream title generation and recent-activity title
11
+ // This queue merges thread title generation and recent-activity title
12
12
  // refinement because both are short-lived title synthesis jobs with the same
13
13
  // operational shape.
14
14
 
15
- interface WorkstreamTitleGenerationJob {
16
- kind: 'workstream-title'
17
- workstreamId: string
15
+ interface ThreadTitleGenerationJob {
16
+ kind: 'thread-title'
17
+ threadId: string
18
18
  sourceText: string
19
19
  }
20
20
 
@@ -23,12 +23,12 @@ interface RecentActivityTitleRefinementJob {
23
23
  activityId: string
24
24
  }
25
25
 
26
- type TitleGenerationJob = WorkstreamTitleGenerationJob | RecentActivityTitleRefinementJob
26
+ type TitleGenerationJob = ThreadTitleGenerationJob | RecentActivityTitleRefinementJob
27
27
 
28
28
  async function processTitleGenerationJob(job: Job<TitleGenerationJob>): Promise<void> {
29
29
  await databaseService.connect()
30
- if (job.data.kind === 'workstream-title') {
31
- await workstreamTitleService.generateAndPersistTitle(ensureRecordId(job.data.workstreamId), job.data.sourceText)
30
+ if (job.data.kind === 'thread-title') {
31
+ await threadTitleService.generateAndPersistTitle(ensureRecordId(job.data.threadId), job.data.sourceText)
32
32
  return
33
33
  }
34
34
 
@@ -45,11 +45,8 @@ const titleGeneration = createQueueFactory<TitleGenerationJob>({
45
45
  processor: processTitleGenerationJob,
46
46
  })
47
47
 
48
- export function enqueueWorkstreamTitleGeneration(job: Omit<WorkstreamTitleGenerationJob, 'kind'>) {
49
- return titleGeneration.enqueue(
50
- { kind: 'workstream-title', ...job },
51
- { jobId: `workstream-title:${job.workstreamId}` },
52
- )
48
+ export function enqueueThreadTitleGeneration(job: Omit<ThreadTitleGenerationJob, 'kind'>) {
49
+ return titleGeneration.enqueue({ kind: 'thread-title', ...job }, { jobId: `thread-title:${job.threadId}` })
53
50
  }
54
51
 
55
52
  export function enqueueRecentActivityTitleRefinement(job: Omit<RecentActivityTitleRefinementJob, 'kind'>) {
@@ -9,7 +9,7 @@ export {
9
9
  } from './connection-accessor'
10
10
  export { withOrgMemoryLock } from './org-memory-lock'
11
11
  export { LeaseLockLostError, withRedisLeaseLock } from './redis-lease-lock'
12
- export { closeSharedSubscriber, createWorkstreamResumableContext } from './stream-context'
12
+ export { closeSharedSubscriber, createThreadResumableContext } from './stream-context'
13
13
 
14
14
  export { createRedisConnectionManager }
15
15
  export type { RedisConnectionManager }
@@ -55,7 +55,7 @@ export async function closeSharedSubscriber(): Promise<void> {
55
55
  }
56
56
  }
57
57
 
58
- export function createWorkstreamResumableContext() {
58
+ export function createThreadResumableContext() {
59
59
  const redis = getRedisConnection()
60
60
  return createResumableStreamContext({
61
61
  waitUntil: null,
@@ -1,5 +1,5 @@
1
1
  import { agentDisplayNames } from '../config/agent-defaults'
2
- import { asRecord, readOptionalString } from './workstream-chat-helpers'
2
+ import { asRecord, readOptionalString } from './thread-chat-helpers'
3
3
 
4
4
  interface RuntimeAgentIdentityOverrides {
5
5
  displayNamesById: Partial<Record<string, string>>
@@ -7,7 +7,7 @@ import type {
7
7
  } from '@lota-sdk/shared'
8
8
 
9
9
  import { getLeadAgentId } from '../config/agent-defaults'
10
- import { resolveOnboardingOwnerAgentId } from '../config/workstream-defaults'
10
+ import { resolveOnboardingOwnerAgentId } from '../config/thread-defaults'
11
11
  import type { ChatMode } from './agent-types'
12
12
  export interface AgentRuntimeConfig<TAgent extends string> {
13
13
  id: TAgent
@@ -73,15 +73,13 @@ function buildOwnershipDispatchArtifactPayload(artifacts: PlanArtifactSubmission
73
73
  return artifacts.map((artifact) => ({
74
74
  name: artifact.name,
75
75
  kind: artifact.kind,
76
- pointer: artifact.pointer,
77
- ...(artifact.schemaRef ? { schemaRef: artifact.schemaRef } : {}),
78
76
  ...(artifact.description ? { description: artifact.description } : {}),
79
77
  ...(artifact.payload !== undefined ? { payload: artifact.payload } : {}),
80
78
  }))
81
79
  }
82
80
 
83
- export function toChatMode(workstreamMode: 'direct' | 'group'): ChatMode {
84
- return workstreamMode === 'direct' ? 'fixedWorkstreamMode' : 'workstreamMode'
81
+ export function toChatMode(threadType: string): ChatMode {
82
+ return threadType === 'default' ? 'fixedThreadMode' : 'threadMode'
85
83
  }
86
84
 
87
85
  function toMemoryBlockSection(memoryBlock: string | undefined): string | undefined {
@@ -92,13 +90,13 @@ function toMemoryBlockSection(memoryBlock: string | undefined): string | undefin
92
90
 
93
91
  export function resolveActiveAgentSkills<TAgent extends string, TSkill extends PropertyKey>(params: {
94
92
  agentId: TAgent
95
- workstreamMode: 'direct' | 'group'
93
+ threadType: string
96
94
  mode?: ChatMode
97
95
  onboardingActive: boolean
98
96
  linearInstalled: boolean
99
97
  getAgentSkills: (agentId: TAgent, mode: ChatMode) => TSkill[]
100
98
  }): TSkill[] {
101
- const mode = params.mode ?? toChatMode(params.workstreamMode)
99
+ const mode = params.mode ?? toChatMode(params.threadType)
102
100
  return params
103
101
  .getAgentSkills(params.agentId, mode)
104
102
  .filter((skill) => (params.linearInstalled ? true : skill !== ('linear' as TSkill)))
@@ -107,7 +105,7 @@ export function resolveActiveAgentSkills<TAgent extends string, TSkill extends P
107
105
  export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends PropertyKey>(params: {
108
106
  agentId: TAgent
109
107
  displayNameByAgent: Record<TAgent, string>
110
- workstreamMode: 'direct' | 'group'
108
+ threadType: string
111
109
  mode?: ChatMode
112
110
  skills?: TSkill[]
113
111
  onboardingActive: boolean
@@ -115,7 +113,7 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
115
113
  systemWorkspaceDetails?: string
116
114
  preSeededMemoriesSection?: string
117
115
  retrievedKnowledgeSection?: string
118
- workstreamMemoryBlock?: string
116
+ threadMemoryBlock?: string
119
117
  responseGuardSection?: string
120
118
  learnedSkillsSection?: string
121
119
  additionalInstructionSections?: string[]
@@ -125,7 +123,7 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
125
123
  buildSkillInstructionSection: (skills: TSkill[]) => string
126
124
  buildOnboardingPromptSection: () => string
127
125
  }): AgentRuntimeConfig<TAgent> {
128
- const mode = params.mode ?? toChatMode(params.workstreamMode)
126
+ const mode = params.mode ?? toChatMode(params.threadType)
129
127
  const rulesSection = params.buildGlobalRuleInstructionSection(params.ruleOptions)
130
128
  const skillsSection =
131
129
  params.skills && params.skills.length > 0 ? params.buildSkillInstructionSection(params.skills) : ''
@@ -138,7 +136,7 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
138
136
  params.systemWorkspaceDetails?.trim(),
139
137
  params.preSeededMemoriesSection?.trim(),
140
138
  params.retrievedKnowledgeSection?.trim(),
141
- toMemoryBlockSection(params.workstreamMemoryBlock),
139
+ toMemoryBlockSection(params.threadMemoryBlock),
142
140
  ...(params.additionalInstructionSections?.map((section) => section.trim()) ?? []),
143
141
  params.responseGuardSection?.trim(),
144
142
  params.onboardingActive ? 'Onboarding is active. Keep responses onboarding-focused and concise.' : undefined,
@@ -154,9 +152,9 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
154
152
  }
155
153
  }
156
154
 
157
- export function buildWorkstreamAgentToolPolicy<TAgent extends string, TSkill extends PropertyKey>(params: {
155
+ export function buildThreadAgentToolPolicy<TAgent extends string, TSkill extends PropertyKey>(params: {
158
156
  agentId: TAgent
159
- workstreamMode: 'direct' | 'group'
157
+ threadType: string
160
158
  mode?: ChatMode
161
159
  onboardingActive: boolean
162
160
  linearInstalled: boolean
@@ -164,11 +162,11 @@ export function buildWorkstreamAgentToolPolicy<TAgent extends string, TSkill ext
164
162
  provideRepoTool: boolean
165
163
  getAgentSkills: (agentId: TAgent, mode: ChatMode) => TSkill[]
166
164
  }): AgentToolPolicy<TSkill> {
167
- const resolvedMode = params.mode ?? toChatMode(params.workstreamMode)
165
+ const resolvedMode = params.mode ?? toChatMode(params.threadType)
168
166
  const onboardingOwnerAgentId = resolveOnboardingOwnerAgentId(getLeadAgentId()) as TAgent
169
167
  const skills = resolveActiveAgentSkills({
170
168
  agentId: params.agentId,
171
- workstreamMode: params.workstreamMode,
169
+ threadType: params.threadType,
172
170
  mode: resolvedMode,
173
171
  onboardingActive: params.onboardingActive,
174
172
  linearInstalled: params.linearInstalled,
@@ -203,7 +201,7 @@ export function buildTeamConsultationAgentToolPolicy({
203
201
  provideRepoTool: boolean
204
202
  }): AgentToolPolicy<string> & { blockedToolNames: Set<string> } {
205
203
  return {
206
- resolvedMode: 'fixedWorkstreamMode',
204
+ resolvedMode: 'fixedThreadMode',
207
205
  skills: [],
208
206
  includeMemorySearch: false,
209
207
  includeConversationSearch: false,
@@ -249,9 +247,9 @@ export function buildOwnershipDispatchContextSection(params: {
249
247
  return [
250
248
  '<ownership-dispatch-execution>',
251
249
  'You are executing a single isolated execution-plan node.',
252
- 'Do not ask the user questions. Do not reference any hidden or prior workstream chat history.',
253
- 'Use only the provided node context, resolved input, input artifacts, and upstream handoff context.',
254
- 'Return only the final structured node result that satisfies the required output contract, including durable handoffContext for downstream nodes.',
250
+ 'Do not ask the user questions. Do not reference any hidden or prior thread chat history.',
251
+ 'Use only the provided node context, resolved input, input artifacts, and upstream summaries.',
252
+ 'Return only the final structured node result that satisfies the required output contract.',
255
253
  JSON.stringify(payload, null, 2),
256
254
  '</ownership-dispatch-execution>',
257
255
  ].join('\n')
@@ -268,14 +266,14 @@ export function buildOwnershipDispatchResponseGuard(params: {
268
266
  return [
269
267
  '<ownership-dispatch-result-contract>',
270
268
  'Return a single JSON object with this exact shape:',
271
- '{"structuredOutput"?: object, "artifacts": Array<{ "name": string, "kind": "json"|"markdown"|"file"|"external-ref"|"record", "pointer": string, "schemaRef"?: string, "description"?: string, "payload"?: object|array }>, "notes"?: string, "handoffContext"?: { "summary": string, "keyDecisions"?: string[], "openQuestions"?: string[], "risks"?: string[], "recommendations"?: string[], "references"?: string[] }}',
269
+ '{"notes": string, "structuredOutput"?: object, "artifacts": Array<{ "name": string, "kind": "json"|"markdown"|"file"|"external-ref"|"record", "description"?: string, "payload"?: object|array }>}',
272
270
  'Do not wrap the JSON in markdown or code fences.',
273
271
  `Node label: ${params.node.label}`,
274
272
  `Required deliverables: ${params.node.deliverables.length > 0 ? params.node.deliverables.map((item) => item.name).join(', ') : 'none'}`,
275
273
  ...(completionCheckHints.length > 0
276
274
  ? ['Structured output fields required by completion checks:', ...completionCheckHints]
277
275
  : []),
278
- 'If downstream nodes depend on this work, include handoffContext.',
276
+ 'notes is required. Include a concise summary of what was done, key decisions, and any context downstream nodes need.',
279
277
  '</ownership-dispatch-result-contract>',
280
278
  ].join('\n')
281
279
  }
@@ -8,7 +8,7 @@ export type RoutedChatRequest =
8
8
  | { kind: 'turn'; inputMessage: ChatMessage }
9
9
  | { kind: 'invalid'; message: string }
10
10
 
11
- export function routeWorkstreamChatMessages(messages: ChatMessage[]): RoutedChatRequest {
11
+ export function routeThreadChatMessages(messages: ChatMessage[]): RoutedChatRequest {
12
12
  if (isApprovalContinuationRequest(messages)) {
13
13
  if (isNativeToolApprovalRequest(messages)) {
14
14
  return { kind: 'native-tool-approval', messages }