@lota-sdk/core 0.4.8 → 0.4.9

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 (259) hide show
  1. package/package.json +11 -12
  2. package/src/ai/embedding-cache.ts +94 -22
  3. package/src/ai-gateway/ai-gateway.ts +738 -223
  4. package/src/config/agent-defaults.ts +176 -75
  5. package/src/config/agent-types.ts +54 -4
  6. package/src/config/constants.ts +8 -2
  7. package/src/config/logger.ts +286 -19
  8. package/src/config/thread-defaults.ts +33 -21
  9. package/src/create-runtime.ts +725 -387
  10. package/src/db/base.service.ts +52 -28
  11. package/src/db/cursor-pagination.ts +71 -30
  12. package/src/db/memory-store.helpers.ts +4 -7
  13. package/src/db/memory-store.ts +856 -598
  14. package/src/db/memory.ts +398 -275
  15. package/src/db/record-id.ts +32 -10
  16. package/src/db/schema-fingerprint.ts +30 -12
  17. package/src/db/service-normalization.ts +255 -0
  18. package/src/db/service.ts +726 -761
  19. package/src/db/startup.ts +140 -66
  20. package/src/db/transaction-conflict.ts +15 -0
  21. package/src/effect/awaitable-effect.ts +87 -0
  22. package/src/effect/errors.ts +121 -0
  23. package/src/effect/helpers.ts +98 -0
  24. package/src/effect/index.ts +22 -0
  25. package/src/effect/layers.ts +228 -0
  26. package/src/effect/runtime-ref.ts +25 -0
  27. package/src/effect/runtime.ts +31 -0
  28. package/src/effect/services.ts +57 -0
  29. package/src/effect/zod.ts +43 -0
  30. package/src/embeddings/provider.ts +122 -76
  31. package/src/index.ts +46 -1
  32. package/src/openrouter/direct-provider.ts +11 -35
  33. package/src/queues/autonomous-job.queue.ts +130 -74
  34. package/src/queues/context-compaction.queue.ts +60 -15
  35. package/src/queues/delayed-node-promotion.queue.ts +52 -15
  36. package/src/queues/document-processor.queue.ts +52 -77
  37. package/src/queues/memory-consolidation.queue.ts +47 -32
  38. package/src/queues/organization-learning.queue.ts +13 -4
  39. package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
  40. package/src/queues/plan-scheduler.queue.ts +107 -31
  41. package/src/queues/post-chat-memory.queue.ts +66 -24
  42. package/src/queues/queue-factory.ts +142 -52
  43. package/src/queues/standalone-worker.ts +39 -0
  44. package/src/queues/title-generation.queue.ts +54 -9
  45. package/src/redis/connection.ts +84 -32
  46. package/src/redis/index.ts +6 -8
  47. package/src/redis/org-memory-lock.ts +60 -27
  48. package/src/redis/redis-lease-lock.ts +200 -121
  49. package/src/redis/runtime-connection.ts +10 -0
  50. package/src/redis/stream-context.ts +84 -46
  51. package/src/runtime/agent-identity-overrides.ts +2 -2
  52. package/src/runtime/agent-runtime-policy.ts +4 -1
  53. package/src/runtime/agent-stream-helpers.ts +20 -9
  54. package/src/runtime/chat-run-orchestration.ts +102 -19
  55. package/src/runtime/chat-run-registry.ts +36 -2
  56. package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
  57. package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
  58. package/src/runtime/execution-plan-visibility.ts +2 -2
  59. package/src/runtime/execution-plan.ts +42 -15
  60. package/src/runtime/graph-designer.ts +11 -7
  61. package/src/runtime/helper-model.ts +135 -48
  62. package/src/runtime/index.ts +7 -7
  63. package/src/runtime/indexed-repositories-policy.ts +3 -3
  64. package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
  65. package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
  66. package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
  67. package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
  68. package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
  69. package/src/runtime/plugin-resolution.ts +144 -24
  70. package/src/runtime/plugin-types.ts +9 -1
  71. package/src/runtime/post-turn-side-effects.ts +197 -130
  72. package/src/runtime/retrieval-adapters.ts +38 -4
  73. package/src/runtime/runtime-config.ts +150 -61
  74. package/src/runtime/runtime-extensions.ts +21 -34
  75. package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
  76. package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
  77. package/src/runtime/social-chat/social-chat.ts +594 -0
  78. package/src/runtime/specialist-runner.ts +36 -10
  79. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
  80. package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
  81. package/src/runtime/thread-chat-helpers.ts +2 -2
  82. package/src/runtime/thread-plan-turn.ts +2 -1
  83. package/src/runtime/thread-turn-context.ts +172 -94
  84. package/src/runtime/turn-lifecycle.ts +93 -27
  85. package/src/services/agent-activity.service.ts +287 -203
  86. package/src/services/agent-executor.service.ts +329 -217
  87. package/src/services/artifact.service.ts +225 -148
  88. package/src/services/attachment.service.ts +137 -115
  89. package/src/services/autonomous-job.service.ts +888 -491
  90. package/src/services/chat-run-registry.service.ts +11 -1
  91. package/src/services/context-compaction.service.ts +136 -86
  92. package/src/services/document-chunk.service.ts +162 -90
  93. package/src/services/execution-plan/execution-plan-approval.ts +26 -0
  94. package/src/services/execution-plan/execution-plan-context.ts +29 -0
  95. package/src/services/execution-plan/execution-plan-graph.ts +256 -0
  96. package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
  97. package/src/services/execution-plan/execution-plan-spec.ts +75 -0
  98. package/src/services/execution-plan/execution-plan.service.ts +1041 -0
  99. package/src/services/feedback-loop.service.ts +132 -76
  100. package/src/services/global-orchestrator.service.ts +80 -170
  101. package/src/services/graph-full-routing.ts +182 -0
  102. package/src/services/index.ts +18 -21
  103. package/src/services/institutional-memory.service.ts +220 -123
  104. package/src/services/learned-skill.service.ts +364 -259
  105. package/src/services/memory/memory-conversation.ts +95 -0
  106. package/src/services/memory/memory-org-memory.ts +39 -0
  107. package/src/services/memory/memory-preseeded.ts +80 -0
  108. package/src/services/memory/memory-rerank.ts +297 -0
  109. package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
  110. package/src/services/memory/memory.service.ts +692 -0
  111. package/src/services/memory/rerank.service.ts +209 -0
  112. package/src/services/monitoring-window.service.ts +92 -70
  113. package/src/services/mutating-approval.service.ts +62 -53
  114. package/src/services/node-workspace.service.ts +141 -98
  115. package/src/services/notification.service.ts +17 -16
  116. package/src/services/organization-member.service.ts +120 -66
  117. package/src/services/organization.service.ts +144 -51
  118. package/src/services/ownership-dispatcher.service.ts +415 -264
  119. package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
  120. package/src/services/plan/plan-agent-query.service.ts +322 -0
  121. package/src/services/plan/plan-approval.service.ts +102 -0
  122. package/src/services/plan/plan-artifact.service.ts +60 -0
  123. package/src/services/plan/plan-builder.service.ts +76 -0
  124. package/src/services/plan/plan-checkpoint.service.ts +103 -0
  125. package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
  126. package/src/services/plan/plan-completion-side-effects.ts +175 -0
  127. package/src/services/plan/plan-coordination.service.ts +181 -0
  128. package/src/services/plan/plan-cycle.service.ts +398 -0
  129. package/src/services/plan/plan-deadline.service.ts +547 -0
  130. package/src/services/plan/plan-event-delivery.service.ts +261 -0
  131. package/src/services/plan/plan-executor-context.ts +35 -0
  132. package/src/services/plan/plan-executor-graph.ts +475 -0
  133. package/src/services/plan/plan-executor-helpers.ts +322 -0
  134. package/src/services/plan/plan-executor-persistence.ts +209 -0
  135. package/src/services/plan/plan-executor.service.ts +1654 -0
  136. package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
  137. package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
  138. package/src/services/plan/plan-run-serialization.ts +15 -0
  139. package/src/services/plan/plan-run.service.ts +644 -0
  140. package/src/services/plan/plan-scheduler.service.ts +385 -0
  141. package/src/services/plan/plan-template.service.ts +224 -0
  142. package/src/services/plan/plan-transaction-events.ts +33 -0
  143. package/src/services/plan/plan-validator.service.ts +907 -0
  144. package/src/services/plan/plan-workspace.service.ts +125 -0
  145. package/src/services/plugin-executor.service.ts +97 -68
  146. package/src/services/quality-metrics.service.ts +112 -94
  147. package/src/services/queue-job.service.ts +296 -230
  148. package/src/services/recent-activity-title.service.ts +65 -36
  149. package/src/services/recent-activity.service.ts +274 -259
  150. package/src/services/skill-resolver.service.ts +38 -12
  151. package/src/services/social-chat-history.service.ts +176 -125
  152. package/src/services/system-executor.service.ts +91 -61
  153. package/src/services/thread/thread-active-run.ts +203 -0
  154. package/src/services/thread/thread-bootstrap.ts +369 -0
  155. package/src/services/thread/thread-listing.ts +198 -0
  156. package/src/services/thread/thread-memory-block.ts +117 -0
  157. package/src/services/thread/thread-message.service.ts +363 -0
  158. package/src/services/thread/thread-record-store.ts +155 -0
  159. package/src/services/thread/thread-title.service.ts +74 -0
  160. package/src/services/thread/thread-turn-execution.ts +280 -0
  161. package/src/services/thread/thread-turn-message-context.ts +73 -0
  162. package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
  163. package/src/services/thread/thread-turn-streaming.ts +402 -0
  164. package/src/services/thread/thread-turn-tracing.ts +35 -0
  165. package/src/services/thread/thread-turn.ts +343 -0
  166. package/src/services/thread/thread.service.ts +335 -0
  167. package/src/services/user.service.ts +82 -32
  168. package/src/services/write-intent-validator.service.ts +63 -51
  169. package/src/storage/attachment-parser.ts +69 -27
  170. package/src/storage/attachment-storage.service.ts +331 -275
  171. package/src/storage/generated-document-storage.service.ts +66 -34
  172. package/src/system-agents/agent-result.ts +3 -1
  173. package/src/system-agents/context-compaction.agent.ts +2 -2
  174. package/src/system-agents/delegated-agent-factory.ts +159 -90
  175. package/src/system-agents/memory-reranker.agent.ts +2 -2
  176. package/src/system-agents/memory.agent.ts +2 -2
  177. package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
  178. package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
  179. package/src/system-agents/skill-extractor.agent.ts +2 -2
  180. package/src/system-agents/skill-manager.agent.ts +2 -2
  181. package/src/system-agents/thread-router.agent.ts +157 -113
  182. package/src/system-agents/title-generator.agent.ts +2 -2
  183. package/src/tools/execution-plan.tool.ts +220 -161
  184. package/src/tools/fetch-webpage.tool.ts +21 -17
  185. package/src/tools/firecrawl-client.ts +16 -6
  186. package/src/tools/index.ts +1 -0
  187. package/src/tools/memory-block.tool.ts +14 -6
  188. package/src/tools/plan-approval.tool.ts +49 -47
  189. package/src/tools/read-file-parts.tool.ts +44 -33
  190. package/src/tools/remember-memory.tool.ts +65 -45
  191. package/src/tools/search-web.tool.ts +26 -22
  192. package/src/tools/search.tool.ts +41 -29
  193. package/src/tools/team-think.tool.ts +124 -83
  194. package/src/tools/user-questions.tool.ts +4 -3
  195. package/src/tools/web-tool-shared.ts +6 -0
  196. package/src/utils/async.ts +17 -23
  197. package/src/utils/crypto.ts +21 -0
  198. package/src/utils/date-time.ts +40 -1
  199. package/src/utils/errors.ts +95 -16
  200. package/src/utils/hono-error-handler.ts +24 -39
  201. package/src/utils/index.ts +2 -1
  202. package/src/utils/null-proto-record.ts +41 -0
  203. package/src/utils/sse-keepalive.ts +124 -21
  204. package/src/workers/bootstrap.ts +186 -51
  205. package/src/workers/memory-consolidation.worker.ts +325 -237
  206. package/src/workers/organization-learning.worker.ts +50 -16
  207. package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
  208. package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
  209. package/src/workers/skill-extraction.runner.ts +176 -93
  210. package/src/workers/utils/file-section-chunker.ts +8 -10
  211. package/src/workers/utils/repo-structure-extractor.ts +349 -260
  212. package/src/workers/utils/repomix-file-sections.ts +2 -2
  213. package/src/workers/utils/thread-message-query.ts +97 -38
  214. package/src/workers/worker-utils.ts +56 -31
  215. package/src/config/debug-logger.ts +0 -47
  216. package/src/redis/connection-accessor.ts +0 -26
  217. package/src/runtime/context-compaction-runtime.ts +0 -87
  218. package/src/runtime/social-chat-agent-runner.ts +0 -118
  219. package/src/runtime/social-chat.ts +0 -516
  220. package/src/runtime/team-consultation-orchestrator.ts +0 -272
  221. package/src/services/adaptive-playbook.service.ts +0 -152
  222. package/src/services/artifact-provenance.service.ts +0 -172
  223. package/src/services/chat-attachments.service.ts +0 -17
  224. package/src/services/context-compaction-runtime.singleton.ts +0 -13
  225. package/src/services/execution-plan.service.ts +0 -1118
  226. package/src/services/memory.service.ts +0 -914
  227. package/src/services/plan-agent-heartbeat.service.ts +0 -136
  228. package/src/services/plan-agent-query.service.ts +0 -267
  229. package/src/services/plan-approval.service.ts +0 -83
  230. package/src/services/plan-artifact.service.ts +0 -50
  231. package/src/services/plan-builder.service.ts +0 -67
  232. package/src/services/plan-checkpoint.service.ts +0 -81
  233. package/src/services/plan-completion-side-effects.ts +0 -80
  234. package/src/services/plan-coordination.service.ts +0 -157
  235. package/src/services/plan-cycle.service.ts +0 -284
  236. package/src/services/plan-deadline.service.ts +0 -430
  237. package/src/services/plan-event-delivery.service.ts +0 -166
  238. package/src/services/plan-executor.service.ts +0 -1950
  239. package/src/services/plan-run.service.ts +0 -515
  240. package/src/services/plan-scheduler.service.ts +0 -240
  241. package/src/services/plan-template.service.ts +0 -177
  242. package/src/services/plan-validator.service.ts +0 -818
  243. package/src/services/plan-workspace.service.ts +0 -83
  244. package/src/services/rerank.service.ts +0 -156
  245. package/src/services/thread-message.service.ts +0 -275
  246. package/src/services/thread-plan-registry.service.ts +0 -22
  247. package/src/services/thread-title.service.ts +0 -39
  248. package/src/services/thread-turn-preparation.service.ts +0 -1147
  249. package/src/services/thread-turn.ts +0 -172
  250. package/src/services/thread.service.ts +0 -869
  251. package/src/utils/env.ts +0 -8
  252. /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
  253. /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
  254. /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
  255. /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
  256. /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
  257. /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
  258. /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
  259. /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
