@lota-sdk/core 0.1.11 → 0.1.12

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 (95) hide show
  1. package/package.json +2 -87
  2. package/src/ai/index.ts +3 -0
  3. package/src/bifrost/index.ts +1 -0
  4. package/src/config/agent-defaults.ts +30 -7
  5. package/src/config/constants.ts +0 -9
  6. package/src/config/debug-logger.ts +43 -0
  7. package/src/config/index.ts +5 -0
  8. package/src/config/model-constants.ts +0 -3
  9. package/src/config/workstream-defaults.ts +4 -0
  10. package/src/db/cursor-pagination.ts +2 -2
  11. package/src/db/index.ts +10 -0
  12. package/src/db/memory.ts +9 -15
  13. package/src/document/index.ts +2 -0
  14. package/src/document/parsing.ts +0 -25
  15. package/src/embeddings/provider.ts +17 -8
  16. package/src/index.ts +15 -505
  17. package/src/queues/index.ts +10 -0
  18. package/src/redis/connection-accessor.ts +26 -0
  19. package/src/redis/connection.ts +1 -1
  20. package/src/redis/index.ts +9 -25
  21. package/src/redis/org-memory-lock.ts +1 -1
  22. package/src/redis/redis-lease-lock.ts +1 -1
  23. package/src/redis/stream-context.ts +12 -2
  24. package/src/runtime/agent-runtime-policy.ts +9 -5
  25. package/src/runtime/agent-stream-helpers.ts +6 -3
  26. package/src/runtime/agent-types.ts +1 -5
  27. package/src/runtime/approval-continuation.ts +9 -1
  28. package/src/runtime/chat-attachments.ts +1 -1
  29. package/src/runtime/chat-request-routing.ts +1 -1
  30. package/src/runtime/context-compaction-runtime.ts +2 -2
  31. package/src/runtime/context-compaction.ts +1 -1
  32. package/src/runtime/execution-plan.ts +1 -1
  33. package/src/runtime/index.ts +26 -0
  34. package/src/runtime/indexed-repositories-policy.ts +10 -10
  35. package/src/runtime/memory-pipeline.ts +0 -2
  36. package/src/runtime/runtime-config.ts +238 -0
  37. package/src/runtime/runtime-extensions.ts +3 -2
  38. package/src/runtime/runtime-worker-registry.ts +47 -0
  39. package/src/runtime/team-consultation-orchestrator.ts +9 -6
  40. package/src/runtime/team-consultation-prompts.ts +3 -2
  41. package/src/runtime/turn-lifecycle.ts +1 -1
  42. package/src/runtime/workstream-chat-helpers.ts +0 -54
  43. package/src/runtime/workstream-routing-policy.ts +3 -7
  44. package/src/runtime.ts +387 -0
  45. package/src/services/chat-attachments.service.ts +1 -1
  46. package/src/services/context-compaction.service.ts +1 -1
  47. package/src/services/execution-plan.service.ts +14 -16
  48. package/src/services/index.ts +14 -0
  49. package/src/services/learned-skill.service.ts +80 -37
  50. package/src/services/memory.service.ts +5 -4
  51. package/src/services/mutating-approval.service.ts +1 -1
  52. package/src/services/organization-member.service.ts +1 -1
  53. package/src/services/organization.service.ts +1 -1
  54. package/src/services/plan-approval.service.ts +2 -2
  55. package/src/services/plan-artifact.service.ts +2 -3
  56. package/src/services/plan-builder.service.ts +1 -1
  57. package/src/services/plan-checkpoint.service.ts +2 -2
  58. package/src/services/plan-compiler.service.ts +2 -2
  59. package/src/services/plan-executor.service.ts +10 -9
  60. package/src/services/plan-run.service.ts +2 -2
  61. package/src/services/plan-validator.service.ts +4 -4
  62. package/src/services/recent-activity-title.service.ts +1 -1
  63. package/src/services/recent-activity.service.ts +14 -16
  64. package/src/services/user.service.ts +2 -2
  65. package/src/services/workstream-message.service.ts +2 -3
  66. package/src/services/workstream-title.service.ts +1 -1
  67. package/src/services/workstream-turn-preparation.ts +105 -50
  68. package/src/services/workstream-turn.ts +14 -1
  69. package/src/services/workstream.service.ts +9 -9
  70. package/src/storage/attachment-parser.ts +1 -1
  71. package/src/storage/attachment-storage.service.ts +11 -10
  72. package/src/storage/generated-document-storage.service.ts +7 -6
  73. package/src/storage/index.ts +10 -0
  74. package/src/system-agents/delegated-agent-factory.ts +78 -29
  75. package/src/system-agents/index.ts +4 -0
  76. package/src/system-agents/recent-activity-title-refiner.agent.ts +38 -3
  77. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  78. package/src/system-agents/skill-extractor.agent.ts +1 -1
  79. package/src/system-agents/skill-manager.agent.ts +2 -4
  80. package/src/tools/execution-plan.tool.ts +2 -2
  81. package/src/tools/firecrawl-client.ts +2 -2
  82. package/src/tools/index.ts +12 -0
  83. package/src/tools/research-topic.tool.ts +1 -1
  84. package/src/tools/team-think.tool.ts +1 -1
  85. package/src/tools/user-questions.tool.ts +2 -2
  86. package/src/utils/index.ts +6 -0
  87. package/src/workers/bootstrap.ts +8 -16
  88. package/src/workers/index.ts +7 -0
  89. package/src/workers/regular-chat-memory-digest.runner.ts +1 -1
  90. package/src/workers/skill-extraction.runner.ts +1 -1
  91. package/src/workers/utils/{repo-indexer-chunker.ts → file-section-chunker.ts} +23 -52
  92. package/src/workers/utils/repo-structure-extractor.ts +2 -5
  93. package/src/workers/utils/repomix-file-sections.ts +42 -0
  94. package/src/config/env-shapes.ts +0 -121
  95. package/src/runtime/agent-contract.ts +0 -1
