@lota-sdk/core 0.4.8 → 0.4.10

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 (272) hide show
  1. package/package.json +11 -12
  2. package/src/ai/embedding-cache.ts +96 -22
  3. package/src/ai-gateway/ai-gateway.ts +766 -223
  4. package/src/config/agent-defaults.ts +189 -75
  5. package/src/config/agent-types.ts +54 -4
  6. package/src/config/background-processing.ts +1 -1
  7. package/src/config/constants.ts +8 -2
  8. package/src/config/index.ts +0 -1
  9. package/src/config/logger.ts +299 -19
  10. package/src/config/thread-defaults.ts +40 -20
  11. package/src/create-runtime.ts +200 -449
  12. package/src/db/base.service.ts +52 -28
  13. package/src/db/cursor-pagination.ts +71 -30
  14. package/src/db/memory-query-builder.ts +2 -1
  15. package/src/db/memory-store.helpers.ts +4 -7
  16. package/src/db/memory-store.ts +868 -601
  17. package/src/db/memory.ts +396 -280
  18. package/src/db/record-id.ts +32 -10
  19. package/src/db/schema-fingerprint.ts +30 -12
  20. package/src/db/service-normalization.ts +288 -0
  21. package/src/db/service.ts +912 -779
  22. package/src/db/startup.ts +153 -68
  23. package/src/db/transaction-conflict.ts +15 -0
  24. package/src/effect/awaitable-effect.ts +96 -0
  25. package/src/effect/errors.ts +121 -0
  26. package/src/effect/helpers.ts +123 -0
  27. package/src/effect/index.ts +24 -0
  28. package/src/effect/layers.ts +238 -0
  29. package/src/effect/runtime-ref.ts +25 -0
  30. package/src/effect/runtime.ts +46 -0
  31. package/src/effect/services.ts +61 -0
  32. package/src/effect/zod.ts +43 -0
  33. package/src/embeddings/provider.ts +128 -83
  34. package/src/index.ts +48 -1
  35. package/src/openrouter/direct-provider.ts +11 -35
  36. package/src/queues/autonomous-job.queue.ts +117 -73
  37. package/src/queues/context-compaction.queue.ts +50 -17
  38. package/src/queues/delayed-node-promotion.queue.ts +46 -17
  39. package/src/queues/document-processor.queue.ts +52 -77
  40. package/src/queues/memory-consolidation.queue.ts +47 -32
  41. package/src/queues/organization-learning.queue.ts +26 -4
  42. package/src/queues/plan-agent-heartbeat.queue.ts +71 -24
  43. package/src/queues/plan-scheduler.queue.ts +97 -33
  44. package/src/queues/post-chat-memory.queue.ts +56 -26
  45. package/src/queues/queue-factory.ts +227 -59
  46. package/src/queues/standalone-worker.ts +39 -0
  47. package/src/queues/title-generation.queue.ts +45 -11
  48. package/src/redis/connection.ts +182 -113
  49. package/src/redis/index.ts +6 -8
  50. package/src/redis/org-memory-lock.ts +60 -27
  51. package/src/redis/redis-lease-lock.ts +200 -121
  52. package/src/redis/runtime-connection.ts +20 -0
  53. package/src/redis/stream-context.ts +92 -46
  54. package/src/runtime/agent-identity-overrides.ts +2 -2
  55. package/src/runtime/agent-runtime-policy.ts +5 -2
  56. package/src/runtime/agent-stream-helpers.ts +24 -9
  57. package/src/runtime/chat-run-orchestration.ts +102 -19
  58. package/src/runtime/chat-run-registry.ts +36 -2
  59. package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
  60. package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +161 -94
  61. package/src/runtime/domain-layer.ts +192 -0
  62. package/src/runtime/execution-plan-visibility.ts +2 -2
  63. package/src/runtime/execution-plan.ts +42 -15
  64. package/src/runtime/graph-designer.ts +16 -4
  65. package/src/runtime/helper-model.ts +139 -48
  66. package/src/runtime/index.ts +7 -8
  67. package/src/runtime/indexed-repositories-policy.ts +3 -3
  68. package/src/runtime/{memory-block.ts → memory/memory-block.ts} +50 -36
  69. package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
  70. package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +54 -67
  71. package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
  72. package/src/runtime/memory/memory-scope.ts +53 -0
  73. package/src/runtime/plugin-resolution.ts +124 -25
  74. package/src/runtime/plugin-types.ts +9 -1
  75. package/src/runtime/post-turn-side-effects.ts +177 -130
  76. package/src/runtime/retrieval-adapters.ts +40 -6
  77. package/src/runtime/runtime-accessors.ts +92 -0
  78. package/src/runtime/runtime-config.ts +150 -61
  79. package/src/runtime/runtime-extensions.ts +23 -25
  80. package/src/runtime/runtime-lifecycle.ts +124 -0
  81. package/src/runtime/runtime-services.ts +386 -0
  82. package/src/runtime/runtime-token.ts +47 -0
  83. package/src/runtime/social-chat/social-chat-agent-runner.ts +159 -0
  84. package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +51 -20
  85. package/src/runtime/social-chat/social-chat.ts +630 -0
  86. package/src/runtime/specialist-runner.ts +36 -10
  87. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +433 -0
  88. package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
  89. package/src/runtime/thread-chat-helpers.ts +2 -2
  90. package/src/runtime/thread-plan-turn.ts +2 -1
  91. package/src/runtime/thread-turn-context.ts +183 -111
  92. package/src/runtime/turn-lifecycle.ts +93 -27
  93. package/src/services/agent-activity.service.ts +287 -203
  94. package/src/services/agent-executor.service.ts +253 -149
  95. package/src/services/artifact.service.ts +231 -149
  96. package/src/services/attachment.service.ts +171 -115
  97. package/src/services/autonomous-job.service.ts +890 -491
  98. package/src/services/background-work.service.ts +54 -0
  99. package/src/services/chat-run-registry.service.ts +13 -1
  100. package/src/services/context-compaction.service.ts +136 -86
  101. package/src/services/document-chunk.service.ts +151 -88
  102. package/src/services/execution-plan/execution-plan-approval.ts +26 -0
  103. package/src/services/execution-plan/execution-plan-context.ts +29 -0
  104. package/src/services/execution-plan/execution-plan-graph.ts +278 -0
  105. package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
  106. package/src/services/execution-plan/execution-plan-spec.ts +75 -0
  107. package/src/services/execution-plan/execution-plan.service.ts +1041 -0
  108. package/src/services/feedback-loop.service.ts +132 -76
  109. package/src/services/global-orchestrator.service.ts +101 -168
  110. package/src/services/graph-full-routing.ts +193 -0
  111. package/src/services/index.ts +19 -21
  112. package/src/services/institutional-memory.service.ts +213 -125
  113. package/src/services/learned-skill.service.ts +368 -260
  114. package/src/services/memory/memory-conversation.ts +95 -0
  115. package/src/services/memory/memory-errors.ts +27 -0
  116. package/src/services/memory/memory-org-memory.ts +50 -0
  117. package/src/services/memory/memory-preseeded.ts +86 -0
  118. package/src/services/memory/memory-rerank.ts +297 -0
  119. package/src/services/{memory-utils.ts → memory/memory-utils.ts} +6 -5
  120. package/src/services/memory/memory.service.ts +674 -0
  121. package/src/services/memory/rerank.service.ts +201 -0
  122. package/src/services/monitoring-window.service.ts +92 -70
  123. package/src/services/mutating-approval.service.ts +62 -53
  124. package/src/services/node-workspace.service.ts +141 -98
  125. package/src/services/notification.service.ts +29 -16
  126. package/src/services/organization-member.service.ts +120 -66
  127. package/src/services/organization.service.ts +153 -77
  128. package/src/services/ownership-dispatcher.service.ts +456 -263
  129. package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
  130. package/src/services/plan/plan-agent-query.service.ts +322 -0
  131. package/src/services/{plan-approval.service.ts → plan/plan-approval.service.ts} +45 -22
  132. package/src/services/plan/plan-artifact.service.ts +60 -0
  133. package/src/services/plan/plan-builder.service.ts +76 -0
  134. package/src/services/plan/plan-checkpoint.service.ts +103 -0
  135. package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
  136. package/src/services/plan/plan-completion-side-effects.ts +169 -0
  137. package/src/services/plan/plan-coordination.service.ts +181 -0
  138. package/src/services/plan/plan-cycle.service.ts +405 -0
  139. package/src/services/plan/plan-deadline.service.ts +533 -0
  140. package/src/services/plan/plan-event-delivery.service.ts +266 -0
  141. package/src/services/plan/plan-executor-context.ts +35 -0
  142. package/src/services/plan/plan-executor-graph.ts +522 -0
  143. package/src/services/plan/plan-executor-helpers.ts +307 -0
  144. package/src/services/plan/plan-executor-persistence.ts +209 -0
  145. package/src/services/plan/plan-executor.service.ts +1737 -0
  146. package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
  147. package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
  148. package/src/services/plan/plan-run-serialization.ts +15 -0
  149. package/src/services/plan/plan-run.service.ts +637 -0
  150. package/src/services/plan/plan-scheduler.service.ts +379 -0
  151. package/src/services/plan/plan-template.service.ts +224 -0
  152. package/src/services/plan/plan-transaction-events.ts +36 -0
  153. package/src/services/plan/plan-validator.service.ts +907 -0
  154. package/src/services/plan/plan-workspace.service.ts +131 -0
  155. package/src/services/plugin-executor.service.ts +102 -68
  156. package/src/services/quality-metrics.service.ts +112 -94
  157. package/src/services/queue-job.service.ts +288 -231
  158. package/src/services/recent-activity-title.service.ts +73 -36
  159. package/src/services/recent-activity.service.ts +274 -259
  160. package/src/services/skill-resolver.service.ts +38 -12
  161. package/src/services/social-chat-history.service.ts +190 -122
  162. package/src/services/system-executor.service.ts +96 -61
  163. package/src/services/thread/thread-active-run.ts +203 -0
  164. package/src/services/thread/thread-bootstrap.ts +385 -0
  165. package/src/services/thread/thread-listing.ts +199 -0
  166. package/src/services/thread/thread-memory-block.ts +130 -0
  167. package/src/services/thread/thread-message.service.ts +379 -0
  168. package/src/services/thread/thread-record-store.ts +155 -0
  169. package/src/services/thread/thread-title.service.ts +74 -0
  170. package/src/services/thread/thread-turn-execution.ts +280 -0
  171. package/src/services/thread/thread-turn-message-context.ts +73 -0
  172. package/src/services/thread/thread-turn-preparation.service.ts +1148 -0
  173. package/src/services/thread/thread-turn-streaming.ts +403 -0
  174. package/src/services/thread/thread-turn-tracing.ts +35 -0
  175. package/src/services/thread/thread-turn.ts +376 -0
  176. package/src/services/thread/thread.service.ts +344 -0
  177. package/src/services/user.service.ts +82 -32
  178. package/src/services/write-intent-validator.service.ts +63 -51
  179. package/src/storage/attachment-parser.ts +69 -27
  180. package/src/storage/attachment-storage.service.ts +334 -275
  181. package/src/storage/generated-document-storage.service.ts +66 -34
  182. package/src/system-agents/agent-result.ts +3 -1
  183. package/src/system-agents/context-compaction.agent.ts +3 -3
  184. package/src/system-agents/delegated-agent-factory.ts +159 -90
  185. package/src/system-agents/helper-agent-options.ts +1 -1
  186. package/src/system-agents/memory-reranker.agent.ts +3 -3
  187. package/src/system-agents/memory.agent.ts +3 -3
  188. package/src/system-agents/recent-activity-title-refiner.agent.ts +3 -3
  189. package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -3
  190. package/src/system-agents/skill-extractor.agent.ts +3 -3
  191. package/src/system-agents/skill-manager.agent.ts +3 -3
  192. package/src/system-agents/thread-router.agent.ts +157 -113
  193. package/src/system-agents/title-generator.agent.ts +3 -3
  194. package/src/tools/execution-plan.tool.ts +241 -171
  195. package/src/tools/fetch-webpage.tool.ts +29 -18
  196. package/src/tools/firecrawl-client.ts +26 -6
  197. package/src/tools/index.ts +1 -0
  198. package/src/tools/memory-block.tool.ts +14 -6
  199. package/src/tools/plan-approval.tool.ts +57 -47
  200. package/src/tools/read-file-parts.tool.ts +44 -33
  201. package/src/tools/remember-memory.tool.ts +65 -45
  202. package/src/tools/search-web.tool.ts +33 -22
  203. package/src/tools/search.tool.ts +41 -29
  204. package/src/tools/team-think.tool.ts +125 -84
  205. package/src/tools/user-questions.tool.ts +4 -3
  206. package/src/tools/web-tool-shared.ts +6 -0
  207. package/src/utils/async.ts +25 -22
  208. package/src/utils/crypto.ts +21 -0
  209. package/src/utils/date-time.ts +40 -1
  210. package/src/utils/errors.ts +111 -20
  211. package/src/utils/hono-error-handler.ts +24 -39
  212. package/src/utils/index.ts +2 -1
  213. package/src/utils/null-proto-record.ts +41 -0
  214. package/src/utils/sse-keepalive.ts +124 -21
  215. package/src/workers/bootstrap.ts +164 -52
  216. package/src/workers/memory-consolidation.worker.ts +325 -237
  217. package/src/workers/organization-learning.worker.ts +50 -16
  218. package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
  219. package/src/workers/regular-chat-memory-digest.runner.ts +185 -114
  220. package/src/workers/skill-extraction.runner.ts +176 -93
  221. package/src/workers/utils/file-section-chunker.ts +8 -10
  222. package/src/workers/utils/repo-structure-extractor.ts +349 -260
  223. package/src/workers/utils/repomix-file-sections.ts +2 -2
  224. package/src/workers/utils/thread-message-query.ts +97 -38
  225. package/src/workers/worker-utils.ts +74 -31
  226. package/src/config/debug-logger.ts +0 -47
  227. package/src/config/search.ts +0 -3
  228. package/src/redis/connection-accessor.ts +0 -26
  229. package/src/runtime/agent-types.ts +0 -1
  230. package/src/runtime/context-compaction-runtime.ts +0 -87
  231. package/src/runtime/memory-scope.ts +0 -43
  232. package/src/runtime/social-chat-agent-runner.ts +0 -118
  233. package/src/runtime/social-chat.ts +0 -516
  234. package/src/runtime/team-consultation-orchestrator.ts +0 -272
  235. package/src/services/adaptive-playbook.service.ts +0 -152
  236. package/src/services/artifact-provenance.service.ts +0 -172
  237. package/src/services/chat-attachments.service.ts +0 -17
  238. package/src/services/context-compaction-runtime.singleton.ts +0 -13
  239. package/src/services/execution-plan.service.ts +0 -1118
  240. package/src/services/memory.service.ts +0 -914
  241. package/src/services/plan-agent-heartbeat.service.ts +0 -136
  242. package/src/services/plan-agent-query.service.ts +0 -267
  243. package/src/services/plan-artifact.service.ts +0 -50
  244. package/src/services/plan-builder.service.ts +0 -67
  245. package/src/services/plan-checkpoint.service.ts +0 -81
  246. package/src/services/plan-completion-side-effects.ts +0 -80
  247. package/src/services/plan-coordination.service.ts +0 -157
  248. package/src/services/plan-cycle.service.ts +0 -284
  249. package/src/services/plan-deadline.service.ts +0 -430
  250. package/src/services/plan-event-delivery.service.ts +0 -166
  251. package/src/services/plan-executor.service.ts +0 -1950
  252. package/src/services/plan-run.service.ts +0 -515
  253. package/src/services/plan-scheduler.service.ts +0 -240
  254. package/src/services/plan-template.service.ts +0 -177
  255. package/src/services/plan-validator.service.ts +0 -818
  256. package/src/services/plan-workspace.service.ts +0 -83
  257. package/src/services/rerank.service.ts +0 -156
  258. package/src/services/thread-message.service.ts +0 -275
  259. package/src/services/thread-plan-registry.service.ts +0 -22
  260. package/src/services/thread-title.service.ts +0 -39
  261. package/src/services/thread-turn-preparation.service.ts +0 -1147
  262. package/src/services/thread-turn.ts +0 -172
  263. package/src/services/thread.service.ts +0 -869
  264. package/src/utils/env.ts +0 -8
  265. /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
  266. /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
  267. /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
  268. /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
  269. /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
  270. /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
  271. /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
  272. /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
