@lota-sdk/core 0.4.9 → 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 (158) hide show
  1. package/package.json +2 -2
  2. package/src/ai/embedding-cache.ts +3 -1
  3. package/src/ai-gateway/ai-gateway.ts +38 -10
  4. package/src/config/agent-defaults.ts +22 -9
  5. package/src/config/agent-types.ts +1 -1
  6. package/src/config/background-processing.ts +1 -1
  7. package/src/config/index.ts +0 -1
  8. package/src/config/logger.ts +20 -7
  9. package/src/config/thread-defaults.ts +12 -4
  10. package/src/create-runtime.ts +69 -656
  11. package/src/db/memory-query-builder.ts +2 -1
  12. package/src/db/memory-store.ts +29 -20
  13. package/src/db/memory.ts +188 -195
  14. package/src/db/service-normalization.ts +97 -64
  15. package/src/db/service.ts +706 -538
  16. package/src/db/startup.ts +30 -19
  17. package/src/effect/awaitable-effect.ts +46 -37
  18. package/src/effect/helpers.ts +30 -5
  19. package/src/effect/index.ts +7 -5
  20. package/src/effect/layers.ts +82 -72
  21. package/src/effect/runtime.ts +18 -3
  22. package/src/effect/services.ts +15 -11
  23. package/src/embeddings/provider.ts +65 -66
  24. package/src/index.ts +13 -11
  25. package/src/queues/autonomous-job.queue.ts +59 -71
  26. package/src/queues/context-compaction.queue.ts +6 -18
  27. package/src/queues/delayed-node-promotion.queue.ts +9 -17
  28. package/src/queues/organization-learning.queue.ts +17 -4
  29. package/src/queues/plan-agent-heartbeat.queue.ts +23 -20
  30. package/src/queues/plan-scheduler.queue.ts +6 -18
  31. package/src/queues/post-chat-memory.queue.ts +6 -18
  32. package/src/queues/queue-factory.ts +128 -50
  33. package/src/queues/title-generation.queue.ts +6 -17
  34. package/src/redis/connection.ts +181 -164
  35. package/src/redis/runtime-connection.ts +13 -3
  36. package/src/redis/stream-context.ts +17 -9
  37. package/src/runtime/agent-runtime-policy.ts +1 -1
  38. package/src/runtime/agent-stream-helpers.ts +15 -11
  39. package/src/runtime/chat-run-orchestration.ts +1 -1
  40. package/src/runtime/context-compaction/context-compaction-runtime.ts +1 -1
  41. package/src/runtime/context-compaction/context-compaction.ts +126 -82
  42. package/src/runtime/domain-layer.ts +192 -0
  43. package/src/runtime/graph-designer.ts +15 -7
  44. package/src/runtime/helper-model.ts +8 -4
  45. package/src/runtime/index.ts +0 -1
  46. package/src/runtime/memory/memory-block.ts +19 -9
  47. package/src/runtime/memory/memory-pipeline.ts +53 -66
  48. package/src/runtime/memory/memory-scope.ts +33 -29
  49. package/src/runtime/plugin-resolution.ts +33 -54
  50. package/src/runtime/post-turn-side-effects.ts +6 -26
  51. package/src/runtime/retrieval-adapters.ts +4 -4
  52. package/src/runtime/runtime-accessors.ts +92 -0
  53. package/src/runtime/runtime-config.ts +3 -3
  54. package/src/runtime/runtime-extensions.ts +20 -9
  55. package/src/runtime/runtime-lifecycle.ts +124 -0
  56. package/src/runtime/runtime-services.ts +386 -0
  57. package/src/runtime/runtime-token.ts +47 -0
  58. package/src/runtime/social-chat/social-chat-agent-runner.ts +7 -5
  59. package/src/runtime/social-chat/social-chat-history.ts +21 -12
  60. package/src/runtime/social-chat/social-chat.ts +401 -365
  61. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +58 -52
  62. package/src/runtime/thread-turn-context.ts +21 -27
  63. package/src/services/agent-activity.service.ts +1 -1
  64. package/src/services/agent-executor.service.ts +179 -187
  65. package/src/services/artifact.service.ts +10 -5
  66. package/src/services/attachment.service.ts +35 -1
  67. package/src/services/autonomous-job.service.ts +58 -56
  68. package/src/services/background-work.service.ts +54 -0
  69. package/src/services/chat-run-registry.service.ts +3 -1
  70. package/src/services/context-compaction.service.ts +1 -1
  71. package/src/services/document-chunk.service.ts +8 -17
  72. package/src/services/execution-plan/execution-plan-graph.ts +74 -52
  73. package/src/services/execution-plan/execution-plan.service.ts +1 -1
  74. package/src/services/feedback-loop.service.ts +1 -1
  75. package/src/services/global-orchestrator.service.ts +33 -10
  76. package/src/services/graph-full-routing.ts +44 -33
  77. package/src/services/index.ts +1 -0
  78. package/src/services/institutional-memory.service.ts +8 -17
  79. package/src/services/learned-skill.service.ts +38 -35
  80. package/src/services/memory/memory-errors.ts +27 -0
  81. package/src/services/memory/memory-org-memory.ts +14 -3
  82. package/src/services/memory/memory-preseeded.ts +10 -4
  83. package/src/services/memory/memory-utils.ts +2 -1
  84. package/src/services/memory/memory.service.ts +26 -44
  85. package/src/services/memory/rerank.service.ts +3 -11
  86. package/src/services/monitoring-window.service.ts +1 -1
  87. package/src/services/mutating-approval.service.ts +1 -1
  88. package/src/services/node-workspace.service.ts +2 -2
  89. package/src/services/notification.service.ts +16 -4
  90. package/src/services/organization-member.service.ts +1 -1
  91. package/src/services/organization.service.ts +34 -51
  92. package/src/services/ownership-dispatcher.service.ts +132 -90
  93. package/src/services/plan/plan-agent-heartbeat.service.ts +1 -1
  94. package/src/services/plan/plan-agent-query.service.ts +1 -1
  95. package/src/services/plan/plan-approval.service.ts +52 -48
  96. package/src/services/plan/plan-artifact.service.ts +2 -2
  97. package/src/services/plan/plan-builder.service.ts +2 -2
  98. package/src/services/plan/plan-checkpoint.service.ts +1 -1
  99. package/src/services/plan/plan-compiler.service.ts +1 -1
  100. package/src/services/plan/plan-completion-side-effects.ts +18 -24
  101. package/src/services/plan/plan-coordination.service.ts +1 -1
  102. package/src/services/plan/plan-cycle.service.ts +171 -164
  103. package/src/services/plan/plan-deadline.service.ts +290 -304
  104. package/src/services/plan/plan-event-delivery.service.ts +44 -39
  105. package/src/services/plan/plan-executor-graph.ts +114 -67
  106. package/src/services/plan/plan-executor-helpers.ts +60 -75
  107. package/src/services/plan/plan-executor.service.ts +550 -467
  108. package/src/services/plan/plan-run.service.ts +12 -19
  109. package/src/services/plan/plan-scheduler.service.ts +27 -33
  110. package/src/services/plan/plan-template.service.ts +1 -1
  111. package/src/services/plan/plan-transaction-events.ts +8 -5
  112. package/src/services/plan/plan-validator.service.ts +1 -1
  113. package/src/services/plan/plan-workspace.service.ts +17 -11
  114. package/src/services/plugin-executor.service.ts +26 -21
  115. package/src/services/quality-metrics.service.ts +1 -1
  116. package/src/services/queue-job.service.ts +8 -17
  117. package/src/services/recent-activity-title.service.ts +17 -9
  118. package/src/services/recent-activity.service.ts +1 -1
  119. package/src/services/skill-resolver.service.ts +1 -1
  120. package/src/services/social-chat-history.service.ts +37 -20
  121. package/src/services/system-executor.service.ts +25 -20
  122. package/src/services/thread/thread-bootstrap.ts +26 -10
  123. package/src/services/thread/thread-listing.ts +2 -1
  124. package/src/services/thread/thread-memory-block.ts +18 -5
  125. package/src/services/thread/thread-message.service.ts +24 -8
  126. package/src/services/thread/thread-title.service.ts +1 -1
  127. package/src/services/thread/thread-turn-execution.ts +1 -1
  128. package/src/services/thread/thread-turn-preparation.service.ts +18 -16
  129. package/src/services/thread/thread-turn-streaming.ts +12 -11
  130. package/src/services/thread/thread-turn.ts +43 -10
  131. package/src/services/thread/thread.service.ts +11 -2
  132. package/src/services/user.service.ts +1 -1
  133. package/src/services/write-intent-validator.service.ts +1 -1
  134. package/src/storage/attachment-storage.service.ts +7 -4
  135. package/src/storage/generated-document-storage.service.ts +1 -1
  136. package/src/system-agents/context-compaction.agent.ts +1 -1
  137. package/src/system-agents/helper-agent-options.ts +1 -1
  138. package/src/system-agents/memory-reranker.agent.ts +1 -1
  139. package/src/system-agents/memory.agent.ts +1 -1
  140. package/src/system-agents/recent-activity-title-refiner.agent.ts +1 -1
  141. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  142. package/src/system-agents/skill-extractor.agent.ts +1 -1
  143. package/src/system-agents/skill-manager.agent.ts +1 -1
  144. package/src/system-agents/title-generator.agent.ts +1 -1
  145. package/src/tools/execution-plan.tool.ts +28 -17
  146. package/src/tools/fetch-webpage.tool.ts +20 -13
  147. package/src/tools/firecrawl-client.ts +13 -3
  148. package/src/tools/plan-approval.tool.ts +9 -1
  149. package/src/tools/search-web.tool.ts +16 -9
  150. package/src/tools/team-think.tool.ts +2 -2
  151. package/src/utils/async.ts +15 -6
  152. package/src/utils/errors.ts +27 -15
  153. package/src/workers/bootstrap.ts +25 -48
  154. package/src/workers/organization-learning.worker.ts +1 -1
  155. package/src/workers/regular-chat-memory-digest.runner.ts +25 -15
  156. package/src/workers/worker-utils.ts +20 -2
  157. package/src/config/search.ts +0 -3
  158. package/src/runtime/agent-types.ts +0 -1