package/src/index.ts CHANGED
@@ -1,505 +1,15 @@
1
- import type { CoreWorkstreamProfile } from './config/agent-defaults'
2
- import type { LotaWorkstreamConfig } from './config/workstream-defaults'
3
- import { ensureRecordId } from './db/record-id'
4
- import type { SurrealDBService } from './db/service'
5
- import { TABLES } from './db/tables'
6
- import type { startContextCompactionWorker } from './queues/context-compaction.queue'
7
- import type {
8
- scheduleRecurringConsolidation,
9
- startMemoryConsolidationWorker,
10
- } from './queues/memory-consolidation.queue'
11
- import type { startPostChatMemoryWorker } from './queues/post-chat-memory.queue'
12
- import type { startRecentActivityTitleRefinementWorker } from './queues/recent-activity-title-refinement.queue'
13
- import type { startRegularChatMemoryDigestWorker } from './queues/regular-chat-memory-digest.queue'
14
- import type { startSkillExtractionWorker } from './queues/skill-extraction.queue'
15
- import type { startWorkstreamTitleGenerationWorker } from './queues/workstream-title-generation.queue'
16
- import type { RedisConnectionManager } from './redis/connection'
17
- import type { isApprovalContinuationRequest } from './runtime/approval-continuation'
18
- import type { routeWorkstreamChatMessages } from './runtime/chat-request-routing'
19
- import type { LotaPlugin } from './runtime/plugin-types'
20
- import type { LotaRuntimeAdapters, LotaRuntimeTurnHooks } from './runtime/runtime-extensions'
21
- import type { attachmentService } from './services/attachment.service'
22
- import type { documentChunkService } from './services/document-chunk.service'
23
- import type { executionPlanService } from './services/execution-plan.service'
24
- import type { memoryService } from './services/memory.service'
25
- import type { verifyMutatingApproval } from './services/mutating-approval.service'
26
- import type { organizationMemberService } from './services/organization-member.service'
27
- import type { organizationService } from './services/organization.service'
28
- import type { recentActivityTitleService } from './services/recent-activity-title.service'
29
- import type { recentActivityService } from './services/recent-activity.service'
30
- import type { userService } from './services/user.service'
31
- import type { workstreamMessageService } from './services/workstream-message.service'
32
- import type { workstreamTitleService } from './services/workstream-title.service'
33
- import type {
34
- createWorkstreamApprovalContinuationStream,
35
- createWorkstreamNativeToolApprovalStream,
36
- createWorkstreamTurnStream,
37
- runWorkstreamTurnInBackground,
38
- } from './services/workstream-turn'
39
- import type { workstreamService } from './services/workstream.service'
40
- import type { generatedDocumentStorageService } from './storage/generated-document-storage.service'
41
-
42
- export type LotaAgentFactoryRegistry = Record<string, (...args: unknown[]) => unknown>
43
-
44
- interface LotaRuntimeBuiltInWorkers {
45
- startContextCompactionWorker: typeof startContextCompactionWorker
46
- startMemoryConsolidationWorker: typeof startMemoryConsolidationWorker
47
- startPostChatMemoryWorker: typeof startPostChatMemoryWorker
48
- startRecentActivityTitleRefinementWorker: typeof startRecentActivityTitleRefinementWorker
49
- startRegularChatMemoryDigestWorker: typeof startRegularChatMemoryDigestWorker
50
- startSkillExtractionWorker: typeof startSkillExtractionWorker
51
- startWorkstreamTitleGenerationWorker: typeof startWorkstreamTitleGenerationWorker
52
- scheduleRecurringConsolidation: typeof scheduleRecurringConsolidation
53
- }
54
-
55
- type ArchiveSdkWorkstream = (
56
- workstreamId: Parameters<typeof workstreamService.updateStatus>[0],
57
- status?: 'archived',
58
- ) => ReturnType<typeof workstreamService.updateStatus>
59
-
60
- type UnarchiveSdkWorkstream = (
61
- workstreamId: Parameters<typeof workstreamService.updateStatus>[0],
62
- status?: 'regular',
63
- ) => ReturnType<typeof workstreamService.updateStatus>
64
-
65
- export interface LotaRuntimeConfig {
66
- database: { url: string; namespace: string; username: string; password: string }
67
- redis: { url: string }
68
- aiGateway: { url: string; key: string; admin?: string; pass?: string; embeddingModel?: string }
69
- s3: {
70
- endpoint: string
71
- bucket: string
72
- region?: string
73
- accessKeyId: string
74
- secretAccessKey: string
75
- attachmentUrlExpiresIn?: number
76
- }
77
- firecrawl: { apiKey: string; apiBaseUrl?: string }
78
- logging?: { level?: 'trace' | 'debug' | 'info' | 'warning' | 'error' | 'fatal' }
79
- memory?: { searchK?: number; embeddingCacheTtlSeconds?: number }
80
- workstreams?: LotaWorkstreamConfig
81
- backgroundProcessing?: {
82
- memoryExtractionFrequency?: number
83
- skillExtractionFrequency?: number
84
- memoryDigestFrequency?: number
85
- memoryConsolidationFrequency?: number
86
- }
87
-
88
- agents: {
89
- roster: readonly string[]
90
- displayNames: Record<string, string>
91
- shortDisplayNames?: Record<string, string>
92
- teamConsultParticipants: readonly string[]
93
- getCoreWorkstreamProfile?: (coreType: string) => CoreWorkstreamProfile
94
- createAgent?: LotaAgentFactoryRegistry
95
- buildAgentTools?: (...args: unknown[]) => unknown
96
- getAgentRuntimeConfig?: (...args: unknown[]) => unknown
97
- }
98
-
99
- toolProviders?: Record<string, unknown>
100
- extraSchemaFiles?: Array<string | URL>
101
- extraWorkers?: Record<string, unknown>
102
- pluginRuntime?: Record<string, LotaPlugin>
103
- runtimeAdapters?: LotaRuntimeAdapters
104
- turnHooks?: LotaRuntimeTurnHooks
105
- }
106
-
107
- export interface LotaRuntime {
108
- services: {
109
- database: SurrealDBService
110
- databaseService: SurrealDBService
111
- redis: RedisConnectionManager
112
- closeRedisConnection: () => Promise<void>
113
- attachmentService: typeof attachmentService
114
- documentChunkService: typeof documentChunkService
115
- generatedDocumentStorageService: typeof generatedDocumentStorageService
116
- memoryService: typeof memoryService
117
- verifyMutatingApproval: typeof verifyMutatingApproval
118
- organizationService: typeof organizationService
119
- organizationMemberService: typeof organizationMemberService
120
- userService: typeof userService
121
- recentActivityService: typeof recentActivityService
122
- recentActivityTitleService: typeof recentActivityTitleService
123
- executionPlanService: typeof executionPlanService
124
- workstreamMessageService: typeof workstreamMessageService
125
- workstreamService: typeof workstreamService
126
- workstreamTitleService: typeof workstreamTitleService
127
- createWorkstreamApprovalContinuationStream: typeof createWorkstreamApprovalContinuationStream
128
- createWorkstreamNativeToolApprovalStream: typeof createWorkstreamNativeToolApprovalStream
129
- createWorkstreamTurnStream: typeof createWorkstreamTurnStream
130
- isApprovalContinuationRequest: typeof isApprovalContinuationRequest
131
- runWorkstreamTurnInBackground: typeof runWorkstreamTurnInBackground
132
- }
133
- lota: {
134
- organizations: {
135
- create: typeof organizationService.createOrganization
136
- upsert: typeof organizationService.upsertOrganization
137
- get: typeof organizationService.getOrganization
138
- list: typeof organizationService.listOrganizations
139
- update: typeof organizationService.updateOrganization
140
- delete: typeof organizationService.deleteOrganization
141
- }
142
- users: {
143
- upsert: typeof userService.upsertUser
144
- get: typeof userService.getUser
145
- list: typeof userService.listUsers
146
- update: typeof userService.updateUser
147
- delete: typeof userService.deleteUser
148
- }
149
- memberships: {
150
- add: typeof organizationMemberService.addMembership
151
- listForOrganization: typeof organizationMemberService.listMembershipsForOrganization
152
- listForUser: typeof organizationMemberService.listMembershipsForUser
153
- remove: typeof organizationMemberService.removeMembership
154
- isMember: typeof organizationMemberService.isMember
155
- }
156
- workstreams: {
157
- create: typeof workstreamService.createWorkstream
158
- list: typeof workstreamService.listWorkstreams
159
- get: typeof workstreamService.getWorkstream
160
- update: typeof workstreamService.updateTitle
161
- archive: ArchiveSdkWorkstream
162
- unarchive: UnarchiveSdkWorkstream
163
- delete: typeof workstreamService.deleteWorkstream
164
- stop: typeof workstreamService.stopActiveRun
165
- listMessages: typeof workstreamMessageService.listMessageHistoryPage
166
- getMessage: (params: { workstreamId: string; messageId: string }) => Promise<unknown>
167
- sendMessage: (params: {
168
- workstreamId: string
169
- organizationId: string
170
- userId: string
171
- userName: string
172
- messages: Parameters<typeof routeWorkstreamChatMessages>[0]
173
- }) => Promise<Awaited<ReturnType<typeof createWorkstreamTurnStream>>>
174
- continueApproval: (params: {
175
- workstreamId: string
176
- organizationId: string
177
- userId: string
178
- userName: string
179
- messages: Parameters<typeof routeWorkstreamChatMessages>[0]
180
- }) => Promise<Awaited<ReturnType<typeof createWorkstreamApprovalContinuationStream>>>
181
- uploadAttachment: typeof attachmentService.uploadWorkstreamAttachment
182
- }
183
- }
184
- redis: {
185
- manager: RedisConnectionManager
186
- getConnection: () => ReturnType<RedisConnectionManager['getConnection']>
187
- getConnectionForBullMQ: () => ReturnType<RedisConnectionManager['getConnectionForBullMQ']>
188
- closeConnection: () => Promise<void>
189
- }
190
- workers: LotaRuntimeBuiltInWorkers & Record<string, unknown>
191
- schemaFiles: Array<string | URL>
192
- contributions: { envKeys: readonly string[]; schemaFiles: Array<string | URL> }
193
- config: LotaRuntimeConfig
194
- plugins: Record<string, LotaPlugin>
195
- connectPluginDatabases(): Promise<void>
196
- connect(): Promise<void>
197
- disconnect(): Promise<void>
198
- }
199
-
200
- export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntime> {
201
- const { lotaSdkEnvKeys, setEnv } = await import('./config/env-shapes')
202
- const { configureLogger } = await import('./config/logger')
203
- const { publishDatabaseBootstrap } = await import('./db/startup')
204
- const { computeSchemaFingerprint } = await import('./db/schema-fingerprint')
205
- const { LOTA_SDK_DATABASE_NAME } = await import('./db/sdk-database')
206
- const { SurrealDBService: SurrealDBServiceClass, setDatabaseService } = await import('./db/service')
207
- const { createRedisConnectionManager } = await import('./redis/connection')
208
- const { setRedisConnectionManager } = await import('./redis/index')
209
- const { configureAgents, configureAgentFactory } = await import('./config/agent-defaults')
210
- const { configureWorkstreams } = await import('./config/workstream-defaults')
211
- const { configureRuntimeExtensions } = await import('./runtime/runtime-extensions')
212
- const { routeWorkstreamChatMessages } = await import('./runtime/chat-request-routing')
213
- const { configureBackgroundProcessing } = await import('./config/background-processing')
214
- const { configureEmbeddingCache } = await import('./ai/embedding-cache')
215
-
216
- // Resolve config defaults
217
- const memory = {
218
- searchK: config.memory?.searchK ?? 6,
219
- embeddingCacheTtlSeconds: config.memory?.embeddingCacheTtlSeconds ?? 3600,
220
- }
221
- const backgroundProcessing = {
222
- memoryExtractionFrequency: config.backgroundProcessing?.memoryExtractionFrequency ?? 3,
223
- skillExtractionFrequency: config.backgroundProcessing?.skillExtractionFrequency ?? 5,
224
- memoryDigestFrequency: config.backgroundProcessing?.memoryDigestFrequency ?? 1,
225
- memoryConsolidationFrequency: config.backgroundProcessing?.memoryConsolidationFrequency ?? 10,
226
- }
227
-
228
- setEnv({
229
- AI_GATEWAY_URL: config.aiGateway.url,
230
- AI_GATEWAY_KEY: config.aiGateway.key,
231
- AI_GATEWAY_ADMIN: config.aiGateway.admin,
232
- AI_GATEWAY_PASS: config.aiGateway.pass,
233
- AI_EMBEDDING_MODEL: config.aiGateway.embeddingModel ?? 'openai/text-embedding-3-small',
234
- REDIS_URL: config.redis.url,
235
- LOG_LEVEL: config.logging?.level ?? 'info',
236
- S3_ENDPOINT: config.s3.endpoint,
237
- S3_BUCKET: config.s3.bucket,
238
- S3_REGION: config.s3.region ?? 'garage',
239
- S3_ACCESS_KEY_ID: config.s3.accessKeyId,
240
- S3_SECRET_ACCESS_KEY: config.s3.secretAccessKey,
241
- ATTACHMENT_URL_EXPIRES_IN: config.s3.attachmentUrlExpiresIn ?? 1800,
242
- FIRECRAWL_API_KEY: config.firecrawl.apiKey,
243
- FIRECRAWL_API_BASE_URL: config.firecrawl.apiBaseUrl,
244
- MEMORY_SEARCH_K: memory.searchK,
245
- })
246
-
247
- await configureLogger(config.logging?.level ?? 'info')
248
-
249
- const db = new SurrealDBServiceClass({
250
- url: config.database.url,
251
- namespace: config.database.namespace,
252
- database: LOTA_SDK_DATABASE_NAME,
253
- username: config.database.username,
254
- password: config.database.password,
255
- })
256
- setDatabaseService(db)
257
-
258
- const redisManager = createRedisConnectionManager({ url: config.redis.url })
259
- setRedisConnectionManager(redisManager)
260
- configureEmbeddingCache(redisManager.getConnection(), memory.embeddingCacheTtlSeconds)
261
- configureBackgroundProcessing(backgroundProcessing)
262
-
263
- configureAgents({
264
- roster: config.agents.roster,
265
- displayNames: config.agents.displayNames,
266
- shortDisplayNames: config.agents.shortDisplayNames,
267
- teamConsultParticipants: config.agents.teamConsultParticipants,
268
- getCoreWorkstreamProfile: config.agents.getCoreWorkstreamProfile,
269
- })
270
- configureWorkstreams({ agentRoster: config.agents.roster, config: config.workstreams })
271
-
272
- if (config.agents.createAgent || config.agents.buildAgentTools || config.agents.getAgentRuntimeConfig) {
273
- configureAgentFactory({
274
- createAgent: config.agents.createAgent ?? {},
275
- buildAgentTools: config.agents.buildAgentTools,
276
- getAgentRuntimeConfig: config.agents.getAgentRuntimeConfig,
277
- pluginRuntime: config.pluginRuntime,
278
- })
279
- }
280
-
281
- const { attachmentService } = await import('./services/attachment.service')
282
- const { documentChunkService } = await import('./services/document-chunk.service')
283
- const { recentActivityService } = await import('./services/recent-activity.service')
284
- const { recentActivityTitleService } = await import('./services/recent-activity-title.service')
285
- const { executionPlanService } = await import('./services/execution-plan.service')
286
- const { memoryService } = await import('./services/memory.service')
287
- const { verifyMutatingApproval } = await import('./services/mutating-approval.service')
288
- const { organizationMemberService } = await import('./services/organization-member.service')
289
- const { organizationService } = await import('./services/organization.service')
290
- const { userService } = await import('./services/user.service')
291
- const { workstreamMessageService } = await import('./services/workstream-message.service')
292
- const { workstreamService } = await import('./services/workstream.service')
293
- const { workstreamTitleService } = await import('./services/workstream-title.service')
294
- const {
295
- createWorkstreamApprovalContinuationStream,
296
- createWorkstreamNativeToolApprovalStream,
297
- createWorkstreamTurnStream,
298
- isApprovalContinuationRequest,
299
- runWorkstreamTurnInBackground,
300
- } = await import('./services/workstream-turn')
301
- const { generatedDocumentStorageService } = await import('./storage/generated-document-storage.service')
302
- const { startContextCompactionWorker } = await import('./queues/context-compaction.queue')
303
- const { scheduleRecurringConsolidation, startMemoryConsolidationWorker } =
304
- await import('./queues/memory-consolidation.queue')
305
- const { startPostChatMemoryWorker } = await import('./queues/post-chat-memory.queue')
306
- const { startRecentActivityTitleRefinementWorker } = await import('./queues/recent-activity-title-refinement.queue')
307
- const { startRegularChatMemoryDigestWorker } = await import('./queues/regular-chat-memory-digest.queue')
308
- const { startSkillExtractionWorker } = await import('./queues/skill-extraction.queue')
309
- const { startWorkstreamTitleGenerationWorker } = await import('./queues/workstream-title-generation.queue')
310
-
311
- configureRuntimeExtensions({
312
- adapters: config.runtimeAdapters,
313
- turnHooks: config.turnHooks,
314
- toolProviders: (config.toolProviders ?? {}) as never,
315
- extraWorkers: config.extraWorkers,
316
- })
317
-
318
- const pluginRuntime = config.pluginRuntime ?? {}
319
- const pluginContributions = Object.values(pluginRuntime).map((plugin) => plugin.contributions)
320
- const schemaFiles = [...getBuiltInSchemaFiles(), ...(config.extraSchemaFiles ?? [])]
321
- const hostContributionSchemaFiles = pluginContributions.flatMap((plugin) => plugin.schemaFiles)
322
- const contributionEnvKeys = [...lotaSdkEnvKeys, ...pluginContributions.flatMap((plugin) => plugin.envKeys)]
323
- const connectPluginDatabases = createPluginDatabaseConnector(pluginRuntime)
324
- const builtInWorkers = {
325
- startContextCompactionWorker,
326
- startMemoryConsolidationWorker,
327
- startPostChatMemoryWorker,
328
- startRecentActivityTitleRefinementWorker,
329
- startRegularChatMemoryDigestWorker,
330
- startSkillExtractionWorker,
331
- startWorkstreamTitleGenerationWorker,
332
- scheduleRecurringConsolidation,
333
- } satisfies LotaRuntimeBuiltInWorkers
334
-
335
- const lota = {
336
- organizations: {
337
- create: organizationService.createOrganization.bind(organizationService),
338
- upsert: organizationService.upsertOrganization.bind(organizationService),
339
- get: organizationService.getOrganization.bind(organizationService),
340
- list: organizationService.listOrganizations.bind(organizationService),
341
- update: organizationService.updateOrganization.bind(organizationService),
342
- delete: organizationService.deleteOrganization.bind(organizationService),
343
- },
344
- users: {
345
- upsert: userService.upsertUser.bind(userService),
346
- get: userService.getUser.bind(userService),
347
- list: userService.listUsers.bind(userService),
348
- update: userService.updateUser.bind(userService),
349
- delete: userService.deleteUser.bind(userService),
350
- },
351
- memberships: {
352
- add: organizationMemberService.addMembership.bind(organizationMemberService),
353
- listForOrganization: organizationMemberService.listMembershipsForOrganization.bind(organizationMemberService),
354
- listForUser: organizationMemberService.listMembershipsForUser.bind(organizationMemberService),
355
- remove: organizationMemberService.removeMembership.bind(organizationMemberService),
356
- isMember: organizationMemberService.isMember.bind(organizationMemberService),
357
- },
358
- workstreams: {
359
- create: workstreamService.createWorkstream.bind(workstreamService),
360
- list: workstreamService.listWorkstreams.bind(workstreamService),
361
- get: workstreamService.getWorkstream.bind(workstreamService),
362
- update: workstreamService.updateTitle.bind(workstreamService),
363
- archive: async (workstreamId, status = 'archived') => await workstreamService.updateStatus(workstreamId, status),
364
- unarchive: async (workstreamId, status = 'regular') => await workstreamService.updateStatus(workstreamId, status),
365
- delete: workstreamService.deleteWorkstream.bind(workstreamService),
366
- stop: workstreamService.stopActiveRun.bind(workstreamService),
367
- listMessages: workstreamMessageService.listMessageHistoryPage.bind(workstreamMessageService),
368
- getMessage: async ({ workstreamId, messageId }) => {
369
- const messages = await workstreamMessageService.listMessages(ensureRecordId(workstreamId, TABLES.WORKSTREAM))
370
- const message = messages.find((candidate) => candidate.id === messageId)
371
- if (!message) {
372
- throw new Error(`Workstream message not found: ${messageId}`)
373
- }
374
- return message
375
- },
376
- sendMessage: async ({ workstreamId, organizationId, userId, userName, messages }) => {
377
- const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
378
- const workstream = await workstreamService.getWorkstream(workstreamRef)
379
- const routed = routeWorkstreamChatMessages(messages)
380
- if (routed.kind !== 'turn') {
381
- throw new Error(routed.kind === 'invalid' ? routed.message : 'Expected a user turn payload.')
382
- }
383
-
384
- return await createWorkstreamTurnStream({
385
- workstream,
386
- workstreamRef,
387
- orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
388
- userRef: ensureRecordId(userId, TABLES.USER),
389
- userName,
390
- inputMessage: routed.inputMessage,
391
- })
392
- },
393
- continueApproval: async ({ workstreamId, organizationId, userId, userName, messages }) => {
394
- const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
395
- const workstream = await workstreamService.getWorkstream(workstreamRef)
396
- const routed = routeWorkstreamChatMessages(messages)
397
- if (routed.kind !== 'approval-continuation') {
398
- throw new Error(
399
- routed.kind === 'invalid' ? routed.message : 'Expected approval continuation messages payload.',
400
- )
401
- }
402
-
403
- return await createWorkstreamApprovalContinuationStream({
404
- workstream,
405
- workstreamRef,
406
- orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
407
- userRef: ensureRecordId(userId, TABLES.USER),
408
- userName,
409
- approvalMessages: routed.approvalMessages,
410
- })
411
- },
412
- uploadAttachment: attachmentService.uploadWorkstreamAttachment.bind(attachmentService),
413
- },
414
- } satisfies LotaRuntime['lota']
415
-
416
- return {
417
- services: {
418
- database: db,
419
- databaseService: db,
420
- redis: redisManager,
421
- closeRedisConnection: async () => await redisManager.closeConnection(),
422
- attachmentService,
423
- documentChunkService,
424
- generatedDocumentStorageService,
425
- memoryService,
426
- verifyMutatingApproval,
427
- organizationService,
428
- organizationMemberService,
429
- userService,
430
- recentActivityService,
431
- recentActivityTitleService,
432
- executionPlanService,
433
- workstreamMessageService,
434
- workstreamService,
435
- workstreamTitleService,
436
- createWorkstreamApprovalContinuationStream,
437
- createWorkstreamNativeToolApprovalStream,
438
- createWorkstreamTurnStream,
439
- isApprovalContinuationRequest,
440
- runWorkstreamTurnInBackground,
441
- },
442
- lota,
443
- redis: {
444
- manager: redisManager,
445
- getConnection: () => redisManager.getConnection(),
446
- getConnectionForBullMQ: () => redisManager.getConnectionForBullMQ(),
447
- closeConnection: async () => await redisManager.closeConnection(),
448
- },
449
- workers: { ...builtInWorkers, ...config.extraWorkers },
450
- schemaFiles,
451
- contributions: { envKeys: [...new Set(contributionEnvKeys)], schemaFiles: hostContributionSchemaFiles },
452
- config,
453
- plugins: pluginRuntime,
454
- async connectPluginDatabases() {
455
- await connectPluginDatabases()
456
- },
457
- async connect() {
458
- await db.connect()
459
- const bunFiles = schemaFiles.map((schemaFile) =>
460
- schemaFile instanceof URL ? Bun.file(schemaFile.pathname) : Bun.file(schemaFile),
461
- )
462
- await db.applySchemaAndMigrations(bunFiles)
463
- const schemaFingerprint = await computeSchemaFingerprint(schemaFiles)
464
- await publishDatabaseBootstrap({ databaseService: db, schemaFingerprint })
465
- },
466
- async disconnect() {
467
- await db.disconnect()
468
- await redisManager.closeConnection()
469
- },
470
- }
471
- }
472
-
473
- function getBuiltInSchemaFiles(): URL[] {
474
- return [
475
- new URL('../infrastructure/schema/00_identity.surql', import.meta.url),
476
- new URL('../infrastructure/schema/00_workstream.surql', import.meta.url),
477
- new URL('../infrastructure/schema/01_memory.surql', import.meta.url),
478
- new URL('../infrastructure/schema/02_execution_plan.surql', import.meta.url),
479
- new URL('../infrastructure/schema/03_learned_skill.surql', import.meta.url),
480
- new URL('../infrastructure/schema/05_recent_activity.surql', import.meta.url),
481
- new URL('../infrastructure/schema/04_runtime_bootstrap.surql', import.meta.url),
482
- ]
483
- }
484
-
485
- function createPluginDatabaseConnector(pluginRuntime: Record<string, LotaPlugin>): () => Promise<void> {
486
- return async () => {
487
- for (const plugin of Object.values(pluginRuntime)) {
488
- const services = plugin.services as Record<string, unknown>
489
- const connectDatabase = services.connectDatabase
490
- if (typeof connectDatabase !== 'function') {
491
- continue
492
- }
493
-
494
- await Reflect.apply(connectDatabase, services, [])
495
- }
496
- }
497
- }
498
-
499
- export type { CoreWorkstreamProfile } from './config/agent-defaults'
500
- export type { SurrealDBService } from './db/service'
501
- export type { RedisConnectionManager } from './redis/connection'
502
- export { createWorkstreamResumableContext } from './redis/stream-context'
503
- export type { LotaPlugin, LotaPluginContributions } from './runtime/plugin-types'
504
- export type { LotaRuntimeAdapters, LotaRuntimeTurnHooks } from './runtime/runtime-extensions'
505
- export { createLogHelloWorldTool } from './tools/log-hello-world.tool'
1
+ export * from './runtime'
2
+ export * from './ai'
3
+ export * from './bifrost'
4
+ export * from './config'
5
+ export * from './db'
6
+ export * from './document'
7
+ export * from './queues'
8
+ export * from './redis'
9
+ export * from './runtime/index'
10
+ export * from './services'
11
+ export * from './storage'
12
+ export * from './system-agents'
13
+ export * from './tools'
14
+ export * from './utils'
15
+ export * from './workers'
@@ -0,0 +1,10 @@
1
+ export * from './context-compaction.queue'
2
+ export * from './document-processor.queue'
3
+ export * from './memory-consolidation.queue'
4
+ export * from './post-chat-memory.queue'
5
+ export * from './recent-activity-title-refinement.queue'
6
+ export * from './regular-chat-memory-digest.config'
7
+ export * from './regular-chat-memory-digest.queue'
8
+ export * from './skill-extraction.config'
9
+ export * from './skill-extraction.queue'
10
+ export * from './workstream-title-generation.queue'
@@ -0,0 +1,26 @@
1
+ import type IORedis from 'ioredis'
2
+
3
+ export interface RedisConnectionAccessor {
4
+ getConnection(): IORedis
5
+ getConnectionForBullMQ(): IORedis
6
+ }
7
+
8
+ let redisManager: RedisConnectionAccessor | undefined
9
+
10
+ export function setRedisConnectionManager(manager: RedisConnectionAccessor): void {
11
+ redisManager = manager
12
+ }
13
+
14
+ export function getRedisConnection(): IORedis {
15
+ if (!redisManager) {
16
+ throw new Error('Redis connection manager not configured. Call setRedisConnectionManager() first.')
17
+ }
18
+ return redisManager.getConnection()
19
+ }
20
+
21
+ export function getRedisConnectionForBullMQ(): IORedis {
22
+ if (!redisManager) {
23
+ throw new Error('Redis connection manager not configured. Call setRedisConnectionManager() first.')
24
+ }
25
+ return redisManager.getConnectionForBullMQ()
26
+ }
@@ -10,7 +10,7 @@ export interface RedisConnectionLogger {
10
10
  error?: (message: string) => void
11
11
  }
