@lota-sdk/core 0.4.9 → 0.4.11
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/package.json +2 -2
- package/src/ai/embedding-cache.ts +3 -1
- package/src/ai-gateway/ai-gateway.ts +164 -82
- package/src/ai-gateway/index.ts +16 -1
- package/src/config/agent-defaults.ts +4 -107
- package/src/config/agent-types.ts +1 -1
- package/src/config/background-processing.ts +1 -1
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +22 -25
- package/src/config/thread-defaults.ts +1 -10
- package/src/create-runtime.ts +145 -670
- package/src/db/base.service.ts +30 -38
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.ts +29 -20
- package/src/db/memory.ts +188 -195
- package/src/db/service-normalization.ts +97 -64
- package/src/db/service.ts +496 -384
- package/src/db/startup.ts +30 -19
- package/src/effect/helpers.ts +30 -5
- package/src/effect/index.ts +7 -7
- package/src/effect/layers.ts +75 -72
- package/src/effect/services.ts +15 -11
- package/src/embeddings/provider.ts +65 -71
- package/src/index.ts +13 -12
- package/src/queues/autonomous-job.queue.ts +177 -143
- package/src/queues/context-compaction.queue.ts +41 -39
- package/src/queues/delayed-node-promotion.queue.ts +61 -42
- package/src/queues/document-processor.queue.ts +5 -3
- package/src/queues/index.ts +1 -0
- package/src/queues/memory-consolidation.queue.ts +79 -53
- package/src/queues/organization-learning.queue.ts +70 -33
- package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
- package/src/queues/plan-scheduler.queue.ts +101 -97
- package/src/queues/post-chat-memory.queue.ts +56 -46
- package/src/queues/queue-factory.ts +146 -69
- package/src/queues/queues.service.ts +61 -0
- package/src/queues/title-generation.queue.ts +44 -44
- package/src/redis/connection.ts +181 -164
- package/src/redis/org-memory-lock.ts +24 -9
- package/src/redis/redis-lease-lock.ts +8 -1
- package/src/redis/stream-context.ts +17 -9
- package/src/runtime/agent-identity-overrides.ts +7 -3
- package/src/runtime/agent-runtime-policy.ts +10 -5
- package/src/runtime/agent-stream-helpers.ts +24 -15
- package/src/runtime/chat-run-orchestration.ts +1 -1
- package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
- package/src/runtime/context-compaction/context-compaction.ts +131 -85
- package/src/runtime/domain-layer.ts +203 -0
- package/src/runtime/execution-plan-visibility.ts +5 -2
- package/src/runtime/graph-designer.ts +0 -14
- package/src/runtime/helper-model.ts +8 -4
- package/src/runtime/index.ts +1 -1
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/memory/memory-block.ts +19 -9
- package/src/runtime/memory/memory-pipeline.ts +53 -66
- package/src/runtime/memory/memory-scope.ts +33 -29
- package/src/runtime/plugin-resolution.ts +58 -62
- package/src/runtime/post-turn-side-effects.ts +139 -161
- package/src/runtime/retrieval-adapters.ts +4 -4
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +0 -43
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +455 -0
- package/src/runtime/runtime-worker-registry.ts +113 -30
- package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
- package/src/runtime/social-chat/social-chat-history.ts +24 -13
- package/src/runtime/social-chat/social-chat.ts +420 -369
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
- package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
- package/src/runtime/thread-chat-helpers.ts +18 -9
- package/src/runtime/thread-turn-context.ts +28 -74
- package/src/runtime/turn-lifecycle.ts +6 -14
- package/src/services/agent-activity.service.ts +169 -176
- package/src/services/agent-executor.service.ts +207 -196
- package/src/services/artifact.service.ts +10 -5
- package/src/services/attachment.service.ts +16 -48
- package/src/services/autonomous-job.service.ts +81 -87
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +3 -1
- package/src/services/context-compaction.service.ts +8 -10
- package/src/services/document-chunk.service.ts +8 -17
- package/src/services/execution-plan/execution-plan-graph.ts +122 -109
- package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
- package/src/services/execution-plan/execution-plan.service.ts +68 -51
- package/src/services/feedback-loop.service.ts +1 -1
- package/src/services/global-orchestrator.service.ts +49 -15
- package/src/services/graph-full-routing.ts +49 -37
- package/src/services/index.ts +1 -0
- package/src/services/institutional-memory.service.ts +8 -17
- package/src/services/learned-skill.service.ts +38 -35
- package/src/services/memory/memory-conversation.ts +10 -5
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +14 -3
- package/src/services/memory/memory-preseeded.ts +10 -4
- package/src/services/memory/memory-utils.ts +2 -1
- package/src/services/memory/memory.service.ts +37 -52
- package/src/services/memory/rerank.service.ts +3 -11
- package/src/services/monitoring-window.service.ts +1 -1
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +2 -2
- package/src/services/notification.service.ts +16 -4
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +34 -51
- package/src/services/ownership-dispatcher.service.ts +148 -95
- package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
- package/src/services/plan/plan-agent-query.service.ts +13 -9
- package/src/services/plan/plan-approval.service.ts +52 -48
- package/src/services/plan/plan-artifact.service.ts +2 -2
- package/src/services/plan/plan-builder.service.ts +2 -2
- package/src/services/plan/plan-checkpoint.service.ts +1 -1
- package/src/services/plan/plan-compiler.service.ts +1 -1
- package/src/services/plan/plan-completion-side-effects.ts +99 -113
- package/src/services/plan/plan-coordination.service.ts +1 -1
- package/src/services/plan/plan-cycle.service.ts +171 -202
- package/src/services/plan/plan-deadline.service.ts +304 -307
- package/src/services/plan/plan-event-delivery.service.ts +84 -72
- package/src/services/plan/plan-executor-context.ts +2 -0
- package/src/services/plan/plan-executor-graph.ts +375 -353
- package/src/services/plan/plan-executor-helpers.ts +60 -75
- package/src/services/plan/plan-executor.service.ts +494 -489
- package/src/services/plan/plan-run.service.ts +12 -19
- package/src/services/plan/plan-scheduler.service.ts +89 -82
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +8 -5
- package/src/services/plan/plan-validator.service.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +17 -11
- package/src/services/plugin-executor.service.ts +26 -21
- package/src/services/quality-metrics.service.ts +1 -1
- package/src/services/queue-job.service.ts +8 -17
- package/src/services/recent-activity-title.service.ts +22 -10
- package/src/services/recent-activity.service.ts +1 -1
- package/src/services/skill-resolver.service.ts +1 -1
- package/src/services/social-chat-history.service.ts +37 -20
- package/src/services/system-executor.service.ts +25 -20
- package/src/services/thread/thread-bootstrap.ts +37 -19
- package/src/services/thread/thread-listing.ts +2 -1
- package/src/services/thread/thread-memory-block.ts +18 -5
- package/src/services/thread/thread-message.service.ts +30 -13
- package/src/services/thread/thread-title.service.ts +1 -1
- package/src/services/thread/thread-turn-execution.ts +87 -83
- package/src/services/thread/thread-turn-preparation.service.ts +65 -40
- package/src/services/thread/thread-turn-streaming.ts +32 -36
- package/src/services/thread/thread-turn.ts +43 -29
- package/src/services/thread/thread.service.ts +32 -8
- package/src/services/user.service.ts +1 -1
- package/src/services/write-intent-validator.service.ts +1 -1
- package/src/storage/attachment-storage.service.ts +7 -4
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +1 -1
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
- package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/skill-extractor.agent.ts +1 -1
- package/src/system-agents/skill-manager.agent.ts +1 -1
- package/src/system-agents/thread-router.agent.ts +23 -20
- package/src/system-agents/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +36 -20
- package/src/tools/fetch-webpage.tool.ts +30 -22
- package/src/tools/firecrawl-client.ts +1 -6
- package/src/tools/plan-approval.tool.ts +9 -1
- package/src/tools/remember-memory.tool.ts +3 -6
- package/src/tools/research-topic.tool.ts +12 -3
- package/src/tools/search-web.tool.ts +26 -18
- package/src/tools/search.tool.ts +4 -5
- package/src/tools/team-think.tool.ts +139 -121
- package/src/utils/async.ts +15 -6
- package/src/utils/errors.ts +27 -15
- package/src/workers/bootstrap.ts +34 -58
- package/src/workers/memory-consolidation.worker.ts +4 -1
- package/src/workers/organization-learning.worker.ts +16 -3
- package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
- package/src/workers/skill-extraction.runner.ts +13 -15
- package/src/workers/worker-utils.ts +14 -8
- package/src/config/search.ts +0 -3
- package/src/effect/awaitable-effect.ts +0 -87
- package/src/effect/runtime-ref.ts +0 -25
- package/src/effect/runtime.ts +0 -31
- package/src/redis/runtime-connection.ts +0 -10
- package/src/runtime/agent-types.ts +0 -1
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import type { ChatMessage } from '@lota-sdk/shared'
|
|
2
2
|
import { Schema, Effect } from 'effect'
|
|
3
|
-
import type { Context } from 'effect'
|
|
4
3
|
|
|
5
4
|
import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
6
5
|
import type { RecordIdRef } from '../db/record-id'
|
|
7
|
-
import { getCurrentRuntime } from '../effect/runtime-ref'
|
|
8
6
|
import { AgentConfigServiceTag, RuntimeAdaptersServiceTag } from '../effect/services'
|
|
9
|
-
import {
|
|
10
|
-
import { enqueueRegularChatMemoryDigest, enqueueSkillExtraction } from '../queues/organization-learning.queue'
|
|
11
|
-
import { enqueuePostChatMemory } from '../queues/post-chat-memory.queue'
|
|
12
|
-
import { enqueueRecentActivityTitleRefinement } from '../queues/title-generation.queue'
|
|
7
|
+
import { LotaQueuesServiceTag } from '../queues/queues.service'
|
|
13
8
|
import { RecentActivityServiceTag } from '../services/recent-activity.service'
|
|
14
9
|
import { ThreadServiceTag } from '../services/thread/thread.service'
|
|
15
10
|
import type { NormalizedThread, ThreadRecord } from '../services/thread/thread.types'
|
|
@@ -21,7 +16,6 @@ import {
|
|
|
21
16
|
shouldEnqueueOnboardingPostChatMemory,
|
|
22
17
|
shouldEnqueueRegularDigestForThread,
|
|
23
18
|
} from './memory/memory-digest-policy'
|
|
24
|
-
import type { LotaRuntimeAdapters } from './runtime-extensions'
|
|
25
19
|
import { shouldEnqueueSkillExtraction } from './skill-extraction-policy'
|
|
26
20
|
import {
|
|
27
21
|
appendPersistedThreadContextToHistoryMessages,
|
|
@@ -33,13 +27,6 @@ import {
|
|
|
33
27
|
toHistoryMessages,
|
|
34
28
|
} from './thread-chat-helpers'
|
|
35
29
|
|
|
36
|
-
interface PostTurnSideEffectsServices {
|
|
37
|
-
recentActivityService: Context.Service.Shape<typeof RecentActivityServiceTag>
|
|
38
|
-
threadService: Context.Service.Shape<typeof ThreadServiceTag>
|
|
39
|
-
agentConfig: ResolvedAgentConfig
|
|
40
|
-
runtimeAdapters: LotaRuntimeAdapters
|
|
41
|
-
}
|
|
42
|
-
|
|
43
30
|
class PostTurnSideEffectsError extends Schema.TaggedErrorClass<PostTurnSideEffectsError>()('PostTurnSideEffectsError', {
|
|
44
31
|
message: Schema.String,
|
|
45
32
|
cause: Schema.Defect,
|
|
@@ -55,20 +42,6 @@ function tryPostTurnSideEffect<A>(
|
|
|
55
42
|
})
|
|
56
43
|
}
|
|
57
44
|
|
|
58
|
-
function getPostTurnSideEffectsServices(): PostTurnSideEffectsServices {
|
|
59
|
-
const runtime = getCurrentRuntime()
|
|
60
|
-
return runtime.runSync(
|
|
61
|
-
Effect.gen(function* () {
|
|
62
|
-
return {
|
|
63
|
-
recentActivityService: yield* RecentActivityServiceTag,
|
|
64
|
-
threadService: yield* ThreadServiceTag,
|
|
65
|
-
agentConfig: yield* AgentConfigServiceTag,
|
|
66
|
-
runtimeAdapters: yield* RuntimeAdaptersServiceTag,
|
|
67
|
-
}
|
|
68
|
-
}),
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
45
|
function resolveDisplayName(
|
|
73
46
|
agentConfig: ResolvedAgentConfig,
|
|
74
47
|
agentId: string,
|
|
@@ -137,154 +110,159 @@ interface PostTurnSideEffectsParams {
|
|
|
137
110
|
agentDisplayNamesById?: Partial<Record<string, string>>
|
|
138
111
|
}
|
|
139
112
|
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
113
|
+
export const runPostTurnSideEffects = Effect.fn('PostTurnSideEffects.run')(function* (
|
|
114
|
+
params: PostTurnSideEffectsParams,
|
|
115
|
+
) {
|
|
116
|
+
const recentActivityService = yield* RecentActivityServiceTag
|
|
117
|
+
const threadService = yield* ThreadServiceTag
|
|
118
|
+
const agentConfig: ResolvedAgentConfig = yield* AgentConfigServiceTag
|
|
119
|
+
const runtimeAdapters = yield* RuntimeAdaptersServiceTag
|
|
120
|
+
const queues = yield* LotaQueuesServiceTag
|
|
121
|
+
const recentHistory = yield* tryPostTurnSideEffect('Failed to load recent thread history.', () =>
|
|
122
|
+
params.loadRecentHistory(),
|
|
123
|
+
)
|
|
124
|
+
const turnCount = yield* threadService.incrementTurnCount(params.threadRef)
|
|
125
|
+
const agentMessages = buildAgentHistoryMessages(agentConfig, params.allAssistantMessages)
|
|
126
|
+
const historyMessagesForMemory = appendPersistedThreadContextToHistoryMessages(
|
|
127
|
+
toHistoryMessages(agentConfig, recentHistory),
|
|
128
|
+
{ compactionSummary: params.latestThreadRecord.compactionSummary },
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
const userMessageText = params.referenceUserMessage ? extractMessageText(params.referenceUserMessage).trim() : ''
|
|
132
|
+
const readableUploads = params.listReadableUploads()
|
|
133
|
+
const attachmentMetadataContext = buildReadableUploadMetadataContext(readableUploads)
|
|
134
|
+
const hasAttachmentContext = Boolean(attachmentMetadataContext)
|
|
135
|
+
const shouldExtractMemory = params.onboardingActive
|
|
136
|
+
? shouldEnqueueOnboardingPostChatMemory({
|
|
137
|
+
onboardingActive: params.onboardingActive,
|
|
138
|
+
userMessageText,
|
|
139
|
+
hasAttachmentContext,
|
|
140
|
+
agentMessageCount: agentMessages.length,
|
|
141
|
+
})
|
|
142
|
+
: shouldEnqueueMemoryExtraction({ onboardingActive: params.onboardingActive, turnCount }) &&
|
|
143
|
+
userMessageText.length > 0
|
|
144
|
+
|
|
145
|
+
if (shouldExtractMemory) {
|
|
146
|
+
const memoryUserMessage = userMessageText || 'User uploaded attachment(s).'
|
|
147
|
+
yield* tryPostTurnSideEffect('Failed to enqueue post-chat memory extraction.', () =>
|
|
148
|
+
safeEnqueue(
|
|
149
|
+
() =>
|
|
150
|
+
queues.postChatMemory.enqueuePostChatMemory({
|
|
151
|
+
orgId: params.orgIdString,
|
|
152
|
+
threadId: params.threadIdString,
|
|
153
|
+
sourceId: params.referenceUserMessageId,
|
|
154
|
+
onboardStatus: readOptionalString((params.workspace as { onboardStatus?: unknown }).onboardStatus),
|
|
155
|
+
userMessage: memoryUserMessage,
|
|
156
|
+
historyMessages: historyMessagesForMemory,
|
|
157
|
+
agentMessages,
|
|
158
|
+
memoryBlock: params.memoryBlock.trim() ? params.memoryBlock : undefined,
|
|
159
|
+
attachmentContext: attachmentMetadataContext,
|
|
160
|
+
}),
|
|
161
|
+
{ operationName: 'post-chat memory extraction enqueue' },
|
|
162
|
+
),
|
|
145
163
|
)
|
|
146
|
-
|
|
147
|
-
const agentMessages = buildAgentHistoryMessages(params.allAssistantMessages)
|
|
148
|
-
const historyMessagesForMemory = appendPersistedThreadContextToHistoryMessages(toHistoryMessages(recentHistory), {
|
|
149
|
-
compactionSummary: params.latestThreadRecord.compactionSummary,
|
|
150
|
-
})
|
|
164
|
+
}
|
|
151
165
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
const referenceUserMessage = params.referenceUserMessage
|
|
167
|
+
if (params.isUserTurn && referenceUserMessage) {
|
|
168
|
+
const conversationSummary = buildConversationSummary({
|
|
169
|
+
agentConfig,
|
|
170
|
+
userMessageText,
|
|
171
|
+
assistantMessages: params.allAssistantMessages,
|
|
172
|
+
})
|
|
173
|
+
if (conversationSummary) {
|
|
174
|
+
const effectiveAgentId = params.visibleThreadAgentId ?? params.defaultLeadAgentId
|
|
175
|
+
const recentActivityResult = yield* recentActivityService.recordEvent({
|
|
176
|
+
orgId: params.orgRef,
|
|
177
|
+
userId: params.userRef,
|
|
178
|
+
source: 'system',
|
|
179
|
+
event: {
|
|
180
|
+
sourceEventId: `chat-turn:${params.referenceUserMessageId}`,
|
|
181
|
+
kind: 'chat.turn.completed',
|
|
182
|
+
targetKind: 'thread',
|
|
183
|
+
targetId: params.threadIdString,
|
|
184
|
+
mergeKey: `thread:${params.threadIdString}`,
|
|
185
|
+
title: buildRecentActivityChatSystemTitle({
|
|
186
|
+
agentConfig,
|
|
187
|
+
thread: params.thread,
|
|
188
|
+
visibleAgentId: effectiveAgentId,
|
|
189
|
+
agentDisplayNamesById: params.agentDisplayNamesById,
|
|
190
|
+
}),
|
|
191
|
+
sourceLabel: resolveDisplayName(agentConfig, effectiveAgentId, params.agentDisplayNamesById),
|
|
192
|
+
deepLink: buildRecentActivityChatDeepLink({
|
|
193
|
+
thread: params.thread,
|
|
194
|
+
threadId: params.threadIdString,
|
|
195
|
+
visibleAgentId: effectiveAgentId,
|
|
196
|
+
}),
|
|
197
|
+
metadata: {
|
|
198
|
+
agentId: effectiveAgentId,
|
|
199
|
+
agentName: resolveDisplayName(agentConfig, effectiveAgentId, params.agentDisplayNamesById),
|
|
200
|
+
threadId: params.threadIdString,
|
|
201
|
+
threadTitle: params.latestThreadRecord.title ?? params.thread.title,
|
|
202
|
+
threadType: params.thread.type,
|
|
203
|
+
...(params.thread.threadType ? { coreType: params.thread.threadType } : {}),
|
|
204
|
+
userMessageText,
|
|
205
|
+
assistantSummary: conversationSummary,
|
|
206
|
+
messageId: params.referenceUserMessageId,
|
|
207
|
+
},
|
|
208
|
+
occurredAt: toIsoDateTimeString(referenceUserMessage.metadata?.createdAt ?? nowEpochMillis()),
|
|
209
|
+
},
|
|
210
|
+
})
|
|
165
211
|
|
|
166
|
-
|
|
167
|
-
const memoryUserMessage = userMessageText || 'User uploaded attachment(s).'
|
|
168
|
-
yield* tryPostTurnSideEffect('Failed to enqueue post-chat memory extraction.', () =>
|
|
212
|
+
yield* tryPostTurnSideEffect('Failed to enqueue post-chat org action.', () =>
|
|
169
213
|
safeEnqueue(
|
|
170
|
-
() =>
|
|
171
|
-
|
|
214
|
+
() => {
|
|
215
|
+
const enqueuePostChatOrgAction = runtimeAdapters.enqueuePostChatOrgAction
|
|
216
|
+
if (!enqueuePostChatOrgAction) {
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const sourceCreatedAt = referenceUserMessage.metadata?.createdAt ?? nowEpochMillis()
|
|
221
|
+
return enqueuePostChatOrgAction({
|
|
172
222
|
orgId: params.orgIdString,
|
|
173
223
|
threadId: params.threadIdString,
|
|
174
224
|
sourceId: params.referenceUserMessageId,
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
attachmentContext: attachmentMetadataContext,
|
|
181
|
-
}),
|
|
182
|
-
{ operationName: 'post-chat memory extraction enqueue' },
|
|
225
|
+
sourceCreatedAt,
|
|
226
|
+
conversationSummary,
|
|
227
|
+
})
|
|
228
|
+
},
|
|
229
|
+
{ operationName: 'post-chat org action enqueue' },
|
|
183
230
|
),
|
|
184
231
|
)
|
|
185
|
-
}
|
|
186
232
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const conversationSummary = buildConversationSummary({
|
|
190
|
-
userMessageText,
|
|
191
|
-
assistantMessages: params.allAssistantMessages,
|
|
192
|
-
})
|
|
193
|
-
if (conversationSummary) {
|
|
194
|
-
const effectiveAgentId = params.visibleThreadAgentId ?? params.defaultLeadAgentId
|
|
195
|
-
const recentActivityResult = yield* recentActivityService.recordEvent({
|
|
196
|
-
orgId: params.orgRef,
|
|
197
|
-
userId: params.userRef,
|
|
198
|
-
source: 'system',
|
|
199
|
-
event: {
|
|
200
|
-
sourceEventId: `chat-turn:${params.referenceUserMessageId}`,
|
|
201
|
-
kind: 'chat.turn.completed',
|
|
202
|
-
targetKind: 'thread',
|
|
203
|
-
targetId: params.threadIdString,
|
|
204
|
-
mergeKey: `thread:${params.threadIdString}`,
|
|
205
|
-
title: buildRecentActivityChatSystemTitle({
|
|
206
|
-
agentConfig,
|
|
207
|
-
thread: params.thread,
|
|
208
|
-
visibleAgentId: effectiveAgentId,
|
|
209
|
-
agentDisplayNamesById: params.agentDisplayNamesById,
|
|
210
|
-
}),
|
|
211
|
-
sourceLabel: resolveDisplayName(agentConfig, effectiveAgentId, params.agentDisplayNamesById),
|
|
212
|
-
deepLink: buildRecentActivityChatDeepLink({
|
|
213
|
-
thread: params.thread,
|
|
214
|
-
threadId: params.threadIdString,
|
|
215
|
-
visibleAgentId: effectiveAgentId,
|
|
216
|
-
}),
|
|
217
|
-
metadata: {
|
|
218
|
-
agentId: effectiveAgentId,
|
|
219
|
-
agentName: resolveDisplayName(agentConfig, effectiveAgentId, params.agentDisplayNamesById),
|
|
220
|
-
threadId: params.threadIdString,
|
|
221
|
-
threadTitle: params.latestThreadRecord.title ?? params.thread.title,
|
|
222
|
-
threadType: params.thread.type,
|
|
223
|
-
...(params.thread.threadType ? { coreType: params.thread.threadType } : {}),
|
|
224
|
-
userMessageText,
|
|
225
|
-
assistantSummary: conversationSummary,
|
|
226
|
-
messageId: params.referenceUserMessageId,
|
|
227
|
-
},
|
|
228
|
-
occurredAt: toIsoDateTimeString(referenceUserMessage.metadata?.createdAt ?? nowEpochMillis()),
|
|
229
|
-
},
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
yield* tryPostTurnSideEffect('Failed to enqueue post-chat org action.', () =>
|
|
233
|
+
if (recentActivityService.isMeaningfulRefinementCandidate(recentActivityResult.item)) {
|
|
234
|
+
yield* tryPostTurnSideEffect('Failed to enqueue recent activity title refinement.', () =>
|
|
233
235
|
safeEnqueue(
|
|
234
|
-
() =>
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
return
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const sourceCreatedAt = referenceUserMessage.metadata?.createdAt ?? nowEpochMillis()
|
|
241
|
-
return enqueuePostChatOrgAction({
|
|
242
|
-
orgId: params.orgIdString,
|
|
243
|
-
threadId: params.threadIdString,
|
|
244
|
-
sourceId: params.referenceUserMessageId,
|
|
245
|
-
sourceCreatedAt,
|
|
246
|
-
conversationSummary,
|
|
247
|
-
})
|
|
248
|
-
},
|
|
249
|
-
{ operationName: 'post-chat org action enqueue' },
|
|
236
|
+
() =>
|
|
237
|
+
queues.titleGeneration.enqueueRecentActivityTitleRefinement({ activityId: recentActivityResult.item.id }),
|
|
238
|
+
{ operationName: 'recent activity title refinement enqueue' },
|
|
250
239
|
),
|
|
251
240
|
)
|
|
252
|
-
|
|
253
|
-
if (recentActivityService.isMeaningfulRefinementCandidate(recentActivityResult.item)) {
|
|
254
|
-
yield* tryPostTurnSideEffect('Failed to enqueue recent activity title refinement.', () =>
|
|
255
|
-
safeEnqueue(() => enqueueRecentActivityTitleRefinement({ activityId: recentActivityResult.item.id }), {
|
|
256
|
-
operationName: 'recent activity title refinement enqueue',
|
|
257
|
-
}),
|
|
258
|
-
)
|
|
259
|
-
}
|
|
260
241
|
}
|
|
261
242
|
}
|
|
243
|
+
}
|
|
262
244
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (shouldEnqueueSkillExtraction({ onboardingActive: params.onboardingActive, turnCount })) {
|
|
272
|
-
yield* tryPostTurnSideEffect('Failed to enqueue skill extraction.', () =>
|
|
273
|
-
safeEnqueue(() => enqueueSkillExtraction({ orgId: params.orgIdString }), {
|
|
274
|
-
operationName: 'skill extraction enqueue',
|
|
275
|
-
}),
|
|
276
|
-
)
|
|
277
|
-
}
|
|
245
|
+
if (shouldEnqueueRegularDigestForThread({ onboardingActive: params.onboardingActive, turnCount })) {
|
|
246
|
+
yield* tryPostTurnSideEffect('Failed to enqueue regular chat memory digest.', () =>
|
|
247
|
+
safeEnqueue(() => queues.organizationLearning.enqueueRegularChatMemoryDigest({ orgId: params.orgIdString }), {
|
|
248
|
+
operationName: 'regular chat memory digest enqueue',
|
|
249
|
+
}),
|
|
250
|
+
)
|
|
251
|
+
}
|
|
278
252
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
})
|
|
253
|
+
if (shouldEnqueueSkillExtraction({ onboardingActive: params.onboardingActive, turnCount })) {
|
|
254
|
+
yield* tryPostTurnSideEffect('Failed to enqueue skill extraction.', () =>
|
|
255
|
+
safeEnqueue(() => queues.organizationLearning.enqueueSkillExtraction({ orgId: params.orgIdString }), {
|
|
256
|
+
operationName: 'skill extraction enqueue',
|
|
257
|
+
}),
|
|
258
|
+
)
|
|
259
|
+
}
|
|
287
260
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
261
|
+
if (shouldEnqueueMemoryConsolidation({ onboardingActive: params.onboardingActive, turnCount })) {
|
|
262
|
+
yield* tryPostTurnSideEffect('Failed to enqueue memory consolidation.', () =>
|
|
263
|
+
safeEnqueue(() => queues.memoryConsolidation.enqueueMemoryConsolidation({ scopeId: params.orgIdString }), {
|
|
264
|
+
operationName: 'memory consolidation enqueue',
|
|
265
|
+
}),
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Schema, Effect } from 'effect'
|
|
2
2
|
|
|
3
|
-
interface ScopedRetrievalTask<TCandidate> {
|
|
3
|
+
interface ScopedRetrievalTask<TCandidate, E = never> {
|
|
4
4
|
scopeTag: string
|
|
5
|
-
retrieve: () => PromiseLike<TCandidate[]> | Effect.Effect<TCandidate[],
|
|
5
|
+
retrieve: () => PromiseLike<TCandidate[]> | Effect.Effect<TCandidate[], E>
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
interface ScopedRetrievalResult<TCandidate> {
|
|
@@ -20,8 +20,8 @@ function toScopedRetrievalError(scopeTag: string, cause: unknown): ScopedRetriev
|
|
|
20
20
|
return new ScopedRetrievalError({ scopeTag, message: cause instanceof Error ? cause.message : String(cause), cause })
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export function executeScopedRetrieval<TCandidate>(
|
|
24
|
-
tasks: ScopedRetrievalTask<TCandidate>[],
|
|
23
|
+
export function executeScopedRetrieval<TCandidate, E>(
|
|
24
|
+
tasks: ScopedRetrievalTask<TCandidate, E>[],
|
|
25
25
|
): Effect.Effect<ScopedRetrievalResult<TCandidate>[], ScopedRetrievalError> {
|
|
26
26
|
return Effect.forEach(
|
|
27
27
|
tasks,
|
|
@@ -8,8 +8,6 @@ import { DEFAULT_AI_GATEWAY_URL } from '../config/constants'
|
|
|
8
8
|
import { OPENROUTER_FAST_RERANK_MODEL_ID } from '../config/model-constants'
|
|
9
9
|
import type { LotaThreadConfig, ThreadBootstrapWelcomeConfig } from '../config/thread-defaults'
|
|
10
10
|
import type { RecordIdRef } from '../db/record-id'
|
|
11
|
-
import { getCurrentRuntime } from '../effect/runtime-ref'
|
|
12
|
-
import { RuntimeConfigServiceTag } from '../effect/services'
|
|
13
11
|
import type { NotificationService } from '../services/notification.service'
|
|
14
12
|
import { isRecord } from '../utils/string'
|
|
15
13
|
import type { GraphDesigner } from './graph-designer'
|
|
@@ -329,7 +327,7 @@ export function parseWorkerBootstrapEnv(env: Record<string, string | undefined>)
|
|
|
329
327
|
return WORKER_BOOTSTRAP_ENV_SCHEMA.parse(env)
|
|
330
328
|
}
|
|
331
329
|
|
|
332
|
-
const
|
|
330
|
+
export const lotaRuntimeEnvConfig = Config.all({
|
|
333
331
|
surrealdbUrl: Config.string('SURREALDB_URL'),
|
|
334
332
|
surrealdbNamespace: Config.string('SURREALDB_NAMESPACE'),
|
|
335
333
|
surrealdbUser: Config.string('SURREALDB_USER'),
|
|
@@ -369,7 +367,7 @@ export function loadLotaRuntimeConfigFromEnv(
|
|
|
369
367
|
overrides: LotaRuntimeEnvironmentOverrides,
|
|
370
368
|
options: { configProvider?: ConfigProvider.ConfigProvider } = {},
|
|
371
369
|
) {
|
|
372
|
-
return
|
|
370
|
+
return lotaRuntimeEnvConfig
|
|
373
371
|
.parse(options.configProvider ?? ConfigProvider.fromEnv())
|
|
374
372
|
.pipe(
|
|
375
373
|
Effect.map((env) =>
|
|
@@ -403,7 +401,7 @@ export function loadLotaRuntimeConfigFromEnv(
|
|
|
403
401
|
apiKey: Redacted.value(env.firecrawlApiKey),
|
|
404
402
|
...(Option.isSome(env.firecrawlApiBaseUrl) ? { apiBaseUrl: env.firecrawlApiBaseUrl.value } : {}),
|
|
405
403
|
},
|
|
406
|
-
logging: overrides.logging ?? { level:
|
|
404
|
+
logging: overrides.logging ?? { level: z.enum(logLevelValues).parse(env.logLevel) },
|
|
407
405
|
memory: {
|
|
408
406
|
searchK: env.memorySearchK,
|
|
409
407
|
rerankerStrategy: env.memoryRerankerStrategy as MemoryRerankerStrategy,
|
|
@@ -422,8 +420,4 @@ export function loadLotaRuntimeConfigFromEnv(
|
|
|
422
420
|
)
|
|
423
421
|
}
|
|
424
422
|
|
|
425
|
-
export function getRuntimeConfig(): ResolvedLotaRuntimeConfig {
|
|
426
|
-
return getCurrentRuntime().runSync(Effect.service(RuntimeConfigServiceTag))
|
|
427
|
-
}
|
|
428
|
-
|
|
429
423
|
export type { LotaThreadConfig }
|
|
@@ -6,19 +6,9 @@ import type {
|
|
|
6
6
|
PlanSpecRecord,
|
|
7
7
|
} from '@lota-sdk/shared'
|
|
8
8
|
import type { ToolSet } from 'ai'
|
|
9
|
-
import { Effect } from 'effect'
|
|
10
|
-
import type { Context } from 'effect'
|
|
11
9
|
|
|
12
10
|
import type { RecordIdRef } from '../db/record-id'
|
|
13
|
-
import { getCurrentRuntime } from '../effect/runtime-ref'
|
|
14
|
-
import {
|
|
15
|
-
RuntimeAdaptersServiceTag,
|
|
16
|
-
RuntimeWorkerExtensionsServiceTag,
|
|
17
|
-
ToolProvidersServiceTag,
|
|
18
|
-
TurnHooksServiceTag,
|
|
19
|
-
} from '../effect/services'
|
|
20
11
|
import type { ReadableUploadMetadata } from '../storage/attachment-types'
|
|
21
|
-
import type { LotaRuntimeWorkerExtensions } from './runtime-worker-registry'
|
|
22
12
|
|
|
23
13
|
export interface LotaRuntimeBackgroundCursor {
|
|
24
14
|
createdAt: Date
|
|
@@ -201,36 +191,3 @@ export interface LotaRuntimeAdapters {
|
|
|
201
191
|
connectPluginDatabases?: () => Promise<void>
|
|
202
192
|
withWorkspaceMemoryLock?: <T>(workspaceId: string, fn: () => Promise<T>) => Promise<T>
|
|
203
193
|
}
|
|
204
|
-
|
|
205
|
-
function resolveFromRuntime<I, T>(tag: Context.Key<I, T>): T {
|
|
206
|
-
return getCurrentRuntime().runSync(Effect.service(tag))
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export function getRuntimeAdapters(): LotaRuntimeAdapters {
|
|
210
|
-
return resolveFromRuntime(RuntimeAdaptersServiceTag)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export function getTurnHooks(): LotaRuntimeTurnHooks {
|
|
214
|
-
return resolveFromRuntime(TurnHooksServiceTag)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export function getToolProviders(): ToolSet {
|
|
218
|
-
return resolveFromRuntime(ToolProvidersServiceTag)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export function getConfiguredPluginDatabaseConnector(): (() => Promise<void>) | undefined {
|
|
222
|
-
return getRuntimeAdapters().connectPluginDatabases
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export function getExtraWorkers(): LotaRuntimeWorkerExtensions {
|
|
226
|
-
return resolveFromRuntime(RuntimeWorkerExtensionsServiceTag)
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export function withConfiguredWorkspaceMemoryLock<T>(workspaceId: string, fn: () => Promise<T>): Promise<T> {
|
|
230
|
-
const adapter = getRuntimeAdapters().withWorkspaceMemoryLock
|
|
231
|
-
if (!adapter) {
|
|
232
|
-
return fn()
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return adapter(workspaceId, fn)
|
|
236
|
-
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin database connect/disconnect helpers and runtime disconnect assembly.
|
|
3
|
+
*
|
|
4
|
+
* The plugin connect/disconnect helpers run inside the supplied
|
|
5
|
+
* `ManagedRuntime` so spans, logging, and layer context stay consistent with
|
|
6
|
+
* the rest of the SDK runtime. `createRuntimeDisconnect` instead drives the
|
|
7
|
+
* shutdown sequence through the caller-supplied `runPromiseWithCurrentContext`
|
|
8
|
+
* (currently `Effect.runPromiseWith(Context.empty())`), which intentionally
|
|
9
|
+
* does not preserve the SDK runtime context — by then the runtime is being
|
|
10
|
+
* torn down.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ManagedRuntime } from 'effect'
|
|
14
|
+
import { Effect } from 'effect'
|
|
15
|
+
|
|
16
|
+
import { clearAiGatewayRuntime } from '../ai-gateway/ai-gateway'
|
|
17
|
+
import { effectTryPromise } from '../effect/helpers'
|
|
18
|
+
import type { LotaPlugin } from './plugin-types'
|
|
19
|
+
|
|
20
|
+
// eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
|
|
21
|
+
type SdkManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
|
|
22
|
+
|
|
23
|
+
function getPluginLifecycleServices(plugin: LotaPlugin): Record<string, unknown> {
|
|
24
|
+
return plugin.services
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Build a plugin database connector that iterates the configured plugins and
|
|
29
|
+
* calls each `services.connectDatabase()` once, tracking completion in
|
|
30
|
+
* `connectedPluginDatabases` so repeated calls are idempotent.
|
|
31
|
+
*/
|
|
32
|
+
export function createPluginDatabaseConnector(
|
|
33
|
+
managedRuntime: SdkManagedRuntime,
|
|
34
|
+
pluginRuntime: Record<string, LotaPlugin>,
|
|
35
|
+
connectedPluginDatabases: Set<string>,
|
|
36
|
+
): () => Promise<void> {
|
|
37
|
+
return () =>
|
|
38
|
+
managedRuntime.runPromise(
|
|
39
|
+
Effect.gen(function* () {
|
|
40
|
+
for (const [pluginName, plugin] of Object.entries(pluginRuntime)) {
|
|
41
|
+
if (connectedPluginDatabases.has(pluginName)) {
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const services = getPluginLifecycleServices(plugin)
|
|
46
|
+
const connectDatabase = Reflect.get(services, 'connectDatabase')
|
|
47
|
+
if (typeof connectDatabase !== 'function') {
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const connectDatabaseFn = connectDatabase as (this: typeof services) => Promise<void>
|
|
52
|
+
yield* effectTryPromise(() => connectDatabaseFn.call(services))
|
|
53
|
+
connectedPluginDatabases.add(pluginName)
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Build a plugin database disconnector. Clears `connectedPluginDatabases`
|
|
61
|
+
* entries regardless of whether the plugin provides a `disconnectDatabase`
|
|
62
|
+
* hook, so the set stays in sync with actual connection state.
|
|
63
|
+
*/
|
|
64
|
+
export function createPluginDatabaseDisconnector(
|
|
65
|
+
managedRuntime: SdkManagedRuntime,
|
|
66
|
+
pluginRuntime: Record<string, LotaPlugin>,
|
|
67
|
+
connectedPluginDatabases: Set<string>,
|
|
68
|
+
): () => Promise<void> {
|
|
69
|
+
return () =>
|
|
70
|
+
managedRuntime.runPromise(
|
|
71
|
+
Effect.gen(function* () {
|
|
72
|
+
for (const [pluginName, plugin] of Object.entries(pluginRuntime)) {
|
|
73
|
+
if (!connectedPluginDatabases.has(pluginName)) {
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const services = getPluginLifecycleServices(plugin)
|
|
78
|
+
const disconnectDatabase = Reflect.get(services, 'disconnectDatabase')
|
|
79
|
+
if (typeof disconnectDatabase !== 'function') {
|
|
80
|
+
connectedPluginDatabases.delete(pluginName)
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const disconnectDatabaseFn = disconnectDatabase as (this: typeof services) => Promise<void>
|
|
85
|
+
yield* effectTryPromise(() => disconnectDatabaseFn.call(services))
|
|
86
|
+
connectedPluginDatabases.delete(pluginName)
|
|
87
|
+
}
|
|
88
|
+
}),
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface CreateDisconnectInput {
|
|
93
|
+
managedRuntime: SdkManagedRuntime
|
|
94
|
+
runPromiseWithCurrentContext: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
95
|
+
socialChatShutdown: () => Promise<void>
|
|
96
|
+
disconnectPluginDatabases: () => Promise<void>
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Compose the runtime `disconnect()` function. The returned function is
|
|
101
|
+
* idempotent: the first call starts the shutdown sequence, subsequent calls
|
|
102
|
+
* return the same in-flight promise.
|
|
103
|
+
*/
|
|
104
|
+
export function createRuntimeDisconnect(input: CreateDisconnectInput): () => Promise<void> {
|
|
105
|
+
const { managedRuntime, runPromiseWithCurrentContext, socialChatShutdown, disconnectPluginDatabases } = input
|
|
106
|
+
|
|
107
|
+
let disconnectPromise: Promise<void> | null = null
|
|
108
|
+
|
|
109
|
+
return () => {
|
|
110
|
+
if (disconnectPromise) {
|
|
111
|
+
return disconnectPromise
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
disconnectPromise = runPromiseWithCurrentContext(
|
|
115
|
+
Effect.gen(function* () {
|
|
116
|
+
yield* Effect.ignore(effectTryPromise(() => socialChatShutdown()))
|
|
117
|
+
yield* Effect.ignore(effectTryPromise(() => disconnectPluginDatabases()))
|
|
118
|
+
yield* effectTryPromise(() => managedRuntime.dispose())
|
|
119
|
+
yield* Effect.sync(() => clearAiGatewayRuntime())
|
|
120
|
+
}),
|
|
121
|
+
)
|
|
122
|
+
return disconnectPromise
|
|
123
|
+
}
|
|
124
|
+
}
|