@@ -110,11 +110,15 @@ interface PlanCycleDeps {
110
110
  export function makePlanCycleService(deps: PlanCycleDeps) {
111
111
  const { db, planSchedulerService, planTemplateService } = deps
112
112
 
113
- function getCycleEffect(cycleId: RecordIdInput) {
114
- return db.findOne(TABLES.PLAN_CYCLE, { id: ensureRecordId(cycleId, TABLES.PLAN_CYCLE) }, PlanCycleRecordSchema)
115
- }
113
+ const getCycleEffect = Effect.fn('PlanCycle.getCycle')(function* (cycleId: RecordIdInput) {
114
+ return yield* db.findOne(
115
+ TABLES.PLAN_CYCLE,
116
+ { id: ensureRecordId(cycleId, TABLES.PLAN_CYCLE) },
117
+ PlanCycleRecordSchema,
118
+ )
119
+ })
116
120
 
117
- function createCycleEffect(params: {
121
+ const createCycleEffect = Effect.fn('PlanCycle.createCycle')(function* (params: {
118
122
  organizationId: RecordIdInput
119
123
  threadId: RecordIdInput
120
124
  templateId: RecordIdInput
@@ -123,10 +127,10 @@ export function makePlanCycleService(deps: PlanCycleDeps) {
123
127
  carryForwardPolicy?: CarryForwardPolicy
124
128
  leadAgentId: string
125
129
  }) {
126
- return Effect.gen(function* () {
127
- const now = nowDate()
130
+ const now = nowDate()
128
131
 
129
- const cycle = yield* db.create(
132
+ const cycle = yield* db
133
+ .create(
130
134
  TABLES.PLAN_CYCLE,
131
135
  {
132
136
  organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
@@ -141,198 +145,194 @@ export function makePlanCycleService(deps: PlanCycleDeps) {
141
145
  },
142
146
  PlanCycleRecordSchema,
143
147
  )
148
+ .pipe(Effect.withSpan('PlanCycle.persistCycle'))
144
149
 
145
- const createResult = yield* planTemplateService.instantiate({
150
+ const createResult = yield* planTemplateService
151
+ .instantiate({
146
152
  templateId: params.templateId,
147
153
  organizationId: params.organizationId,
148
154
  threadId: params.threadId,
149
155
  leadAgentId: params.leadAgentId,
150
156
  })
157
+ .pipe(Effect.withSpan('PlanCycle.instantiateTemplate'))
151
158
 
152
- const createdRunId = createResult.plan?.runId
153
- const scheduleSpec = cycleScheduleToSpec(params.schedule)
154
- const scheduleParams: {
155
- organizationId: RecordIdInput
156
- threadId: RecordIdInput
157
- scheduleSpec: PlanScheduleSpec
158
- runId?: RecordIdInput
159
- } = { organizationId: params.organizationId, threadId: params.threadId, scheduleSpec }
160
- if (createdRunId !== undefined) {
161
- scheduleParams.runId = ensureRecordId(createdRunId, TABLES.PLAN_RUN)
162
- }
163
-
164
- const scheduleRecord = yield* planSchedulerService.createSchedule(scheduleParams)
159
+ const createdRunId = createResult.plan?.runId
160
+ const scheduleSpec = cycleScheduleToSpec(params.schedule)
161
+ const scheduleParams: {
162
+ organizationId: RecordIdInput
163
+ threadId: RecordIdInput
164
+ scheduleSpec: PlanScheduleSpec
165
+ runId?: RecordIdInput
166
+ } = { organizationId: params.organizationId, threadId: params.threadId, scheduleSpec }
167
+ if (createdRunId !== undefined) {
168
+ scheduleParams.runId = ensureRecordId(createdRunId, TABLES.PLAN_RUN)
169
+ }
170
+
171
+ const scheduleRecord = yield* planSchedulerService.createSchedule(scheduleParams)
172
+
173
+ const updatedPayload: { scheduleId: RecordIdInput; currentRunId?: RecordIdInput; currentIteration: number } = {
174
+ scheduleId: ensureRecordId(scheduleRecord.id, TABLES.PLAN_SCHEDULE),
175
+ currentIteration: 1,
176
+ }
177
+ if (createdRunId !== undefined) {
178
+ updatedPayload.currentRunId = ensureRecordId(createdRunId, TABLES.PLAN_RUN)
179
+ }
180
+
181
+ const updated = yield* db.update(
182
+ TABLES.PLAN_CYCLE,
183
+ ensureRecordId(cycle.id, TABLES.PLAN_CYCLE),
184
+ updatedPayload,
185
+ PlanCycleRecordSchema,
186
+ )
165
187
 
166
- const updatedPayload: { scheduleId: RecordIdInput; currentRunId?: RecordIdInput; currentIteration: number } = {
167
- scheduleId: ensureRecordId(scheduleRecord.id, TABLES.PLAN_SCHEDULE),
168
- currentIteration: 1,
169
- }
170
- if (createdRunId !== undefined) {
171
- updatedPayload.currentRunId = ensureRecordId(createdRunId, TABLES.PLAN_RUN)
172
- }
188
+ return updated ?? cycle
189
+ })
173
190
 
174
- const updated = yield* db.update(
175
- TABLES.PLAN_CYCLE,
176
- ensureRecordId(cycle.id, TABLES.PLAN_CYCLE),
177
- updatedPayload,
178
- PlanCycleRecordSchema,
191
+ const advanceCycleEffect = Effect.fn('PlanCycle.advanceCycle')(function* (cycleId: RecordIdInput) {
192
+ const cycle = yield* getCycleEffect(cycleId)
193
+ if (!cycle) {
194
+ return yield* new PlanCycleNotFoundError({
195
+ cycleId: recordIdToString(cycleId, TABLES.PLAN_CYCLE),
196
+ message: `Cycle not found: ${recordIdToString(cycleId, TABLES.PLAN_CYCLE)}`,
197
+ })
198
+ }
199
+
200
+ if (cycle.status !== 'active') {
201
+ return
202
+ }
203
+
204
+ const currentRunId = cycle.currentRunId
205
+ if (currentRunId !== undefined) {
206
+ const runRecord = yield* db.findOne(
207
+ TABLES.PLAN_RUN,
208
+ { id: ensureRecordId(currentRunId, TABLES.PLAN_RUN) },
209
+ PlanRunSchema,
179
210
  )
180
-
181
- return updated ?? cycle
182
- })
183
- }
184
-
185
- function advanceCycleEffect(cycleId: RecordIdInput) {
186
- return Effect.gen(function* () {
187
- const cycle = yield* getCycleEffect(cycleId)
188
- if (!cycle) {
189
- return yield* new PlanCycleNotFoundError({
190
- cycleId: recordIdToString(cycleId, TABLES.PLAN_CYCLE),
191
- message: `Cycle not found: ${recordIdToString(cycleId, TABLES.PLAN_CYCLE)}`,
192
- })
193
- }
194
-
195
- if (cycle.status !== 'active') {
211
+ if (runRecord && !TERMINAL_RUN_STATUSES.has(runRecord.status)) {
196
212
  return
197
213
  }
214
+ }
198
215
 
199
- const currentRunId = cycle.currentRunId
200
- if (currentRunId !== undefined) {
201
- const runRecord = yield* db.findOne(
202
- TABLES.PLAN_RUN,
203
- { id: ensureRecordId(currentRunId, TABLES.PLAN_RUN) },
204
- PlanRunSchema,
205
- )
206
- if (runRecord && !TERMINAL_RUN_STATUSES.has(runRecord.status)) {
207
- return
208
- }
209
- }
210
-
211
- const template = yield* planTemplateService.getTemplate(cycle.templateId)
212
- if (!template) {
213
- return yield* new PlanTemplateNotFoundForCycleError({
214
- templateId: recordIdToString(cycle.templateId, TABLES.PLAN_TEMPLATE),
215
- message: `Template not found for cycle: ${recordIdToString(cycle.templateId, TABLES.PLAN_TEMPLATE)}`,
216
+ const template = yield* planTemplateService.getTemplate(cycle.templateId)
217
+ if (!template) {
218
+ return yield* new PlanTemplateNotFoundForCycleError({
219
+ templateId: recordIdToString(cycle.templateId, TABLES.PLAN_TEMPLATE),
220
+ message: `Template not found for cycle: ${recordIdToString(cycle.templateId, TABLES.PLAN_TEMPLATE)}`,
221
+ })
222
+ }
223
+
224
+ let previousRunArtifacts: PlanArtifactRecord[] = []
225
+ if (currentRunId !== undefined) {
226
+ previousRunArtifacts = yield* db
227
+ .findMany(TABLES.PLAN_ARTIFACT, { runId: ensureRecordId(currentRunId, TABLES.PLAN_RUN) }, PlanArtifactSchema, {
228
+ orderBy: 'createdAt',
229
+ orderDir: 'ASC',
216
230
  })
217
- }
218
-
219
- let previousRunArtifacts: PlanArtifactRecord[] = []
220
- if (currentRunId !== undefined) {
221
- previousRunArtifacts = yield* db.findMany(
222
- TABLES.PLAN_ARTIFACT,
223
- { runId: ensureRecordId(currentRunId, TABLES.PLAN_RUN) },
224
- PlanArtifactSchema,
225
- { orderBy: 'createdAt', orderDir: 'ASC' },
226
- )
227
- }
231
+ .pipe(Effect.withSpan('PlanCycle.loadPreviousRunArtifacts'))
232
+ }
228
233
 
229
- const draft = buildCarryForwardDraft({ template, previousRunArtifacts, policy: cycle.carryForwardPolicy })
234
+ const draft = buildCarryForwardDraft({ template, previousRunArtifacts, policy: cycle.carryForwardPolicy })
230
235
 
231
- const result = yield* planTemplateService.instantiate({
236
+ const result = yield* planTemplateService
237
+ .instantiate({
232
238
  templateId: cycle.templateId,
233
239
  organizationId: cycle.organizationId,
234
240
  threadId: cycle.threadId,
235
241
  leadAgentId: 'system',
236
242
  overrides: draft,
237
243
  })
244
+ .pipe(Effect.withSpan('PlanCycle.instantiateTemplate'))
238
245
 
239
- const newRunId = result.plan?.runId
240
- const updatePayload: { currentRunId?: RecordIdInput; currentIteration: number } = {
241
- currentIteration: cycle.currentIteration + 1,
242
- }
243
- if (newRunId !== undefined) {
244
- updatePayload.currentRunId = ensureRecordId(newRunId, TABLES.PLAN_RUN)
245
- }
246
-
247
- yield* db.update(
248
- TABLES.PLAN_CYCLE,
249
- ensureRecordId(cycleId, TABLES.PLAN_CYCLE),
250
- updatePayload,
251
- PlanCycleRecordSchema,
252
- )
253
- })
254
- }
255
-
256
- function cancelCycleEffect(cycleId: RecordIdInput) {
257
- return Effect.gen(function* () {
258
- const cycle = yield* getCycleEffect(cycleId)
259
- if (!cycle) {
260
- return yield* new PlanCycleNotFoundError({
261
- cycleId: recordIdToString(cycleId, TABLES.PLAN_CYCLE),
262
- message: `Cycle not found: ${recordIdToString(cycleId, TABLES.PLAN_CYCLE)}`,
263
- })
264
- }
265
-
266
- const scheduleId = cycle.scheduleId
267
- if (scheduleId !== undefined) {
268
- yield* planSchedulerService.cancelSchedule(scheduleId)
269
- }
246
+ const newRunId = result.plan?.runId
247
+ const updatePayload: { currentRunId?: RecordIdInput; currentIteration: number } = {
248
+ currentIteration: cycle.currentIteration + 1,
249
+ }
250
+ if (newRunId !== undefined) {
251
+ updatePayload.currentRunId = ensureRecordId(newRunId, TABLES.PLAN_RUN)
252
+ }
270
253
 
271
- yield* db.update(
272
- TABLES.PLAN_CYCLE,
273
- ensureRecordId(cycleId, TABLES.PLAN_CYCLE),
274
- { status: 'cancelled' },
275
- PlanCycleRecordSchema,
276
- )
277
- })
278
- }
254
+ yield* db.update(
255
+ TABLES.PLAN_CYCLE,
256
+ ensureRecordId(cycleId, TABLES.PLAN_CYCLE),
257
+ updatePayload,
258
+ PlanCycleRecordSchema,
259
+ )
260
+ })
261
+
262
+ const cancelCycleEffect = Effect.fn('PlanCycle.cancelCycle')(function* (cycleId: RecordIdInput) {
263
+ const cycle = yield* getCycleEffect(cycleId)
264
+ if (!cycle) {
265
+ return yield* new PlanCycleNotFoundError({
266
+ cycleId: recordIdToString(cycleId, TABLES.PLAN_CYCLE),
267
+ message: `Cycle not found: ${recordIdToString(cycleId, TABLES.PLAN_CYCLE)}`,
268
+ })
269
+ }
279
270
 
280
- function pauseCycleEffect(cycleId: RecordIdInput) {
281
- return Effect.gen(function* () {
282
- const cycle = yield* getCycleEffect(cycleId)
283
- if (!cycle) {
284
- return yield* new PlanCycleNotFoundError({
285
- cycleId: recordIdToString(cycleId, TABLES.PLAN_CYCLE),
286
- message: `Cycle not found: ${recordIdToString(cycleId, TABLES.PLAN_CYCLE)}`,
287
- })
288
- }
271
+ const scheduleId = cycle.scheduleId
272
+ if (scheduleId !== undefined) {
273
+ yield* planSchedulerService.cancelSchedule(scheduleId)
274
+ }
289
275
 
290
- const scheduleId = cycle.scheduleId
291
- if (scheduleId !== undefined) {
292
- yield* planSchedulerService.pauseSchedule(scheduleId)
293
- }
276
+ yield* db.update(
277
+ TABLES.PLAN_CYCLE,
278
+ ensureRecordId(cycleId, TABLES.PLAN_CYCLE),
279
+ { status: 'cancelled' },
280
+ PlanCycleRecordSchema,
281
+ )
282
+ })
283
+
284
+ const pauseCycleEffect = Effect.fn('PlanCycle.pauseCycle')(function* (cycleId: RecordIdInput) {
285
+ const cycle = yield* getCycleEffect(cycleId)
286
+ if (!cycle) {
287
+ return yield* new PlanCycleNotFoundError({
288
+ cycleId: recordIdToString(cycleId, TABLES.PLAN_CYCLE),
289
+ message: `Cycle not found: ${recordIdToString(cycleId, TABLES.PLAN_CYCLE)}`,
290
+ })
291
+ }
294
292
 
295
- yield* db.update(
296
- TABLES.PLAN_CYCLE,
297
- ensureRecordId(cycleId, TABLES.PLAN_CYCLE),
298
- { status: 'paused' },
299
- PlanCycleRecordSchema,
300
- )
301
- })
302
- }
293
+ const scheduleId = cycle.scheduleId
294
+ if (scheduleId !== undefined) {
295
+ yield* planSchedulerService.pauseSchedule(scheduleId)
296
+ }
303
297
 
304
- function resumeCycleEffect(cycleId: RecordIdInput) {
305
- return Effect.gen(function* () {
306
- const cycle = yield* getCycleEffect(cycleId)
307
- if (!cycle) {
308
- return yield* new PlanCycleNotFoundError({
309
- cycleId: recordIdToString(cycleId, TABLES.PLAN_CYCLE),
310
- message: `Cycle not found: ${recordIdToString(cycleId, TABLES.PLAN_CYCLE)}`,
311
- })
312
- }
298
+ yield* db.update(
299
+ TABLES.PLAN_CYCLE,
300
+ ensureRecordId(cycleId, TABLES.PLAN_CYCLE),
301
+ { status: 'paused' },
302
+ PlanCycleRecordSchema,
303
+ )
304
+ })
305
+
306
+ const resumeCycleEffect = Effect.fn('PlanCycle.resumeCycle')(function* (cycleId: RecordIdInput) {
307
+ const cycle = yield* getCycleEffect(cycleId)
308
+ if (!cycle) {
309
+ return yield* new PlanCycleNotFoundError({
310
+ cycleId: recordIdToString(cycleId, TABLES.PLAN_CYCLE),
311
+ message: `Cycle not found: ${recordIdToString(cycleId, TABLES.PLAN_CYCLE)}`,
312
+ })
313
+ }
313
314
 
314
- const scheduleId = cycle.scheduleId
315
- if (scheduleId !== undefined) {
316
- yield* planSchedulerService.resumeSchedule(scheduleId)
317
- }
315
+ const scheduleId = cycle.scheduleId
316
+ if (scheduleId !== undefined) {
317
+ yield* planSchedulerService.resumeSchedule(scheduleId)
318
+ }
318
319
 
319
- yield* db.update(
320
- TABLES.PLAN_CYCLE,
321
- ensureRecordId(cycleId, TABLES.PLAN_CYCLE),
322
- { status: 'active' },
323
- PlanCycleRecordSchema,
324
- )
325
- })
326
- }
320
+ yield* db.update(
321
+ TABLES.PLAN_CYCLE,
322
+ ensureRecordId(cycleId, TABLES.PLAN_CYCLE),
323
+ { status: 'active' },
324
+ PlanCycleRecordSchema,
325
+ )
326
+ })
327
327
 
328
- function listCyclesEffect(threadId: RecordIdInput) {
329
- return db.findMany(
328
+ const listCyclesEffect = Effect.fn('PlanCycle.listCycles')(function* (threadId: RecordIdInput) {
329
+ return yield* db.findMany(
330
330
  TABLES.PLAN_CYCLE,
331
331
  { threadId: ensureRecordId(threadId, TABLES.THREAD) },
332
332
  PlanCycleRecordSchema,
333
333
  { orderBy: 'createdAt', orderDir: 'ASC' },
334
334
  )
335
- }
335
+ })
336
336
 
337
337
  return {
338
338
  cycleScheduleToSpec,
@@ -347,10 +347,12 @@ export function makePlanCycleService(deps: PlanCycleDeps) {
347
347
  }): Promise<PlanCycleRecord> {
348
348
  return runPromise(createCycleEffect(params))
349
349
  },
350
+ createCycleEffect,
350
351
 
351
352
  advanceCycle(cycleId: RecordIdInput): Promise<void> {
352
353
  return runPromise(advanceCycleEffect(cycleId))
353
354
  },
355
+ advanceCycleEffect,
354
356
 
355
357
  buildCarryForwardDraft(params: {
356
358
  template: PlanTemplateRecord
@@ -363,29 +365,34 @@ export function makePlanCycleService(deps: PlanCycleDeps) {
363
365
  cancelCycle(cycleId: RecordIdInput): Promise<void> {
364
366
  return runPromise(cancelCycleEffect(cycleId))
365
367
  },
368
+ cancelCycleEffect,
366
369
 
367
370
  pauseCycle(cycleId: RecordIdInput): Promise<void> {
368
371
  return runPromise(pauseCycleEffect(cycleId))
369
372
  },
373
+ pauseCycleEffect,
370
374
 
371
375
  resumeCycle(cycleId: RecordIdInput): Promise<void> {
372
376
  return runPromise(resumeCycleEffect(cycleId))
373
377
  },
378
+ resumeCycleEffect,
374
379
 
375
380
  listCycles(threadId: RecordIdInput): Promise<PlanCycleRecord[]> {
376
381
  return runPromise(listCyclesEffect(threadId))
377
382
  },
383
+ listCyclesEffect,
378
384
 
379
385
  getCycle(cycleId: RecordIdInput): Promise<PlanCycleRecord | null> {
380
386
  return runPromise(getCycleEffect(cycleId))
381
387
  },
388
+ getCycleEffect,
382
389
  }
383
390
  }
384
391
 
385
392
  export class PlanCycleServiceTag extends Context.Service<
386
393
  PlanCycleServiceTag,
387
394
  ReturnType<typeof makePlanCycleService>
388
- >()('PlanCycleService') {}
395
+ >()('@lota-sdk/core/PlanCycleService') {}
389
396
 
390
397
  export const PlanCycleServiceLive = Layer.effect(
391
398
  PlanCycleServiceTag,