@@ -1,19 +1,28 @@
1
1
  import type { ChatMessage } from '@lota-sdk/shared'
2
+ import { Schema, Effect } from 'effect'
3
+ import type { Context } from 'effect'
2
4
 
3
- import { agentDisplayNames } from '../config/agent-defaults'
5
+ import type { ResolvedAgentConfig } from '../config/agent-defaults'
4
6
  import type { RecordIdRef } from '../db/record-id'
7
+ import { getCurrentRuntime } from '../effect/runtime-ref'
8
+ import { AgentConfigServiceTag, RuntimeAdaptersServiceTag } from '../effect/services'
5
9
  import { enqueueMemoryConsolidation } from '../queues/memory-consolidation.queue'
6
10
  import { enqueueRegularChatMemoryDigest, enqueueSkillExtraction } from '../queues/organization-learning.queue'
7
11
  import { enqueuePostChatMemory } from '../queues/post-chat-memory.queue'
8
12
  import { enqueueRecentActivityTitleRefinement } from '../queues/title-generation.queue'
13
+ import { RecentActivityServiceTag } from '../services/recent-activity.service'
14
+ import { ThreadServiceTag } from '../services/thread/thread.service'
15
+ import type { NormalizedThread, ThreadRecord } from '../services/thread/thread.types'
16
+ import { safeEnqueue } from '../utils/async'
17
+ import { nowEpochMillis, toIsoDateTimeString } from '../utils/date-time'
9
18
  import {
10
19
  shouldEnqueueMemoryConsolidation,
11
20
  shouldEnqueueMemoryExtraction,
12
21
  shouldEnqueueOnboardingPostChatMemory,
13
22
  shouldEnqueueRegularDigestForThread,
14
- } from '../runtime/memory-digest-policy'
15
- import { getRuntimeAdapters } from '../runtime/runtime-extensions'
16
- import { shouldEnqueueSkillExtraction } from '../runtime/skill-extraction-policy'
23
+ } from './memory/memory-digest-policy'
24
+ import type { LotaRuntimeAdapters } from './runtime-extensions'
25
+ import { shouldEnqueueSkillExtraction } from './skill-extraction-policy'
17
26
  import {
18
27
  appendPersistedThreadContextToHistoryMessages,
19
28
  buildAgentHistoryMessages,
@@ -22,14 +31,49 @@ import {
22
31
  extractMessageText,
23
32
  readOptionalString,
24
33
  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'
34
+ } from './thread-chat-helpers'
35
+
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
+ class PostTurnSideEffectsError extends Schema.TaggedErrorClass<PostTurnSideEffectsError>()('PostTurnSideEffectsError', {
44
+ message: Schema.String,
45
+ cause: Schema.Defect,
46
+ }) {}
47
+
48
+ function tryPostTurnSideEffect<A>(
49
+ message: string,
50
+ thunk: () => PromiseLike<A>,
51
+ ): Effect.Effect<A, PostTurnSideEffectsError> {
52
+ return Effect.tryPromise({
53
+ try: () => Promise.resolve(thunk()),
54
+ catch: (cause) => new PostTurnSideEffectsError({ message, cause }),
55
+ })
56
+ }
57
+
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
+ }
31
71
 