@@ -1,19 +1,26 @@
1
1
  import type { ChatMessage } from '@lota-sdk/shared'
2
+ import { Schema, Effect } from 'effect'
2
3
 
3
- import { agentDisplayNames } from '../config/agent-defaults'
4
+ import type { ResolvedAgentConfig } from '../config/agent-defaults'
4
5
  import type { RecordIdRef } from '../db/record-id'
6
+ import { runPromise } from '../effect/runtime'
7
+ import { AgentConfigServiceTag, RuntimeAdaptersServiceTag } from '../effect/services'
5
8
  import { enqueueMemoryConsolidation } from '../queues/memory-consolidation.queue'
6
9
  import { enqueueRegularChatMemoryDigest, enqueueSkillExtraction } from '../queues/organization-learning.queue'
7
10
  import { enqueuePostChatMemory } from '../queues/post-chat-memory.queue'
8
11
  import { enqueueRecentActivityTitleRefinement } from '../queues/title-generation.queue'
12
+ import { RecentActivityServiceTag } from '../services/recent-activity.service'
13
+ import { ThreadServiceTag } from '../services/thread/thread.service'
14
+ import type { NormalizedThread, ThreadRecord } from '../services/thread/thread.types'
15
+ import { safeEnqueue } from '../utils/async'
16
+ import { nowEpochMillis, toIsoDateTimeString } from '../utils/date-time'
9
17
  import {
10
18
  shouldEnqueueMemoryConsolidation,
11
19
  shouldEnqueueMemoryExtraction,
12
20
  shouldEnqueueOnboardingPostChatMemory,
13
21
  shouldEnqueueRegularDigestForThread,
14
- } from '../runtime/memory-digest-policy'
15
- import { getRuntimeAdapters } from '../runtime/runtime-extensions'
16
- import { shouldEnqueueSkillExtraction } from '../runtime/skill-extraction-policy'
22
+ } from './memory/memory-digest-policy'
23
+ import { shouldEnqueueSkillExtraction } from './skill-extraction-policy'
17
24
  import {
18
25
  appendPersistedThreadContextToHistoryMessages,
19
26
  buildAgentHistoryMessages,
@@ -22,14 +29,28 @@ import {
22
29
  extractMessageText,
23
30
  readOptionalString,
24
31
  toHistoryMessages,
25
- } from '../runtime/thread-chat-helpers'
26
- import { recentActivityService } from '../services/recent-activity.service'
27
- import { threadService } from '../services/thread.service'
28
- import type { NormalizedThread, ThreadRecord } from '../services/thread.types'
29
- import { safeEnqueue } from '../utils/async'
30
- import { toIsoDateTimeString } from '../utils/date-time'
32
+ } from './thread-chat-helpers'
33
+
34
+ class PostTurnSideEffectsError extends Schema.TaggedErrorClass<PostTurnSideEffectsError>()('PostTurnSideEffectsError', {
35
+ message: Schema.String,
36
+ cause: Schema.Defect,
37
+ }) {}
38
+
39
+ function tryPostTurnSideEffect<A>(
40
+ message: string,
41
+ thunk: () => PromiseLike<A>,
42
+ ): Effect.Effect<A, PostTurnSideEffectsError> {
43
+ return Effect.tryPromise({
44
+ try: () => Promise.resolve(thunk()),
45
+ catch: (cause) => new PostTurnSideEffectsError({ message, cause }),
46
+ })
47
+ }
31
48
 
