@lota-sdk/core 0.1.5
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.
- package/infrastructure/schema/00_workstream.surql +55 -0
- package/infrastructure/schema/01_memory.surql +47 -0
- package/infrastructure/schema/02_execution_plan.surql +62 -0
- package/infrastructure/schema/03_learned_skill.surql +32 -0
- package/infrastructure/schema/04_runtime_bootstrap.surql +8 -0
- package/package.json +128 -0
- package/src/ai/definitions.ts +308 -0
- package/src/bifrost/bifrost.ts +256 -0
- package/src/config/agent-defaults.ts +99 -0
- package/src/config/constants.ts +33 -0
- package/src/config/env-shapes.ts +122 -0
- package/src/config/logger.ts +29 -0
- package/src/config/model-constants.ts +31 -0
- package/src/config/search.ts +17 -0
- package/src/config/workstream-defaults.ts +68 -0
- package/src/db/base.service.ts +55 -0
- package/src/db/cursor-pagination.ts +73 -0
- package/src/db/memory-query-builder.ts +207 -0
- package/src/db/memory-store.helpers.ts +118 -0
- package/src/db/memory-store.rows.ts +29 -0
- package/src/db/memory-store.ts +974 -0
- package/src/db/memory-types.ts +193 -0
- package/src/db/memory.ts +505 -0
- package/src/db/record-id.ts +78 -0
- package/src/db/service.ts +932 -0
- package/src/db/startup.ts +152 -0
- package/src/db/tables.ts +20 -0
- package/src/document/org-document-chunking.ts +224 -0
- package/src/document/parsing.ts +40 -0
- package/src/embeddings/provider.ts +76 -0
- package/src/index.ts +302 -0
- package/src/queues/context-compaction.queue.ts +82 -0
- package/src/queues/document-processor.queue.ts +118 -0
- package/src/queues/memory-consolidation.queue.ts +65 -0
- package/src/queues/post-chat-memory.queue.ts +128 -0
- package/src/queues/recent-activity-title-refinement.queue.ts +69 -0
- package/src/queues/regular-chat-memory-digest.config.ts +12 -0
- package/src/queues/regular-chat-memory-digest.queue.ts +73 -0
- package/src/queues/skill-extraction.config.ts +9 -0
- package/src/queues/skill-extraction.queue.ts +62 -0
- package/src/redis/connection.ts +176 -0
- package/src/redis/index.ts +30 -0
- package/src/redis/org-memory-lock.ts +43 -0
- package/src/redis/redis-lease-lock.ts +158 -0
- package/src/runtime/agent-contract.ts +1 -0
- package/src/runtime/agent-prompt-context.ts +119 -0
- package/src/runtime/agent-runtime-policy.ts +192 -0
- package/src/runtime/agent-stream-helpers.ts +117 -0
- package/src/runtime/agent-types.ts +22 -0
- package/src/runtime/approval-continuation.ts +16 -0
- package/src/runtime/chat-attachments.ts +46 -0
- package/src/runtime/chat-message.ts +10 -0
- package/src/runtime/chat-request-routing.ts +21 -0
- package/src/runtime/chat-run-orchestration.ts +25 -0
- package/src/runtime/chat-run-registry.ts +20 -0
- package/src/runtime/chat-types.ts +18 -0
- package/src/runtime/context-compaction-constants.ts +11 -0
- package/src/runtime/context-compaction-runtime.ts +86 -0
- package/src/runtime/context-compaction.ts +909 -0
- package/src/runtime/execution-plan.ts +59 -0
- package/src/runtime/helper-model.ts +405 -0
- package/src/runtime/indexed-repositories-policy.ts +28 -0
- package/src/runtime/instruction-sections.ts +8 -0
- package/src/runtime/llm-content.ts +71 -0
- package/src/runtime/memory-block.ts +264 -0
- package/src/runtime/memory-digest-policy.ts +14 -0
- package/src/runtime/memory-format.ts +8 -0
- package/src/runtime/memory-pipeline.ts +570 -0
- package/src/runtime/memory-prompts-fact.ts +47 -0
- package/src/runtime/memory-prompts-parse.ts +3 -0
- package/src/runtime/memory-prompts-update.ts +37 -0
- package/src/runtime/memory-scope.ts +43 -0
- package/src/runtime/plugin-types.ts +10 -0
- package/src/runtime/retrieval-adapters.ts +25 -0
- package/src/runtime/retrieval-pipeline.ts +3 -0
- package/src/runtime/runtime-extensions.ts +154 -0
- package/src/runtime/skill-extraction-policy.ts +3 -0
- package/src/runtime/team-consultation-orchestrator.ts +245 -0
- package/src/runtime/team-consultation-prompts.ts +32 -0
- package/src/runtime/title-helpers.ts +12 -0
- package/src/runtime/turn-lifecycle.ts +28 -0
- package/src/runtime/workstream-chat-helpers.ts +187 -0
- package/src/runtime/workstream-routing-policy.ts +301 -0
- package/src/runtime/workstream-state.ts +261 -0
- package/src/services/attachment.service.ts +159 -0
- package/src/services/chat-attachments.service.ts +17 -0
- package/src/services/chat-run-registry.service.ts +3 -0
- package/src/services/context-compaction-runtime.ts +13 -0
- package/src/services/context-compaction.service.ts +115 -0
- package/src/services/document-chunk.service.ts +141 -0
- package/src/services/execution-plan.service.ts +890 -0
- package/src/services/learned-skill.service.ts +328 -0
- package/src/services/memory-assessment.service.ts +43 -0
- package/src/services/memory.service.ts +807 -0
- package/src/services/memory.utils.ts +84 -0
- package/src/services/mutating-approval.service.ts +110 -0
- package/src/services/recent-activity-title.service.ts +74 -0
- package/src/services/recent-activity.service.ts +397 -0
- package/src/services/workstream-change-tracker.service.ts +313 -0
- package/src/services/workstream-message.service.ts +283 -0
- package/src/services/workstream-title.service.ts +58 -0
- package/src/services/workstream-turn-preparation.ts +1340 -0
- package/src/services/workstream-turn.ts +37 -0
- package/src/services/workstream.service.ts +854 -0
- package/src/services/workstream.types.ts +118 -0
- package/src/storage/attachment-parser.ts +101 -0
- package/src/storage/attachment-storage.service.ts +391 -0
- package/src/storage/attachments.types.ts +11 -0
- package/src/storage/attachments.utils.ts +58 -0
- package/src/storage/generated-document-storage.service.ts +55 -0
- package/src/system-agents/agent-result.ts +27 -0
- package/src/system-agents/context-compacter.agent.ts +46 -0
- package/src/system-agents/delegated-agent-factory.ts +177 -0
- package/src/system-agents/helper-agent-options.ts +20 -0
- package/src/system-agents/memory-reranker.agent.ts +38 -0
- package/src/system-agents/memory.agent.ts +58 -0
- package/src/system-agents/recent-activity-title-refiner.agent.ts +53 -0
- package/src/system-agents/regular-chat-memory-digest.agent.ts +75 -0
- package/src/system-agents/researcher.agent.ts +34 -0
- package/src/system-agents/skill-extractor.agent.ts +88 -0
- package/src/system-agents/skill-manager.agent.ts +80 -0
- package/src/system-agents/title-generator.agent.ts +42 -0
- package/src/system-agents/workstream-tracker.agent.ts +58 -0
- package/src/tools/execution-plan.tool.ts +163 -0
- package/src/tools/fetch-webpage.tool.ts +132 -0
- package/src/tools/firecrawl-client.ts +12 -0
- package/src/tools/memory-block.tool.ts +55 -0
- package/src/tools/read-file-parts.tool.ts +80 -0
- package/src/tools/remember-memory.tool.ts +85 -0
- package/src/tools/research-topic.tool.ts +15 -0
- package/src/tools/search-tools.ts +55 -0
- package/src/tools/search-web.tool.ts +175 -0
- package/src/tools/team-think.tool.ts +125 -0
- package/src/tools/tool-contract.ts +21 -0
- package/src/tools/user-questions.tool.ts +18 -0
- package/src/utils/async.ts +50 -0
- package/src/utils/date-time.ts +34 -0
- package/src/utils/error.ts +10 -0
- package/src/utils/errors.ts +28 -0
- package/src/utils/hono-error-handler.ts +71 -0
- package/src/utils/string.ts +51 -0
- package/src/workers/bootstrap.ts +44 -0
- package/src/workers/memory-consolidation.worker.ts +318 -0
- package/src/workers/regular-chat-memory-digest.helpers.ts +100 -0
- package/src/workers/regular-chat-memory-digest.runner.ts +363 -0
- package/src/workers/regular-chat-memory-digest.worker.ts +22 -0
- package/src/workers/skill-extraction.runner.ts +331 -0
- package/src/workers/skill-extraction.worker.ts +22 -0
- package/src/workers/utils/repo-indexer-chunker.ts +331 -0
- package/src/workers/utils/repo-structure-extractor.ts +645 -0
- package/src/workers/utils/repomix-process-concurrency.ts +65 -0
- package/src/workers/utils/sandbox-error.ts +5 -0
- package/src/workers/worker-utils.ts +182 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import type { CoreWorkstreamProfile } from './config/agent-defaults'
|
|
2
|
+
import type { LotaWorkstreamConfig } from './config/workstream-defaults'
|
|
3
|
+
import type { SurrealDBService } from './db/service'
|
|
4
|
+
import type { startContextCompactionWorker } from './queues/context-compaction.queue'
|
|
5
|
+
import type {
|
|
6
|
+
scheduleRecurringConsolidation,
|
|
7
|
+
startMemoryConsolidationWorker,
|
|
8
|
+
} from './queues/memory-consolidation.queue'
|
|
9
|
+
import type { startPostChatMemoryWorker } from './queues/post-chat-memory.queue'
|
|
10
|
+
import type { startRecentActivityTitleRefinementWorker } from './queues/recent-activity-title-refinement.queue'
|
|
11
|
+
import type { startRegularChatMemoryDigestWorker } from './queues/regular-chat-memory-digest.queue'
|
|
12
|
+
import type { startSkillExtractionWorker } from './queues/skill-extraction.queue'
|
|
13
|
+
import type { RedisConnectionManager } from './redis/connection'
|
|
14
|
+
import type { isApprovalContinuationRequest } from './runtime/approval-continuation'
|
|
15
|
+
import type { LotaPlugin } from './runtime/plugin-types'
|
|
16
|
+
import type { LotaRuntimeAdapters, LotaRuntimeTurnHooks } from './runtime/runtime-extensions'
|
|
17
|
+
import type { attachmentService } from './services/attachment.service'
|
|
18
|
+
import type { executionPlanService } from './services/execution-plan.service'
|
|
19
|
+
import type { memoryService } from './services/memory.service'
|
|
20
|
+
import type { verifyMutatingApproval } from './services/mutating-approval.service'
|
|
21
|
+
import type { recentActivityTitleService } from './services/recent-activity-title.service'
|
|
22
|
+
import type { recentActivityService } from './services/recent-activity.service'
|
|
23
|
+
import type { workstreamMessageService } from './services/workstream-message.service'
|
|
24
|
+
import type { workstreamTitleService } from './services/workstream-title.service'
|
|
25
|
+
import type {
|
|
26
|
+
createWorkstreamApprovalContinuationStream,
|
|
27
|
+
createWorkstreamTurnStream,
|
|
28
|
+
runWorkstreamTurnInBackground,
|
|
29
|
+
} from './services/workstream-turn'
|
|
30
|
+
import type { workstreamService } from './services/workstream.service'
|
|
31
|
+
import type { generatedDocumentStorageService } from './storage/generated-document-storage.service'
|
|
32
|
+
|
|
33
|
+
export type LotaAgentFactoryRegistry = Record<string, (...args: unknown[]) => unknown>
|
|
34
|
+
|
|
35
|
+
interface LotaRuntimeBuiltInWorkers {
|
|
36
|
+
startContextCompactionWorker: typeof startContextCompactionWorker
|
|
37
|
+
startMemoryConsolidationWorker: typeof startMemoryConsolidationWorker
|
|
38
|
+
startPostChatMemoryWorker: typeof startPostChatMemoryWorker
|
|
39
|
+
startRecentActivityTitleRefinementWorker: typeof startRecentActivityTitleRefinementWorker
|
|
40
|
+
startRegularChatMemoryDigestWorker: typeof startRegularChatMemoryDigestWorker
|
|
41
|
+
startSkillExtractionWorker: typeof startSkillExtractionWorker
|
|
42
|
+
scheduleRecurringConsolidation: typeof scheduleRecurringConsolidation
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface LotaRuntimeConfig {
|
|
46
|
+
database: { url: string; namespace: string; database: string; username: string; password: string }
|
|
47
|
+
redis: { url: string }
|
|
48
|
+
aiGateway: { url: string; key: string; admin?: string; pass?: string; embeddingModel?: string }
|
|
49
|
+
s3: {
|
|
50
|
+
endpoint: string
|
|
51
|
+
bucket: string
|
|
52
|
+
region?: string
|
|
53
|
+
accessKeyId: string
|
|
54
|
+
secretAccessKey: string
|
|
55
|
+
attachmentUrlExpiresIn?: number
|
|
56
|
+
}
|
|
57
|
+
firecrawl: { apiKey: string; apiBaseUrl?: string }
|
|
58
|
+
logging?: { level?: 'trace' | 'debug' | 'info' | 'warning' | 'error' | 'fatal' }
|
|
59
|
+
memory?: { searchK?: number }
|
|
60
|
+
workstreams?: LotaWorkstreamConfig
|
|
61
|
+
|
|
62
|
+
agents: {
|
|
63
|
+
roster: readonly string[]
|
|
64
|
+
displayNames: Record<string, string>
|
|
65
|
+
shortDisplayNames?: Record<string, string>
|
|
66
|
+
teamConsultParticipants: readonly string[]
|
|
67
|
+
getCoreWorkstreamProfile?: (coreType: string) => CoreWorkstreamProfile
|
|
68
|
+
createAgent?: LotaAgentFactoryRegistry
|
|
69
|
+
buildAgentTools?: (...args: unknown[]) => unknown
|
|
70
|
+
getAgentRuntimeConfig?: (...args: unknown[]) => unknown
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
toolProviders?: Record<string, unknown>
|
|
74
|
+
extraSchemaFiles?: Array<string | URL>
|
|
75
|
+
extraWorkers?: Record<string, unknown>
|
|
76
|
+
pluginRuntime?: Record<string, LotaPlugin>
|
|
77
|
+
runtimeAdapters?: LotaRuntimeAdapters
|
|
78
|
+
turnHooks?: LotaRuntimeTurnHooks
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface LotaRuntime {
|
|
82
|
+
services: {
|
|
83
|
+
database: SurrealDBService
|
|
84
|
+
databaseService: SurrealDBService
|
|
85
|
+
redis: RedisConnectionManager
|
|
86
|
+
closeRedisConnection: () => Promise<void>
|
|
87
|
+
attachmentService: typeof attachmentService
|
|
88
|
+
generatedDocumentStorageService: typeof generatedDocumentStorageService
|
|
89
|
+
memoryService: typeof memoryService
|
|
90
|
+
verifyMutatingApproval: typeof verifyMutatingApproval
|
|
91
|
+
recentActivityService: typeof recentActivityService
|
|
92
|
+
recentActivityTitleService: typeof recentActivityTitleService
|
|
93
|
+
executionPlanService: typeof executionPlanService
|
|
94
|
+
workstreamMessageService: typeof workstreamMessageService
|
|
95
|
+
workstreamService: typeof workstreamService
|
|
96
|
+
workstreamTitleService: typeof workstreamTitleService
|
|
97
|
+
createWorkstreamApprovalContinuationStream: typeof createWorkstreamApprovalContinuationStream
|
|
98
|
+
createWorkstreamTurnStream: typeof createWorkstreamTurnStream
|
|
99
|
+
isApprovalContinuationRequest: typeof isApprovalContinuationRequest
|
|
100
|
+
runWorkstreamTurnInBackground: typeof runWorkstreamTurnInBackground
|
|
101
|
+
}
|
|
102
|
+
redis: {
|
|
103
|
+
manager: RedisConnectionManager
|
|
104
|
+
getConnection: () => ReturnType<RedisConnectionManager['getConnection']>
|
|
105
|
+
getConnectionForBullMQ: () => ReturnType<RedisConnectionManager['getConnectionForBullMQ']>
|
|
106
|
+
closeConnection: () => Promise<void>
|
|
107
|
+
}
|
|
108
|
+
workers: LotaRuntimeBuiltInWorkers & Record<string, unknown>
|
|
109
|
+
schemaFiles: Array<string | URL>
|
|
110
|
+
contributions: { envKeys: readonly string[]; schemaFiles: Array<string | URL> }
|
|
111
|
+
config: LotaRuntimeConfig
|
|
112
|
+
plugins: Record<string, LotaPlugin>
|
|
113
|
+
connectPluginDatabases(): Promise<void>
|
|
114
|
+
connect(): Promise<void>
|
|
115
|
+
disconnect(): Promise<void>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntime> {
|
|
119
|
+
const { lotaSdkEnvKeys, setEnv } = await import('./config/env-shapes')
|
|
120
|
+
const { configureLogger } = await import('./config/logger')
|
|
121
|
+
const { SurrealDBService: SurrealDBServiceClass, setDatabaseService } = await import('./db/service')
|
|
122
|
+
const { createRedisConnectionManager } = await import('./redis/connection')
|
|
123
|
+
const { setRedisConnectionManager } = await import('./redis/index')
|
|
124
|
+
const { configureAgents, configureAgentFactory } = await import('./config/agent-defaults')
|
|
125
|
+
const { configureWorkstreams } = await import('./config/workstream-defaults')
|
|
126
|
+
const { configureRuntimeExtensions } = await import('./runtime/runtime-extensions')
|
|
127
|
+
|
|
128
|
+
setEnv({
|
|
129
|
+
AI_GATEWAY_URL: config.aiGateway.url,
|
|
130
|
+
AI_GATEWAY_KEY: config.aiGateway.key,
|
|
131
|
+
AI_GATEWAY_ADMIN: config.aiGateway.admin,
|
|
132
|
+
AI_GATEWAY_PASS: config.aiGateway.pass,
|
|
133
|
+
AI_EMBEDDING_MODEL: config.aiGateway.embeddingModel ?? 'openai/text-embedding-3-small',
|
|
134
|
+
REDIS_URL: config.redis.url,
|
|
135
|
+
LOG_LEVEL: config.logging?.level ?? 'info',
|
|
136
|
+
S3_ENDPOINT: config.s3.endpoint,
|
|
137
|
+
S3_BUCKET: config.s3.bucket,
|
|
138
|
+
S3_REGION: config.s3.region ?? 'garage',
|
|
139
|
+
S3_ACCESS_KEY_ID: config.s3.accessKeyId,
|
|
140
|
+
S3_SECRET_ACCESS_KEY: config.s3.secretAccessKey,
|
|
141
|
+
ATTACHMENT_URL_EXPIRES_IN: config.s3.attachmentUrlExpiresIn ?? 1800,
|
|
142
|
+
FIRECRAWL_API_KEY: config.firecrawl.apiKey,
|
|
143
|
+
FIRECRAWL_API_BASE_URL: config.firecrawl.apiBaseUrl,
|
|
144
|
+
MEMORY_SEARCH_K: config.memory?.searchK ?? 6,
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
await configureLogger(config.logging?.level ?? 'info')
|
|
148
|
+
|
|
149
|
+
const db = new SurrealDBServiceClass({
|
|
150
|
+
url: config.database.url,
|
|
151
|
+
namespace: config.database.namespace,
|
|
152
|
+
database: config.database.database,
|
|
153
|
+
username: config.database.username,
|
|
154
|
+
password: config.database.password,
|
|
155
|
+
})
|
|
156
|
+
setDatabaseService(db)
|
|
157
|
+
|
|
158
|
+
const redisManager = createRedisConnectionManager({ url: config.redis.url })
|
|
159
|
+
setRedisConnectionManager(redisManager)
|
|
160
|
+
|
|
161
|
+
configureAgents({
|
|
162
|
+
roster: config.agents.roster,
|
|
163
|
+
displayNames: config.agents.displayNames,
|
|
164
|
+
shortDisplayNames: config.agents.shortDisplayNames,
|
|
165
|
+
teamConsultParticipants: config.agents.teamConsultParticipants,
|
|
166
|
+
getCoreWorkstreamProfile: config.agents.getCoreWorkstreamProfile,
|
|
167
|
+
})
|
|
168
|
+
configureWorkstreams({ agentRoster: config.agents.roster, config: config.workstreams })
|
|
169
|
+
|
|
170
|
+
if (config.agents.createAgent || config.agents.buildAgentTools || config.agents.getAgentRuntimeConfig) {
|
|
171
|
+
configureAgentFactory({
|
|
172
|
+
createAgent: config.agents.createAgent ?? {},
|
|
173
|
+
buildAgentTools: config.agents.buildAgentTools,
|
|
174
|
+
getAgentRuntimeConfig: config.agents.getAgentRuntimeConfig,
|
|
175
|
+
pluginRuntime: config.pluginRuntime,
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const { attachmentService } = await import('./services/attachment.service')
|
|
180
|
+
const { recentActivityService } = await import('./services/recent-activity.service')
|
|
181
|
+
const { recentActivityTitleService } = await import('./services/recent-activity-title.service')
|
|
182
|
+
const { executionPlanService } = await import('./services/execution-plan.service')
|
|
183
|
+
const { memoryService } = await import('./services/memory.service')
|
|
184
|
+
const { verifyMutatingApproval } = await import('./services/mutating-approval.service')
|
|
185
|
+
const { workstreamMessageService } = await import('./services/workstream-message.service')
|
|
186
|
+
const { workstreamService } = await import('./services/workstream.service')
|
|
187
|
+
const { workstreamTitleService } = await import('./services/workstream-title.service')
|
|
188
|
+
const {
|
|
189
|
+
createWorkstreamApprovalContinuationStream,
|
|
190
|
+
createWorkstreamTurnStream,
|
|
191
|
+
isApprovalContinuationRequest,
|
|
192
|
+
runWorkstreamTurnInBackground,
|
|
193
|
+
} = await import('./services/workstream-turn')
|
|
194
|
+
const { generatedDocumentStorageService } = await import('./storage/generated-document-storage.service')
|
|
195
|
+
const { startContextCompactionWorker } = await import('./queues/context-compaction.queue')
|
|
196
|
+
const { scheduleRecurringConsolidation, startMemoryConsolidationWorker } =
|
|
197
|
+
await import('./queues/memory-consolidation.queue')
|
|
198
|
+
const { startPostChatMemoryWorker } = await import('./queues/post-chat-memory.queue')
|
|
199
|
+
const { startRecentActivityTitleRefinementWorker } = await import('./queues/recent-activity-title-refinement.queue')
|
|
200
|
+
const { startRegularChatMemoryDigestWorker } = await import('./queues/regular-chat-memory-digest.queue')
|
|
201
|
+
const { startSkillExtractionWorker } = await import('./queues/skill-extraction.queue')
|
|
202
|
+
|
|
203
|
+
configureRuntimeExtensions({
|
|
204
|
+
adapters: config.runtimeAdapters,
|
|
205
|
+
turnHooks: config.turnHooks,
|
|
206
|
+
toolProviders: (config.toolProviders ?? {}) as never,
|
|
207
|
+
extraWorkers: config.extraWorkers,
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
const pluginRuntime = config.pluginRuntime ?? {}
|
|
211
|
+
const pluginContributions = Object.values(pluginRuntime).map((plugin) => plugin.contributions)
|
|
212
|
+
const schemaFiles = [
|
|
213
|
+
...getBuiltInSchemaFiles(),
|
|
214
|
+
...pluginContributions.flatMap((plugin) => plugin.schemaFiles),
|
|
215
|
+
...(config.extraSchemaFiles ?? []),
|
|
216
|
+
]
|
|
217
|
+
const contributionEnvKeys = [...lotaSdkEnvKeys, ...pluginContributions.flatMap((plugin) => plugin.envKeys)]
|
|
218
|
+
const connectPluginDatabases = createPluginDatabaseConnector(pluginRuntime)
|
|
219
|
+
const builtInWorkers = {
|
|
220
|
+
startContextCompactionWorker,
|
|
221
|
+
startMemoryConsolidationWorker,
|
|
222
|
+
startPostChatMemoryWorker,
|
|
223
|
+
startRecentActivityTitleRefinementWorker,
|
|
224
|
+
startRegularChatMemoryDigestWorker,
|
|
225
|
+
startSkillExtractionWorker,
|
|
226
|
+
scheduleRecurringConsolidation,
|
|
227
|
+
} satisfies LotaRuntimeBuiltInWorkers
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
services: {
|
|
231
|
+
database: db,
|
|
232
|
+
databaseService: db,
|
|
233
|
+
redis: redisManager,
|
|
234
|
+
closeRedisConnection: async () => await redisManager.closeConnection(),
|
|
235
|
+
attachmentService,
|
|
236
|
+
generatedDocumentStorageService,
|
|
237
|
+
memoryService,
|
|
238
|
+
verifyMutatingApproval,
|
|
239
|
+
recentActivityService,
|
|
240
|
+
recentActivityTitleService,
|
|
241
|
+
executionPlanService,
|
|
242
|
+
workstreamMessageService,
|
|
243
|
+
workstreamService,
|
|
244
|
+
workstreamTitleService,
|
|
245
|
+
createWorkstreamApprovalContinuationStream,
|
|
246
|
+
createWorkstreamTurnStream,
|
|
247
|
+
isApprovalContinuationRequest,
|
|
248
|
+
runWorkstreamTurnInBackground,
|
|
249
|
+
},
|
|
250
|
+
redis: {
|
|
251
|
+
manager: redisManager,
|
|
252
|
+
getConnection: () => redisManager.getConnection(),
|
|
253
|
+
getConnectionForBullMQ: () => redisManager.getConnectionForBullMQ(),
|
|
254
|
+
closeConnection: async () => await redisManager.closeConnection(),
|
|
255
|
+
},
|
|
256
|
+
workers: { ...builtInWorkers, ...config.extraWorkers },
|
|
257
|
+
schemaFiles,
|
|
258
|
+
contributions: { envKeys: [...new Set(contributionEnvKeys)], schemaFiles },
|
|
259
|
+
config,
|
|
260
|
+
plugins: pluginRuntime,
|
|
261
|
+
async connectPluginDatabases() {
|
|
262
|
+
await connectPluginDatabases()
|
|
263
|
+
},
|
|
264
|
+
async connect() {
|
|
265
|
+
await db.connect()
|
|
266
|
+
},
|
|
267
|
+
async disconnect() {
|
|
268
|
+
await db.disconnect()
|
|
269
|
+
await redisManager.closeConnection()
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function getBuiltInSchemaFiles(): URL[] {
|
|
275
|
+
return [
|
|
276
|
+
new URL('../infrastructure/schema/00_workstream.surql', import.meta.url),
|
|
277
|
+
new URL('../infrastructure/schema/01_memory.surql', import.meta.url),
|
|
278
|
+
new URL('../infrastructure/schema/02_execution_plan.surql', import.meta.url),
|
|
279
|
+
new URL('../infrastructure/schema/03_learned_skill.surql', import.meta.url),
|
|
280
|
+
new URL('../infrastructure/schema/04_runtime_bootstrap.surql', import.meta.url),
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function createPluginDatabaseConnector(pluginRuntime: Record<string, LotaPlugin>): () => Promise<void> {
|
|
285
|
+
return async () => {
|
|
286
|
+
for (const plugin of Object.values(pluginRuntime)) {
|
|
287
|
+
const services = plugin.services as Record<string, unknown>
|
|
288
|
+
const connectDatabase = services.connectDatabase
|
|
289
|
+
if (typeof connectDatabase !== 'function') {
|
|
290
|
+
continue
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
await Reflect.apply(connectDatabase, services, [])
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export type { CoreWorkstreamProfile } from './config/agent-defaults'
|
|
299
|
+
export type { SurrealDBService } from './db/service'
|
|
300
|
+
export type { RedisConnectionManager } from './redis/connection'
|
|
301
|
+
export type { LotaPlugin, LotaPluginContributions } from './runtime/plugin-types'
|
|
302
|
+
export type { LotaRuntimeAdapters, LotaRuntimeTurnHooks } from './runtime/runtime-extensions'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Queue, Worker } from 'bullmq'
|
|
2
|
+
import type { Job } from 'bullmq'
|
|
3
|
+
|
|
4
|
+
import { serverLogger } from '../config/logger'
|
|
5
|
+
import { ensureRecordId } from '../db/record-id'
|
|
6
|
+
import { databaseService } from '../db/service'
|
|
7
|
+
import { TABLES } from '../db/tables'
|
|
8
|
+
import { getRedisConnectionForBullMQ } from '../redis'
|
|
9
|
+
import { contextCompactionService } from '../services/context-compaction.service'
|
|
10
|
+
import { workstreamService } from '../services/workstream.service'
|
|
11
|
+
import {
|
|
12
|
+
attachWorkerEvents,
|
|
13
|
+
createTracedWorkerProcessor,
|
|
14
|
+
createWorkerShutdown,
|
|
15
|
+
registerShutdownSignals,
|
|
16
|
+
} from '../workers/worker-utils'
|
|
17
|
+
import type { WorkerHandle } from '../workers/worker-utils'
|
|
18
|
+
|
|
19
|
+
interface ContextCompactionJob {
|
|
20
|
+
domain: 'workstream'
|
|
21
|
+
entityId: string
|
|
22
|
+
contextSize?: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const CONTEXT_COMPACTION_QUEUE = 'context-compaction'
|
|
26
|
+
|
|
27
|
+
let _contextCompactionQueue: Queue<ContextCompactionJob> | null = null
|
|
28
|
+
function getContextCompactionQueue(): Queue<ContextCompactionJob> {
|
|
29
|
+
if (!_contextCompactionQueue) {
|
|
30
|
+
_contextCompactionQueue = new Queue<ContextCompactionJob>(CONTEXT_COMPACTION_QUEUE, {
|
|
31
|
+
connection: getRedisConnectionForBullMQ(),
|
|
32
|
+
defaultJobOptions: {
|
|
33
|
+
removeOnComplete: 200,
|
|
34
|
+
removeOnFail: 200,
|
|
35
|
+
attempts: 2,
|
|
36
|
+
backoff: { type: 'exponential', delay: 3_000 },
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
return _contextCompactionQueue
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function enqueueContextCompaction(job: ContextCompactionJob) {
|
|
44
|
+
return await getContextCompactionQueue().add('compact', job, {
|
|
45
|
+
deduplication: { id: `compact:${job.domain}:${job.entityId}` },
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function processContextCompactionJob(job: Job<ContextCompactionJob>): Promise<void> {
|
|
50
|
+
await databaseService.connect()
|
|
51
|
+
|
|
52
|
+
const { entityId, contextSize } = job.data
|
|
53
|
+
const workstreamRef = ensureRecordId(entityId, TABLES.WORKSTREAM)
|
|
54
|
+
await workstreamService.setCompacting(workstreamRef, true)
|
|
55
|
+
try {
|
|
56
|
+
await contextCompactionService.compactWorkstreamHistory({ workstreamId: workstreamRef, contextSize })
|
|
57
|
+
} finally {
|
|
58
|
+
await workstreamService.setCompacting(workstreamRef, false)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function startContextCompactionWorker(options: { registerSignals?: boolean } = {}): WorkerHandle {
|
|
63
|
+
const { registerSignals = import.meta.main } = options
|
|
64
|
+
const worker = new Worker(
|
|
65
|
+
CONTEXT_COMPACTION_QUEUE,
|
|
66
|
+
createTracedWorkerProcessor(CONTEXT_COMPACTION_QUEUE, processContextCompactionJob),
|
|
67
|
+
{ connection: getRedisConnectionForBullMQ(), concurrency: 2, lockDuration: 300_000 },
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
attachWorkerEvents(worker, 'Context compaction', serverLogger)
|
|
71
|
+
const shutdown = createWorkerShutdown(worker, 'Context compaction', serverLogger)
|
|
72
|
+
|
|
73
|
+
if (registerSignals) {
|
|
74
|
+
registerShutdownSignals({ name: 'Context compaction', shutdown, logger: serverLogger })
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { worker, shutdown }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (import.meta.main) {
|
|
81
|
+
startContextCompactionWorker()
|
|
82
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
|
|
3
|
+
import { Queue, Worker } from 'bullmq'
|
|
4
|
+
import type IORedis from 'ioredis'
|
|
5
|
+
|
|
6
|
+
import type { chatLogger } from '../config/logger'
|
|
7
|
+
import { attachWorkerEvents, createWorkerShutdown, registerShutdownSignals } from '../workers/worker-utils'
|
|
8
|
+
import type { WorkerHandle } from '../workers/worker-utils'
|
|
9
|
+
|
|
10
|
+
export type DocumentSourceChannel = string
|
|
11
|
+
|
|
12
|
+
export interface DocumentProcessorAttachmentRef {
|
|
13
|
+
storageKey: string
|
|
14
|
+
name: string
|
|
15
|
+
contentType: string
|
|
16
|
+
sizeBytes?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface DocumentProcessorJob {
|
|
20
|
+
orgId: string
|
|
21
|
+
source: DocumentSourceChannel
|
|
22
|
+
sourceId: string
|
|
23
|
+
title: string
|
|
24
|
+
contentType?: string
|
|
25
|
+
sourceCanonicalKey: string
|
|
26
|
+
sourceVersionKey: string
|
|
27
|
+
text?: string
|
|
28
|
+
attachment?: DocumentProcessorAttachmentRef
|
|
29
|
+
metadata?: Record<string, unknown>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const DEFAULT_DOCUMENT_PROCESSOR_QUEUE = 'document-processor'
|
|
33
|
+
const DEFAULT_WORKER_NAME = 'Document processor'
|
|
34
|
+
|
|
35
|
+
export function buildDocumentProcessorJobId(
|
|
36
|
+
job: Pick<
|
|
37
|
+
DocumentProcessorJob,
|
|
38
|
+
'orgId' | 'source' | 'sourceId' | 'sourceCanonicalKey' | 'sourceVersionKey' | 'title'
|
|
39
|
+
>,
|
|
40
|
+
): string {
|
|
41
|
+
const digest = createHash('sha256')
|
|
42
|
+
.update(
|
|
43
|
+
JSON.stringify({
|
|
44
|
+
orgId: job.orgId,
|
|
45
|
+
source: job.source,
|
|
46
|
+
sourceId: job.sourceId,
|
|
47
|
+
sourceCanonicalKey: job.sourceCanonicalKey,
|
|
48
|
+
sourceVersionKey: job.sourceVersionKey,
|
|
49
|
+
title: job.title,
|
|
50
|
+
}),
|
|
51
|
+
)
|
|
52
|
+
.digest('hex')
|
|
53
|
+
|
|
54
|
+
return `doc__${digest}`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function createDocumentProcessorQueueRuntime<TJob extends DocumentProcessorJob>(params: {
|
|
58
|
+
getConnectionForBullMQ: () => IORedis
|
|
59
|
+
getWorkerPath: () => string
|
|
60
|
+
logger: typeof chatLogger
|
|
61
|
+
queueName?: string
|
|
62
|
+
workerName?: string
|
|
63
|
+
concurrency?: number
|
|
64
|
+
lockDuration?: number
|
|
65
|
+
}): {
|
|
66
|
+
enqueue: (job: TJob) => Promise<unknown>
|
|
67
|
+
startWorker: (options?: { registerSignals?: boolean }) => WorkerHandle
|
|
68
|
+
} {
|
|
69
|
+
const queueName = params.queueName ?? DEFAULT_DOCUMENT_PROCESSOR_QUEUE
|
|
70
|
+
const workerName = params.workerName ?? DEFAULT_WORKER_NAME
|
|
71
|
+
const concurrency = params.concurrency ?? 4
|
|
72
|
+
const lockDuration = params.lockDuration ?? 300_000
|
|
73
|
+
const jobName = 'process-document' as Parameters<Queue<TJob, unknown, string>['add']>[0]
|
|
74
|
+
const toQueueData = (job: TJob): Parameters<Queue<TJob, unknown, string>['add']>[1] =>
|
|
75
|
+
job as Parameters<Queue<TJob, unknown, string>['add']>[1]
|
|
76
|
+
let queue: Queue<TJob, unknown, string> | null = null
|
|
77
|
+
|
|
78
|
+
const getQueue = (): Queue<TJob, unknown, string> => {
|
|
79
|
+
if (queue) {
|
|
80
|
+
return queue
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
queue = new Queue<TJob, unknown, string>(queueName, {
|
|
84
|
+
connection: params.getConnectionForBullMQ(),
|
|
85
|
+
defaultJobOptions: {
|
|
86
|
+
removeOnComplete: 200,
|
|
87
|
+
removeOnFail: 200,
|
|
88
|
+
attempts: 3,
|
|
89
|
+
backoff: { type: 'exponential', delay: 1000 },
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
return queue
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
enqueue: async (job) =>
|
|
98
|
+
await getQueue().add(jobName, toQueueData(job), { jobId: buildDocumentProcessorJobId(job) }),
|
|
99
|
+
startWorker: (options = {}) => {
|
|
100
|
+
const { registerSignals = import.meta.main } = options
|
|
101
|
+
const worker = new Worker(queueName, params.getWorkerPath(), {
|
|
102
|
+
connection: params.getConnectionForBullMQ(),
|
|
103
|
+
concurrency,
|
|
104
|
+
lockDuration,
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
attachWorkerEvents(worker, workerName, params.logger)
|
|
108
|
+
|
|
109
|
+
const shutdown = createWorkerShutdown(worker, workerName, params.logger)
|
|
110
|
+
|
|
111
|
+
if (registerSignals) {
|
|
112
|
+
registerShutdownSignals({ name: workerName, shutdown, logger: params.logger })
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { worker, shutdown }
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Queue, Worker } from 'bullmq'
|
|
2
|
+
|
|
3
|
+
import { serverLogger } from '../config/logger'
|
|
4
|
+
import { getRedisConnectionForBullMQ } from '../redis'
|
|
5
|
+
import {
|
|
6
|
+
attachWorkerEvents,
|
|
7
|
+
getWorkerPath,
|
|
8
|
+
createWorkerShutdown,
|
|
9
|
+
registerShutdownSignals,
|
|
10
|
+
} from '../workers/worker-utils'
|
|
11
|
+
import type { WorkerHandle } from '../workers/worker-utils'
|
|
12
|
+
|
|
13
|
+
export interface MemoryConsolidationJob {
|
|
14
|
+
scopeId?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const MEMORY_CONSOLIDATION_QUEUE = 'memory-consolidation'
|
|
18
|
+
|
|
19
|
+
let _memoryConsolidationQueue: Queue<MemoryConsolidationJob> | null = null
|
|
20
|
+
function getMemoryConsolidationQueue(): Queue<MemoryConsolidationJob> {
|
|
21
|
+
if (!_memoryConsolidationQueue) {
|
|
22
|
+
_memoryConsolidationQueue = new Queue<MemoryConsolidationJob>(MEMORY_CONSOLIDATION_QUEUE, {
|
|
23
|
+
connection: getRedisConnectionForBullMQ(),
|
|
24
|
+
defaultJobOptions: {
|
|
25
|
+
removeOnComplete: 50,
|
|
26
|
+
removeOnFail: 50,
|
|
27
|
+
attempts: 2,
|
|
28
|
+
backoff: { type: 'exponential', delay: 5000 },
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
return _memoryConsolidationQueue
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function scheduleRecurringConsolidation() {
|
|
36
|
+
await getMemoryConsolidationQueue().add(
|
|
37
|
+
'consolidate',
|
|
38
|
+
{},
|
|
39
|
+
{ repeat: { every: 24 * 60 * 60 * 1000 }, jobId: 'memory-consolidation-recurring' },
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function startMemoryConsolidationWorker(options: { registerSignals?: boolean } = {}): WorkerHandle {
|
|
44
|
+
const { registerSignals = import.meta.main } = options
|
|
45
|
+
const processorPath = getWorkerPath('memory-consolidation.worker.ts')
|
|
46
|
+
const worker = new Worker(MEMORY_CONSOLIDATION_QUEUE, processorPath, {
|
|
47
|
+
connection: getRedisConnectionForBullMQ(),
|
|
48
|
+
lockDuration: 600_000,
|
|
49
|
+
concurrency: 1,
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
attachWorkerEvents(worker, 'Memory consolidation', serverLogger)
|
|
53
|
+
|
|
54
|
+
const shutdown = createWorkerShutdown(worker, 'Memory consolidation', serverLogger)
|
|
55
|
+
|
|
56
|
+
if (registerSignals) {
|
|
57
|
+
registerShutdownSignals({ name: 'Memory consolidation', shutdown, logger: serverLogger })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { worker, shutdown }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (import.meta.main) {
|
|
64
|
+
startMemoryConsolidationWorker()
|
|
65
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
type OrganizationOnboardStatus = string
|
|
2
|
+
import { Queue, Worker } from 'bullmq'
|
|
3
|
+
import type { Job } from 'bullmq'
|
|
4
|
+
|
|
5
|
+
import { serverLogger } from '../config/logger'
|
|
6
|
+
import { databaseService } from '../db/service'
|
|
7
|
+
import { getRedisConnectionForBullMQ } from '../redis'
|
|
8
|
+
import { memoryService } from '../services/memory.service'
|
|
9
|
+
import {
|
|
10
|
+
attachWorkerEvents,
|
|
11
|
+
createTracedWorkerProcessor,
|
|
12
|
+
createWorkerShutdown,
|
|
13
|
+
registerShutdownSignals,
|
|
14
|
+
} from '../workers/worker-utils'
|
|
15
|
+
import type { WorkerHandle } from '../workers/worker-utils'
|
|
16
|
+
|
|
17
|
+
interface PostChatMemoryMessage {
|
|
18
|
+
role: 'user' | 'agent'
|
|
19
|
+
content: string
|
|
20
|
+
agentName?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface PostChatMemoryExtractionJob {
|
|
24
|
+
orgId: string
|
|
25
|
+
workstreamId: string
|
|
26
|
+
sourceId: string
|
|
27
|
+
onboardStatus?: OrganizationOnboardStatus
|
|
28
|
+
userMessage: string
|
|
29
|
+
historyMessages: PostChatMemoryMessage[]
|
|
30
|
+
agentMessages: Array<{ content: string; agentName?: string }>
|
|
31
|
+
memoryBlock?: string
|
|
32
|
+
attachmentContext?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const POST_CHAT_MEMORY_QUEUE = 'post-chat-memory'
|
|
36
|
+
const POST_CHAT_MEMORY_CONCURRENCY = 3
|
|
37
|
+
const POST_CHAT_MEMORY_LOCK_DURATION_MS = 900_000
|
|
38
|
+
const POST_CHAT_MEMORY_MAX_STALLED_COUNT = 10
|
|
39
|
+
const POST_CHAT_MEMORY_STALLED_INTERVAL_MS = 120_000
|
|
40
|
+
|
|
41
|
+
let _postChatMemoryQueue: Queue<PostChatMemoryExtractionJob> | null = null
|
|
42
|
+
function getPostChatMemoryQueue(): Queue<PostChatMemoryExtractionJob> {
|
|
43
|
+
if (!_postChatMemoryQueue) {
|
|
44
|
+
_postChatMemoryQueue = new Queue<PostChatMemoryExtractionJob>(POST_CHAT_MEMORY_QUEUE, {
|
|
45
|
+
connection: getRedisConnectionForBullMQ(),
|
|
46
|
+
defaultJobOptions: {
|
|
47
|
+
removeOnComplete: 200,
|
|
48
|
+
removeOnFail: 200,
|
|
49
|
+
attempts: 3,
|
|
50
|
+
backoff: { type: 'exponential', delay: 2_000 },
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
return _postChatMemoryQueue
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function enqueuePostChatMemory(job: PostChatMemoryExtractionJob) {
|
|
58
|
+
return await getPostChatMemoryQueue().add('extract-memory', job)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function processPostChatMemoryJob(job: Job<PostChatMemoryExtractionJob>): Promise<void> {
|
|
62
|
+
await databaseService.connect()
|
|
63
|
+
|
|
64
|
+
const data = job.data
|
|
65
|
+
const userMessage = data.userMessage.trim()
|
|
66
|
+
const agentMessages = data.agentMessages
|
|
67
|
+
.map((item) => ({
|
|
68
|
+
content: item.content.trim(),
|
|
69
|
+
...(typeof item.agentName === 'string' && item.agentName.trim() ? { agentName: item.agentName.trim() } : {}),
|
|
70
|
+
}))
|
|
71
|
+
.filter((item) => item.content.length > 0)
|
|
72
|
+
|
|
73
|
+
if (!userMessage || agentMessages.length === 0) return
|
|
74
|
+
|
|
75
|
+
const joinedOutput = agentMessages
|
|
76
|
+
.map((item) => (item.agentName ? `[${item.agentName}] ${item.content}` : item.content))
|
|
77
|
+
.join('\n\n')
|
|
78
|
+
|
|
79
|
+
const uniqueAgentNames = [
|
|
80
|
+
...new Set(
|
|
81
|
+
agentMessages
|
|
82
|
+
.map((item) => item.agentName)
|
|
83
|
+
.filter((value): value is string => typeof value === 'string' && value.length > 0),
|
|
84
|
+
),
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
await memoryService.addConversationMemories({
|
|
88
|
+
orgId: data.orgId,
|
|
89
|
+
input: userMessage,
|
|
90
|
+
output: joinedOutput,
|
|
91
|
+
sourceId: data.sourceId,
|
|
92
|
+
onboardStatus: data.onboardStatus,
|
|
93
|
+
...(uniqueAgentNames.length > 0 ? { agentName: uniqueAgentNames[0] } : {}),
|
|
94
|
+
historyMessages: data.historyMessages,
|
|
95
|
+
memoryBlock: data.memoryBlock,
|
|
96
|
+
attachmentContext: data.attachmentContext,
|
|
97
|
+
agentNames: uniqueAgentNames,
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function startPostChatMemoryWorker(options: { registerSignals?: boolean } = {}): WorkerHandle {
|
|
102
|
+
const { registerSignals = import.meta.main } = options
|
|
103
|
+
const worker = new Worker(
|
|
104
|
+
POST_CHAT_MEMORY_QUEUE,
|
|
105
|
+
createTracedWorkerProcessor(POST_CHAT_MEMORY_QUEUE, processPostChatMemoryJob),
|
|
106
|
+
{
|
|
107
|
+
connection: getRedisConnectionForBullMQ(),
|
|
108
|
+
concurrency: POST_CHAT_MEMORY_CONCURRENCY,
|
|
109
|
+
lockDuration: POST_CHAT_MEMORY_LOCK_DURATION_MS,
|
|
110
|
+
maxStalledCount: POST_CHAT_MEMORY_MAX_STALLED_COUNT,
|
|
111
|
+
stalledInterval: POST_CHAT_MEMORY_STALLED_INTERVAL_MS,
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
attachWorkerEvents(worker, 'Post-chat memory', serverLogger)
|
|
116
|
+
|
|
117
|
+
const shutdown = createWorkerShutdown(worker, 'Post-chat memory', serverLogger)
|
|
118
|
+
|
|
119
|
+
if (registerSignals) {
|
|
120
|
+
registerShutdownSignals({ name: 'Post-chat memory', shutdown, logger: serverLogger })
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return { worker, shutdown }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (import.meta.main) {
|
|
127
|
+
startPostChatMemoryWorker()
|
|
128
|
+
}
|