32
- function resolveDisplayName(agentId: string, overrides?: Partial<Record<string, string>>): string {
72
+ function resolveDisplayName(
73
+ agentConfig: ResolvedAgentConfig,
74
+ agentId: string,
75
+ overrides?: Partial<Record<string, string>>,
76
+ ): string {
33
77
  if (overrides && Object.hasOwn(overrides, agentId)) {
34
78
  const override = overrides[agentId]
35
79
  if (override !== undefined) {
@@ -37,7 +81,7 @@ function resolveDisplayName(agentId: string, overrides?: Partial<Record<string,
37
81
  }
38
82
  }
39
83
 
40
- return agentDisplayNames[agentId] ?? agentId
84
+ return agentConfig.displayNames[agentId] ?? agentId
41
85
  }
42
86
 
43
87
  function buildRecentActivityChatDeepLink(params: {
@@ -53,12 +97,13 @@ function buildRecentActivityChatDeepLink(params: {
53
97
  }
54
98
 
55
99
  function buildRecentActivityChatSystemTitle(params: {
100
+ agentConfig: ResolvedAgentConfig
56
101
  thread: NormalizedThread
57
102
  visibleAgentId: string
58
103
  agentDisplayNamesById?: Partial<Record<string, string>>
59
104
  }): string {
60
105
  if (params.thread.type === 'default') {
61
- return `Conversation with ${resolveDisplayName(params.visibleAgentId, params.agentDisplayNamesById)}`
106
+ return `Conversation with ${resolveDisplayName(params.agentConfig, params.visibleAgentId, params.agentDisplayNamesById)}`
62
107
  }
63
108
 
64
109
  return params.thread.title.trim() || 'Thread update'
@@ -92,132 +137,154 @@ interface PostTurnSideEffectsParams {
92
137
  agentDisplayNamesById?: Partial<Record<string, string>>
93
138
  }
94
139
 
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' },
140
+ const runPostTurnSideEffectsEffect = (params: PostTurnSideEffectsParams) =>
141
+ Effect.gen(function* () {
142
+ const { recentActivityService, threadService, agentConfig, runtimeAdapters } = getPostTurnSideEffectsServices()
143
+ const recentHistory = yield* tryPostTurnSideEffect('Failed to load recent thread history.', () =>
144
+ params.loadRecentHistory(),
133
145
  )
134
- }
135
-
136
- if (params.isUserTurn && params.referenceUserMessage) {
137
- const conversationSummary = buildConversationSummary({
138
- userMessageText,
139
- assistantMessages: params.allAssistantMessages,
146
+ const turnCount = yield* threadService.incrementTurnCount(params.threadRef)
147
+ const agentMessages = buildAgentHistoryMessages(params.allAssistantMessages)
148
+ const historyMessagesForMemory = appendPersistedThreadContextToHistoryMessages(toHistoryMessages(recentHistory), {
149
+ compactionSummary: params.latestThreadRecord.compactionSummary,
140
150
  })
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
151
 
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' },
152
+ const userMessageText = params.referenceUserMessage ? extractMessageText(params.referenceUserMessage).trim() : ''
153
+ const readableUploads = params.listReadableUploads()
154
+ const attachmentMetadataContext = buildReadableUploadMetadataContext(readableUploads)
155
+ const hasAttachmentContext = Boolean(attachmentMetadataContext)
156
+ const shouldExtractMemory = params.onboardingActive
157
+ ? shouldEnqueueOnboardingPostChatMemory({
158
+ onboardingActive: params.onboardingActive,
159
+ userMessageText,
160
+ hasAttachmentContext,
161
+ agentMessageCount: agentMessages.length,
162
+ })
163
+ : shouldEnqueueMemoryExtraction({ onboardingActive: params.onboardingActive, turnCount }) &&
164
+ userMessageText.length > 0
165
+
166
+ if (shouldExtractMemory) {
167
+ const memoryUserMessage = userMessageText || 'User uploaded attachment(s).'
168
+ yield* tryPostTurnSideEffect('Failed to enqueue post-chat memory extraction.', () =>
169
+ safeEnqueue(
170
+ () =>
171
+ enqueuePostChatMemory({
172
+ orgId: params.orgIdString,
173
+ threadId: params.threadIdString,
174
+ sourceId: params.referenceUserMessageId,
175
+ onboardStatus: readOptionalString((params.workspace as { onboardStatus?: unknown }).onboardStatus),
176
+ userMessage: memoryUserMessage,
177
+ historyMessages: historyMessagesForMemory,
178
+ agentMessages,
179
+ memoryBlock: params.memoryBlock.trim() ? params.memoryBlock : undefined,
180
+ attachmentContext: attachmentMetadataContext,
181
+ }),
182
+ { operationName: 'post-chat memory extraction enqueue' },
183
+ ),
196
184
  )
185
+ }
197
186
 
198
- if (recentActivityService.isMeaningfulRefinementCandidate(recentActivityResult.item)) {
199
- await safeEnqueue(() => enqueueRecentActivityTitleRefinement({ activityId: recentActivityResult.item.id }), {
200
- operationName: 'recent activity title refinement enqueue',
187
+ const referenceUserMessage = params.referenceUserMessage
188
+ if (params.isUserTurn && referenceUserMessage) {
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
+ },
201
230
  })
231
+
232
+ yield* tryPostTurnSideEffect('Failed to enqueue post-chat org action.', () =>
233
+ safeEnqueue(
234
+ () => {
235
+ const enqueuePostChatOrgAction = runtimeAdapters.enqueuePostChatOrgAction
236
+ if (!enqueuePostChatOrgAction) {
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' },
250
+ ),
251
+ )
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
+ }
202
260
  }
203
261
  }
204
- }
205
262
 
206
- if (shouldEnqueueRegularDigestForThread({ onboardingActive: params.onboardingActive, turnCount })) {
207
- await safeEnqueue(() => enqueueRegularChatMemoryDigest({ orgId: params.orgIdString }), {
208
- operationName: 'regular chat memory digest enqueue',
209
- })
210
- }
263
+ if (shouldEnqueueRegularDigestForThread({ onboardingActive: params.onboardingActive, turnCount })) {
264
+ yield* tryPostTurnSideEffect('Failed to enqueue regular chat memory digest.', () =>
265
+ safeEnqueue(() => enqueueRegularChatMemoryDigest({ orgId: params.orgIdString }), {
266
+ operationName: 'regular chat memory digest enqueue',
267
+ }),
268
+ )
269
+ }
211
270
 
212
- if (shouldEnqueueSkillExtraction({ onboardingActive: params.onboardingActive, turnCount })) {
213
- await safeEnqueue(() => enqueueSkillExtraction({ orgId: params.orgIdString }), {
214
- operationName: 'skill extraction enqueue',
215
- })
216
- }
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
+ }
217
278
 
218
- if (shouldEnqueueMemoryConsolidation({ onboardingActive: params.onboardingActive, turnCount })) {
219
- await safeEnqueue(() => enqueueMemoryConsolidation({ scopeId: params.orgIdString }), {
220
- operationName: 'memory consolidation enqueue',
221
- })
222
- }
279
+ if (shouldEnqueueMemoryConsolidation({ onboardingActive: params.onboardingActive, turnCount })) {
280
+ yield* tryPostTurnSideEffect('Failed to enqueue memory consolidation.', () =>
281
+ safeEnqueue(() => enqueueMemoryConsolidation({ scopeId: params.orgIdString }), {
282
+ operationName: 'memory consolidation enqueue',
283
+ }),
284
+ )
285
+ }
286
+ })
287
+
288
+ export function runPostTurnSideEffects(params: PostTurnSideEffectsParams): Promise<void> {
289
+ return Effect.runPromise(runPostTurnSideEffectsEffect(params))
223
290
  }
@@ -1,6 +1,8 @@
1
+ import { Schema, Effect } from 'effect'
2
+
1
3
  interface ScopedRetrievalTask<TCandidate> {
2
4
  scopeTag: string
3
- retrieve: () => Promise<TCandidate[]>
5
+ retrieve: () => PromiseLike<TCandidate[]> | Effect.Effect<TCandidate[], unknown>
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>(
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>(
12
24
  tasks: ScopedRetrievalTask<TCandidate>[],
13
- ): Promise<ScopedRetrievalResult<TCandidate>[]> {
14
- return Promise.all(tasks.map(async (task) => ({ scopeTag: task.scopeTag, candidates: await task.retrieve() })))
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 {