32
- function resolveDisplayName(agentId: string, overrides?: Partial<Record<string, string>>): string {
49
+ function resolveDisplayName(
50
+ agentConfig: ResolvedAgentConfig,
51
+ agentId: string,
52
+ overrides?: Partial<Record<string, string>>,
53
+ ): string {
33
54
  if (overrides && Object.hasOwn(overrides, agentId)) {
34
55
  const override = overrides[agentId]
35
56
  if (override !== undefined) {
@@ -37,7 +58,7 @@ function resolveDisplayName(agentId: string, overrides?: Partial<Record<string,
37
58
  }
38
59
  }
39
60
 
40
- return agentDisplayNames[agentId] ?? agentId
61
+ return agentConfig.displayNames[agentId] ?? agentId
41
62
  }
42
63
 
43
64
  function buildRecentActivityChatDeepLink(params: {
@@ -53,12 +74,13 @@ function buildRecentActivityChatDeepLink(params: {
53
74
  }
54
75
 
55
76
  function buildRecentActivityChatSystemTitle(params: {
77
+ agentConfig: ResolvedAgentConfig
56
78
  thread: NormalizedThread
57
79
  visibleAgentId: string
58
80
  agentDisplayNamesById?: Partial<Record<string, string>>
59
81
  }): string {
60
82
  if (params.thread.type === 'default') {
61
- return `Conversation with ${resolveDisplayName(params.visibleAgentId, params.agentDisplayNamesById)}`
83
+ return `Conversation with ${resolveDisplayName(params.agentConfig, params.visibleAgentId, params.agentDisplayNamesById)}`
62
84
  }
63
85
 
64
86
  return params.thread.title.trim() || 'Thread update'
@@ -92,132 +114,157 @@ interface PostTurnSideEffectsParams {
92
114
  agentDisplayNamesById?: Partial<Record<string, string>>
93
115
  }
94
116
 
95
- export async function runPostTurnSideEffects(params: PostTurnSideEffectsParams): Promise<void> {
96
- const recentHistory = await params.loadRecentHistory()
97
- const turnCount = await threadService.incrementTurnCount(params.threadRef)
98
- const agentMessages = buildAgentHistoryMessages(params.allAssistantMessages)
99
- const historyMessagesForMemory = appendPersistedThreadContextToHistoryMessages(toHistoryMessages(recentHistory), {
100
- compactionSummary: params.latestThreadRecord.compactionSummary,
101
- })
102
-
103
- const userMessageText = params.referenceUserMessage ? extractMessageText(params.referenceUserMessage).trim() : ''
104
- const readableUploads = params.listReadableUploads()
105
- const attachmentMetadataContext = buildReadableUploadMetadataContext(readableUploads)
106
- const hasAttachmentContext = Boolean(attachmentMetadataContext)
107
- const shouldExtractMemory = params.onboardingActive
108
- ? shouldEnqueueOnboardingPostChatMemory({
109
- onboardingActive: params.onboardingActive,
110
- userMessageText,
111
- hasAttachmentContext,
112
- agentMessageCount: agentMessages.length,
113
- })
114
- : shouldEnqueueMemoryExtraction({ onboardingActive: params.onboardingActive, turnCount }) &&
115
- userMessageText.length > 0
116
-
117
- if (shouldExtractMemory) {
118
- const memoryUserMessage = userMessageText || 'User uploaded attachment(s).'
119
- await safeEnqueue(
120
- () =>
121
- enqueuePostChatMemory({
122
- orgId: params.orgIdString,
123
- threadId: params.threadIdString,
124
- sourceId: params.referenceUserMessageId,
125
- onboardStatus: readOptionalString((params.workspace as { onboardStatus?: unknown }).onboardStatus),
126
- userMessage: memoryUserMessage,
127
- historyMessages: historyMessagesForMemory,
128
- agentMessages,
129
- memoryBlock: params.memoryBlock.trim() ? params.memoryBlock : undefined,
130
- attachmentContext: attachmentMetadataContext,
131
- }),
132
- { operationName: 'post-chat memory extraction enqueue' },
117
+ const runPostTurnSideEffectsEffect = (params: PostTurnSideEffectsParams) =>
118
+ Effect.gen(function* () {
119
+ const recentActivityService = yield* RecentActivityServiceTag
120
+ const threadService = yield* ThreadServiceTag
121
+ const agentConfig: ResolvedAgentConfig = yield* AgentConfigServiceTag
122
+ const runtimeAdapters = yield* RuntimeAdaptersServiceTag
123
+ const recentHistory = yield* tryPostTurnSideEffect('Failed to load recent thread history.', () =>
124
+ params.loadRecentHistory(),
133
125
  )
134
- }
135
-
136
- if (params.isUserTurn && params.referenceUserMessage) {
137
- const conversationSummary = buildConversationSummary({
138
- userMessageText,
139
- assistantMessages: params.allAssistantMessages,
126
+ const turnCount = yield* threadService.incrementTurnCount(params.threadRef)
127
+ const agentMessages = buildAgentHistoryMessages(params.allAssistantMessages)
128
+ const historyMessagesForMemory = appendPersistedThreadContextToHistoryMessages(toHistoryMessages(recentHistory), {
129
+ compactionSummary: params.latestThreadRecord.compactionSummary,
140
130
  })
141
- if (conversationSummary) {
142
- const effectiveAgentId = params.visibleThreadAgentId ?? params.defaultLeadAgentId
143
- const recentActivityResult = await recentActivityService.recordEvent({
144
- orgId: params.orgRef,
145
- userId: params.userRef,
146
- source: 'system',
147
- event: {
148
- sourceEventId: `chat-turn:${params.referenceUserMessageId}`,
149
- kind: 'chat.turn.completed',
150
- targetKind: 'thread',
151
- targetId: params.threadIdString,
152
- mergeKey: `thread:${params.threadIdString}`,
153
- title: buildRecentActivityChatSystemTitle({
154
- thread: params.thread,
155
- visibleAgentId: effectiveAgentId,
156
- agentDisplayNamesById: params.agentDisplayNamesById,
157
- }),
158
- sourceLabel: resolveDisplayName(effectiveAgentId, params.agentDisplayNamesById),
159
- deepLink: buildRecentActivityChatDeepLink({
160
- thread: params.thread,
161
- threadId: params.threadIdString,
162
- visibleAgentId: effectiveAgentId,
163
- }),
164
- metadata: {
165
- agentId: effectiveAgentId,
166
- agentName: resolveDisplayName(effectiveAgentId, params.agentDisplayNamesById),
167
- threadId: params.threadIdString,
168
- threadTitle: params.latestThreadRecord.title ?? params.thread.title,
169
- threadType: params.thread.type,
170
- ...(params.thread.threadType ? { coreType: params.thread.threadType } : {}),
171
- userMessageText,
172
- assistantSummary: conversationSummary,
173
- messageId: params.referenceUserMessageId,
174
- },
175
- occurredAt: toIsoDateTimeString(params.referenceUserMessage.metadata?.createdAt ?? Date.now()),
176
- },
177
- })
178
131
 
179
- await safeEnqueue(
180
- async () => {
181
- const enqueuePostChatOrgAction = getRuntimeAdapters().enqueuePostChatOrgAction
182
- if (!enqueuePostChatOrgAction) {
183
- return
184
- }
185
- const sourceCreatedAt = params.referenceUserMessage?.metadata?.createdAt ?? Date.now()
186
-
187
- await enqueuePostChatOrgAction({
188
- orgId: params.orgIdString,
189
- threadId: params.threadIdString,
190
- sourceId: params.referenceUserMessageId,
191
- sourceCreatedAt,
192
- conversationSummary,
193
- })
194
- },
195
- { operationName: 'post-chat org action enqueue' },
132
+ const userMessageText = params.referenceUserMessage ? extractMessageText(params.referenceUserMessage).trim() : ''
133
+ const readableUploads = params.listReadableUploads()
134
+ const attachmentMetadataContext = buildReadableUploadMetadataContext(readableUploads)
135
+ const hasAttachmentContext = Boolean(attachmentMetadataContext)
136
+ const shouldExtractMemory = params.onboardingActive
137
+ ? shouldEnqueueOnboardingPostChatMemory({
138
+ onboardingActive: params.onboardingActive,
139
+ userMessageText,
140
+ hasAttachmentContext,
141
+ agentMessageCount: agentMessages.length,
142
+ })
143
+ : shouldEnqueueMemoryExtraction({ onboardingActive: params.onboardingActive, turnCount }) &&
144
+ userMessageText.length > 0
145
+
146
+ if (shouldExtractMemory) {
147
+ const memoryUserMessage = userMessageText || 'User uploaded attachment(s).'
148
+ yield* tryPostTurnSideEffect('Failed to enqueue post-chat memory extraction.', () =>
149
+ safeEnqueue(
150
+ () =>
151
+ enqueuePostChatMemory({
152
+ orgId: params.orgIdString,
153
+ threadId: params.threadIdString,
154
+ sourceId: params.referenceUserMessageId,
155
+ onboardStatus: readOptionalString((params.workspace as { onboardStatus?: unknown }).onboardStatus),
156
+ userMessage: memoryUserMessage,
157
+ historyMessages: historyMessagesForMemory,
158
+ agentMessages,
159
+ memoryBlock: params.memoryBlock.trim() ? params.memoryBlock : undefined,
160
+ attachmentContext: attachmentMetadataContext,
161
+ }),
162
+ { operationName: 'post-chat memory extraction enqueue' },
163
+ ),
196
164
  )
165
+ }
197
166
 
198
- if (recentActivityService.isMeaningfulRefinementCandidate(recentActivityResult.item)) {
199
- await safeEnqueue(() => enqueueRecentActivityTitleRefinement({ activityId: recentActivityResult.item.id }), {
200
- operationName: 'recent activity title refinement enqueue',
167
+ const referenceUserMessage = params.referenceUserMessage
168
+ if (params.isUserTurn && referenceUserMessage) {
169
+ const conversationSummary = buildConversationSummary({
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
+ },
201
210
  })
211
+
212
+ yield* tryPostTurnSideEffect('Failed to enqueue post-chat org action.', () =>
213
+ safeEnqueue(
214
+ () => {
215
+ const enqueuePostChatOrgAction = runtimeAdapters.enqueuePostChatOrgAction
216
+ if (!enqueuePostChatOrgAction) {
217
+ return
218
+ }
219
+
220
+ const sourceCreatedAt = referenceUserMessage.metadata?.createdAt ?? nowEpochMillis()
221
+ return enqueuePostChatOrgAction({
222
+ orgId: params.orgIdString,
223
+ threadId: params.threadIdString,
224
+ sourceId: params.referenceUserMessageId,
225
+ sourceCreatedAt,
226
+ conversationSummary,
227
+ })
228
+ },
229
+ { operationName: 'post-chat org action enqueue' },
230
+ ),
231
+ )
232
+
233
+ if (recentActivityService.isMeaningfulRefinementCandidate(recentActivityResult.item)) {
234
+ yield* tryPostTurnSideEffect('Failed to enqueue recent activity title refinement.', () =>
235
+ safeEnqueue(() => enqueueRecentActivityTitleRefinement({ activityId: recentActivityResult.item.id }), {
236
+ operationName: 'recent activity title refinement enqueue',
237
+ }),
238
+ )
239
+ }
202
240
  }
203
241
  }
204
- }
205
242
 
206
- if (shouldEnqueueRegularDigestForThread({ onboardingActive: params.onboardingActive, turnCount })) {
207
- await safeEnqueue(() => enqueueRegularChatMemoryDigest({ orgId: params.orgIdString }), {
208
- operationName: 'regular chat memory digest enqueue',
209
- })
210
- }
243
+ if (shouldEnqueueRegularDigestForThread({ onboardingActive: params.onboardingActive, turnCount })) {
244
+ yield* tryPostTurnSideEffect('Failed to enqueue regular chat memory digest.', () =>
245
+ safeEnqueue(() => enqueueRegularChatMemoryDigest({ orgId: params.orgIdString }), {
246
+ operationName: 'regular chat memory digest enqueue',
247
+ }),
248
+ )
249
+ }
211
250
 
212
- if (shouldEnqueueSkillExtraction({ onboardingActive: params.onboardingActive, turnCount })) {
213
- await safeEnqueue(() => enqueueSkillExtraction({ orgId: params.orgIdString }), {
214
- operationName: 'skill extraction enqueue',
215
- })
216
- }
251
+ if (shouldEnqueueSkillExtraction({ onboardingActive: params.onboardingActive, turnCount })) {
252
+ yield* tryPostTurnSideEffect('Failed to enqueue skill extraction.', () =>
253
+ safeEnqueue(() => enqueueSkillExtraction({ orgId: params.orgIdString }), {
254
+ operationName: 'skill extraction enqueue',
255
+ }),
256
+ )
257
+ }
217
258
 
218
- if (shouldEnqueueMemoryConsolidation({ onboardingActive: params.onboardingActive, turnCount })) {
219
- await safeEnqueue(() => enqueueMemoryConsolidation({ scopeId: params.orgIdString }), {
220
- operationName: 'memory consolidation enqueue',
221
- })
222
- }
259
+ if (shouldEnqueueMemoryConsolidation({ onboardingActive: params.onboardingActive, turnCount })) {
260
+ yield* tryPostTurnSideEffect('Failed to enqueue memory consolidation.', () =>
261
+ safeEnqueue(() => enqueueMemoryConsolidation({ scopeId: params.orgIdString }), {
262
+ operationName: 'memory consolidation enqueue',
263
+ }),
264
+ )
265
+ }
266
+ })
267
+
268
+ export function runPostTurnSideEffects(params: PostTurnSideEffectsParams): Promise<void> {
269
+ return runPromise(runPostTurnSideEffectsEffect(params))
223
270
  }
@@ -1,6 +1,8 @@
1
- interface ScopedRetrievalTask<TCandidate> {
1
+ import { Schema, Effect } from 'effect'
2
+
3
+ interface ScopedRetrievalTask<TCandidate, E = never> {
2
4
  scopeTag: string
3
- retrieve: () => Promise<TCandidate[]>
5
+ retrieve: () => PromiseLike<TCandidate[]> | Effect.Effect<TCandidate[], E>
4
6
  }
5
7
 
6
8
  interface ScopedRetrievalResult<TCandidate> {
@@ -8,10 +10,42 @@ interface ScopedRetrievalResult<TCandidate> {
8
10
  candidates: TCandidate[]
9
11
  }
10
12
 
11
- export async function executeScopedRetrieval<TCandidate>(
12
- tasks: ScopedRetrievalTask<TCandidate>[],
13
- ): Promise<ScopedRetrievalResult<TCandidate>[]> {
14
- return Promise.all(tasks.map(async (task) => ({ scopeTag: task.scopeTag, candidates: await task.retrieve() })))
13
+ class ScopedRetrievalError extends Schema.TaggedErrorClass<ScopedRetrievalError>()('ScopedRetrievalError', {
14
+ scopeTag: Schema.String,
15
+ message: Schema.String,
16
+ cause: Schema.Defect,
17
+ }) {}
18
+
19
+ function toScopedRetrievalError(scopeTag: string, cause: unknown): ScopedRetrievalError {
20
+ return new ScopedRetrievalError({ scopeTag, message: cause instanceof Error ? cause.message : String(cause), cause })
21
+ }
22
+
23
+ export function executeScopedRetrieval<TCandidate, E>(
24
+ tasks: ScopedRetrievalTask<TCandidate, E>[],
25
+ ): Effect.Effect<ScopedRetrievalResult<TCandidate>[], ScopedRetrievalError> {
26
+ return Effect.forEach(
27
+ tasks,
28
+ (task) =>
29
+ Effect.suspend(() => {
30
+ try {
31
+ const result = task.retrieve()
32
+ if (Effect.isEffect(result)) {
33
+ return result.pipe(
34
+ Effect.mapError((cause) => toScopedRetrievalError(task.scopeTag, cause)),
35
+ Effect.map((candidates) => ({ scopeTag: task.scopeTag, candidates })),
36
+ )
37
+ }
38
+
39
+ return Effect.tryPromise({
40
+ try: () => result,
41
+ catch: (cause) => toScopedRetrievalError(task.scopeTag, cause),
42
+ }).pipe(Effect.map((candidates) => ({ scopeTag: task.scopeTag, candidates })))
43
+ } catch (cause) {
44
+ return Effect.fail(toScopedRetrievalError(task.scopeTag, cause))
45
+ }
46
+ }),
47
+ { concurrency: 'unbounded' },
48
+ )
15
49
  }
16
50
 
17
51
  export function countScopedRetrievalCandidates<TCandidate>(scoped: ScopedRetrievalResult<TCandidate>[]): number {
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Installs and tears down the SDK's module-level runtime accessors.
3
+ *
4
+ * Several SDK modules expose `configure*`/`clear*` pairs so host code can read
5
+ * runtime-resolved services synchronously (AI gateway, agent defaults,
6
+ * firecrawl, graph designer, queue jobs, runtime extensions, redis, thread
7
+ * defaults). `createLotaRuntime` wires them once at boot and clears them on
8
+ * disconnect; this module keeps both phases in a single place so they stay
9
+ * symmetric.
10
+ */
11
+
12
+ import type { Context, ManagedRuntime } from 'effect'
13
+ import { Effect } from 'effect'
14
+
15
+ import {
16
+ AiGatewayTag,
17
+ clearAiGatewayRuntimeAccessors,
18
+ configureAiGatewayRuntimeAccessors,
19
+ } from '../ai-gateway/ai-gateway'
20
+ import { clearAgentRuntimeDefaults, configureAgentRuntimeDefaults } from '../config/agent-defaults'
21
+ import { clearThreadRuntimeDefaults, configureThreadRuntimeDefaults } from '../config/thread-defaults'
22
+ import {
23
+ AgentConfigServiceTag,
24
+ AgentFactoryServiceTag,
25
+ RuntimeAdaptersServiceTag,
26
+ RuntimeWorkerExtensionsServiceTag,
27
+ ThreadConfigServiceTag,
28
+ ToolProvidersServiceTag,
29
+ TurnHooksServiceTag,
30
+ } from '../effect'
31
+ import type { RedisConnectionManager } from '../redis/connection'
32
+ import { clearRuntimeRedisManager, configureRuntimeRedisManager } from '../redis/runtime-connection'
33
+ import { QueueJobServiceTag } from '../services/queue-job.service'
34
+ import { FirecrawlTag, clearFirecrawlClient, configureFirecrawlClient } from '../tools/firecrawl-client'
35
+ import { clearQueueJobService, configureQueueJobService } from '../workers/worker-utils'
36
+ import { clearGraphDesigner, configureGraphDesigner } from './graph-designer'
37
+ import type { ResolvedLotaRuntimeConfig } from './runtime-config'
38
+ import { clearRuntimeExtensionsAccessors, configureRuntimeExtensionsAccessors } from './runtime-extensions'
39
+
40
+ // eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
41
+ type SdkManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
42
+
43
+ interface ConfigureRuntimeAccessorsInput {
44
+ managedRuntime: SdkManagedRuntime
45
+ runtimeConfig: ResolvedLotaRuntimeConfig
46
+ redisManager: RedisConnectionManager
47
+ }
48
+
49
+ /**
50
+ * Resolve every service the SDK exposes through module-level accessors and
51
+ * install them. Must be called after `setLotaSdkRuntime(managedRuntime)`.
52
+ */
53
+ export function configureRuntimeModuleAccessors(input: ConfigureRuntimeAccessorsInput): void {
54
+ const { managedRuntime, runtimeConfig, redisManager } = input
55
+ const resolve = <I, T>(tag: Context.Key<I, T>): T =>
56
+ // We know every tag is provided by the managed runtime; the cast bridges
57
+ // the erased service-set carried by `SdkManagedRuntime`.
58
+ managedRuntime.runSync(Effect.service(tag) as Effect.Effect<T, never, never>)
59
+
60
+ configureAiGatewayRuntimeAccessors({ aiGateway: resolve(AiGatewayTag), runtimeConfig })
61
+ configureAgentRuntimeDefaults({
62
+ agentConfig: resolve(AgentConfigServiceTag),
63
+ agentFactoryConfig: resolve(AgentFactoryServiceTag),
64
+ })
65
+ configureThreadRuntimeDefaults(resolve(ThreadConfigServiceTag))
66
+ configureRuntimeExtensionsAccessors({
67
+ adapters: resolve(RuntimeAdaptersServiceTag),
68
+ turnHooks: resolve(TurnHooksServiceTag),
69
+ toolProviders: resolve(ToolProvidersServiceTag),
70
+ extraWorkers: resolve(RuntimeWorkerExtensionsServiceTag),
71
+ })
72
+ configureFirecrawlClient(resolve(FirecrawlTag))
73
+ configureQueueJobService(resolve(QueueJobServiceTag))
74
+ configureRuntimeRedisManager(redisManager)
75
+ configureGraphDesigner(runtimeConfig.graphDesigner)
76
+ }
77
+
78
+ /**
79
+ * Clears every module-level accessor installed by
80
+ * `configureRuntimeModuleAccessors`. Always safe to call (idempotent per clear
81
+ * function).
82
+ */
83
+ export function clearRuntimeModuleAccessors(): void {
84
+ clearAiGatewayRuntimeAccessors()
85
+ clearAgentRuntimeDefaults()
86
+ clearFirecrawlClient()
87
+ clearGraphDesigner()
88
+ clearQueueJobService()
89
+ clearRuntimeExtensionsAccessors()
90
+ clearRuntimeRedisManager()
91
+ clearThreadRuntimeDefaults()
92
+ }