12
12
 
13
- export interface CreateRedisConnectionManagerOptions {
13
+ interface CreateRedisConnectionManagerOptions {
14
14
  url: string
15
15
  redisOptions?: RedisOptions
16
16
  healthCheckIntervalMs?: number
@@ -1,30 +1,14 @@
1
- import type IORedis from 'ioredis'
2
-
3
1
  import { createRedisConnectionManager } from './connection'
4
2
  import type { RedisConnectionManager } from './connection'
3
+ export { DEFAULT_REDIS_OPTIONS, type RedisConnectionLogger } from './connection'
4
+ export {
5
+ getRedisConnection,
6
+ getRedisConnectionForBullMQ,
7
+ setRedisConnectionManager,
8
+ type RedisConnectionAccessor,
9
+ } from './connection-accessor'
10
+ export { withOrgMemoryLock } from './org-memory-lock'
11
+ export { createWorkstreamResumableContext } from './stream-context'
5
12
 
6
13
  export { createRedisConnectionManager }
7
14
  export type { RedisConnectionManager }
8
-
9
- let _redisManager: { getConnection(): IORedis; getConnectionForBullMQ(): IORedis } | undefined
10
-
11
- export function setRedisConnectionManager(manager: {
12
- getConnection(): IORedis
13
- getConnectionForBullMQ(): IORedis
14
- }): void {
15
- _redisManager = manager
16
- }
17
-
18
- export function getRedisConnection(): IORedis {
19
- if (!_redisManager) {
20
- throw new Error('Redis connection manager not configured. Call setRedisConnectionManager() first.')
21
- }
22
- return _redisManager.getConnection()
23
- }
24
-
25
- export function getRedisConnectionForBullMQ(): IORedis {
26
- if (!_redisManager) {
27
- throw new Error('Redis connection manager not configured. Call setRedisConnectionManager() first.')
28
- }
29
- return _redisManager.getConnectionForBullMQ()
30
- }
@@ -1,5 +1,5 @@
1
- import { getRedisConnection } from '.'
2
1
  import { serverLogger } from '../config/logger'
2
+ import { getRedisConnection } from './connection-accessor'
3
3
  import { withRedisLeaseLock } from './redis-lease-lock'
4
4
 
5
5
  const ORG_MEMORY_LOCK_PREFIX = 'lock:org-memory:org:'
@@ -11,7 +11,7 @@ interface RedisLeaseLockLogger {
11
11
  warn?: (message: string) => void
12
12
  }
13
13
 
14
- export interface RedisLeaseLockOptions {
14
+ interface RedisLeaseLockOptions {
15
15
  redis: IORedis
16
16
  lockKey: string
17
17
  lockTtlMs: number
@@ -2,7 +2,7 @@ import type { Redis } from 'ioredis'
2
2
  import type { Publisher, Subscriber } from 'resumable-stream/ioredis'
3
3
  import { createResumableStreamContext } from 'resumable-stream/ioredis'
4
4
 
5
- import { getRedisConnection } from './index'
5
+ import { getRedisConnection } from './connection-accessor'
6
6
 
7
7
  function toSubscriber(client: Redis): Subscriber {
8
8
  const handlers = new Map<string, (message: string) => void>()
@@ -34,11 +34,21 @@ function toPublisher(client: Redis): Publisher {
34
34
  }
35
35
  }
36
36
 
37
+ let sharedSubscriber: { client: Redis; subscriber: Subscriber } | undefined
38
+
39
+ function getSharedSubscriber(): Subscriber {
40
+ if (!sharedSubscriber) {
41
+ const client = getRedisConnection().duplicate()
42
+ sharedSubscriber = { client, subscriber: toSubscriber(client) }
43
+ }
44
+ return sharedSubscriber.subscriber
45
+ }
46
+
37
47
  export function createWorkstreamResumableContext() {
38
48
  const redis = getRedisConnection()
39
49
  return createResumableStreamContext({
40
50
  waitUntil: null,
41
- subscriber: toSubscriber(redis.duplicate()),
51
+ subscriber: getSharedSubscriber(),
42
52
  publisher: toPublisher(redis),
43
53
  })
44
54
  }