@lota-sdk/core 0.4.9 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) 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 +164 -82
  4. package/src/ai-gateway/index.ts +16 -1
  5. package/src/config/agent-defaults.ts +4 -107
  6. package/src/config/agent-types.ts +1 -1
  7. package/src/config/background-processing.ts +1 -1
  8. package/src/config/index.ts +0 -1
  9. package/src/config/logger.ts +22 -25
  10. package/src/config/thread-defaults.ts +1 -10
  11. package/src/create-runtime.ts +145 -670
  12. package/src/db/base.service.ts +30 -38
  13. package/src/db/memory-query-builder.ts +2 -1
  14. package/src/db/memory-store.ts +29 -20
  15. package/src/db/memory.ts +188 -195
  16. package/src/db/service-normalization.ts +97 -64
  17. package/src/db/service.ts +496 -384
  18. package/src/db/startup.ts +30 -19
  19. package/src/effect/helpers.ts +30 -5
  20. package/src/effect/index.ts +7 -7
  21. package/src/effect/layers.ts +75 -72
  22. package/src/effect/services.ts +15 -11
  23. package/src/embeddings/provider.ts +65 -71
  24. package/src/index.ts +13 -12
  25. package/src/queues/autonomous-job.queue.ts +177 -143
  26. package/src/queues/context-compaction.queue.ts +41 -39
  27. package/src/queues/delayed-node-promotion.queue.ts +61 -42
  28. package/src/queues/document-processor.queue.ts +5 -3
  29. package/src/queues/index.ts +1 -0
  30. package/src/queues/memory-consolidation.queue.ts +79 -53
  31. package/src/queues/organization-learning.queue.ts +70 -33
  32. package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
  33. package/src/queues/plan-scheduler.queue.ts +101 -97
  34. package/src/queues/post-chat-memory.queue.ts +56 -46
  35. package/src/queues/queue-factory.ts +146 -69
  36. package/src/queues/queues.service.ts +61 -0
  37. package/src/queues/title-generation.queue.ts +44 -44
  38. package/src/redis/connection.ts +181 -164
  39. package/src/redis/org-memory-lock.ts +24 -9
  40. package/src/redis/redis-lease-lock.ts +8 -1
  41. package/src/redis/stream-context.ts +17 -9
  42. package/src/runtime/agent-identity-overrides.ts +7 -3
  43. package/src/runtime/agent-runtime-policy.ts +10 -5
  44. package/src/runtime/agent-stream-helpers.ts +24 -15
  45. package/src/runtime/chat-run-orchestration.ts +1 -1
  46. package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
  47. package/src/runtime/context-compaction/context-compaction.ts +131 -85
  48. package/src/runtime/domain-layer.ts +203 -0
  49. package/src/runtime/execution-plan-visibility.ts +5 -2
  50. package/src/runtime/graph-designer.ts +0 -14
  51. package/src/runtime/helper-model.ts +8 -4
  52. package/src/runtime/index.ts +1 -1
  53. package/src/runtime/indexed-repositories-policy.ts +2 -6
  54. package/src/runtime/memory/memory-block.ts +19 -9
  55. package/src/runtime/memory/memory-pipeline.ts +53 -66
  56. package/src/runtime/memory/memory-scope.ts +33 -29
  57. package/src/runtime/plugin-resolution.ts +58 -62
  58. package/src/runtime/post-turn-side-effects.ts +139 -161
  59. package/src/runtime/retrieval-adapters.ts +4 -4
  60. package/src/runtime/runtime-config.ts +3 -9
  61. package/src/runtime/runtime-extensions.ts +0 -43
  62. package/src/runtime/runtime-lifecycle.ts +124 -0
  63. package/src/runtime/runtime-services.ts +455 -0
  64. package/src/runtime/runtime-worker-registry.ts +113 -30
  65. package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
  66. package/src/runtime/social-chat/social-chat-history.ts +24 -13
  67. package/src/runtime/social-chat/social-chat.ts +420 -369
  68. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
  69. package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
  70. package/src/runtime/thread-chat-helpers.ts +18 -9
  71. package/src/runtime/thread-turn-context.ts +28 -74
  72. package/src/runtime/turn-lifecycle.ts +6 -14
  73. package/src/services/agent-activity.service.ts +169 -176
  74. package/src/services/agent-executor.service.ts +207 -196
  75. package/src/services/artifact.service.ts +10 -5
  76. package/src/services/attachment.service.ts +16 -48
  77. package/src/services/autonomous-job.service.ts +81 -87
  78. package/src/services/background-work.service.ts +54 -0
  79. package/src/services/chat-run-registry.service.ts +3 -1
  80. package/src/services/context-compaction.service.ts +8 -10
  81. package/src/services/document-chunk.service.ts +8 -17
  82. package/src/services/execution-plan/execution-plan-graph.ts +122 -109
  83. package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
  84. package/src/services/execution-plan/execution-plan.service.ts +68 -51
  85. package/src/services/feedback-loop.service.ts +1 -1
  86. package/src/services/global-orchestrator.service.ts +49 -15
  87. package/src/services/graph-full-routing.ts +49 -37
  88. package/src/services/index.ts +1 -0
  89. package/src/services/institutional-memory.service.ts +8 -17
  90. package/src/services/learned-skill.service.ts +38 -35
  91. package/src/services/memory/memory-conversation.ts +10 -5
  92. package/src/services/memory/memory-errors.ts +27 -0
  93. package/src/services/memory/memory-org-memory.ts +14 -3
  94. package/src/services/memory/memory-preseeded.ts +10 -4
  95. package/src/services/memory/memory-utils.ts +2 -1
  96. package/src/services/memory/memory.service.ts +37 -52
  97. package/src/services/memory/rerank.service.ts +3 -11
  98. package/src/services/monitoring-window.service.ts +1 -1
  99. package/src/services/mutating-approval.service.ts +1 -1
  100. package/src/services/node-workspace.service.ts +2 -2
  101. package/src/services/notification.service.ts +16 -4
  102. package/src/services/organization-member.service.ts +1 -1
  103. package/src/services/organization.service.ts +34 -51
  104. package/src/services/ownership-dispatcher.service.ts +148 -95
  105. package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
  106. package/src/services/plan/plan-agent-query.service.ts +13 -9
  107. package/src/services/plan/plan-approval.service.ts +52 -48
  108. package/src/services/plan/plan-artifact.service.ts +2 -2
  109. package/src/services/plan/plan-builder.service.ts +2 -2
  110. package/src/services/plan/plan-checkpoint.service.ts +1 -1
  111. package/src/services/plan/plan-compiler.service.ts +1 -1
  112. package/src/services/plan/plan-completion-side-effects.ts +99 -113
  113. package/src/services/plan/plan-coordination.service.ts +1 -1
  114. package/src/services/plan/plan-cycle.service.ts +171 -202
  115. package/src/services/plan/plan-deadline.service.ts +304 -307
  116. package/src/services/plan/plan-event-delivery.service.ts +84 -72
  117. package/src/services/plan/plan-executor-context.ts +2 -0
  118. package/src/services/plan/plan-executor-graph.ts +375 -353
  119. package/src/services/plan/plan-executor-helpers.ts +60 -75
  120. package/src/services/plan/plan-executor.service.ts +494 -489
  121. package/src/services/plan/plan-run.service.ts +12 -19
  122. package/src/services/plan/plan-scheduler.service.ts +89 -82
  123. package/src/services/plan/plan-template.service.ts +1 -1
  124. package/src/services/plan/plan-transaction-events.ts +8 -5
  125. package/src/services/plan/plan-validator.service.ts +1 -1
  126. package/src/services/plan/plan-workspace.service.ts +17 -11
  127. package/src/services/plugin-executor.service.ts +26 -21
  128. package/src/services/quality-metrics.service.ts +1 -1
  129. package/src/services/queue-job.service.ts +8 -17
  130. package/src/services/recent-activity-title.service.ts +22 -10
  131. package/src/services/recent-activity.service.ts +1 -1
  132. package/src/services/skill-resolver.service.ts +1 -1
  133. package/src/services/social-chat-history.service.ts +37 -20
  134. package/src/services/system-executor.service.ts +25 -20
  135. package/src/services/thread/thread-bootstrap.ts +37 -19
  136. package/src/services/thread/thread-listing.ts +2 -1
  137. package/src/services/thread/thread-memory-block.ts +18 -5
  138. package/src/services/thread/thread-message.service.ts +30 -13
  139. package/src/services/thread/thread-title.service.ts +1 -1
  140. package/src/services/thread/thread-turn-execution.ts +87 -83
  141. package/src/services/thread/thread-turn-preparation.service.ts +65 -40
  142. package/src/services/thread/thread-turn-streaming.ts +32 -36
  143. package/src/services/thread/thread-turn.ts +43 -29
  144. package/src/services/thread/thread.service.ts +32 -8
  145. package/src/services/user.service.ts +1 -1
  146. package/src/services/write-intent-validator.service.ts +1 -1
  147. package/src/storage/attachment-storage.service.ts +7 -4
  148. package/src/storage/generated-document-storage.service.ts +1 -1
  149. package/src/system-agents/context-compaction.agent.ts +1 -1
  150. package/src/system-agents/helper-agent-options.ts +1 -1
  151. package/src/system-agents/memory-reranker.agent.ts +1 -1
  152. package/src/system-agents/memory.agent.ts +1 -1
  153. package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
  154. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  155. package/src/system-agents/skill-extractor.agent.ts +1 -1
  156. package/src/system-agents/skill-manager.agent.ts +1 -1
  157. package/src/system-agents/thread-router.agent.ts +23 -20
  158. package/src/system-agents/title-generator.agent.ts +1 -1
  159. package/src/tools/execution-plan.tool.ts +36 -20
  160. package/src/tools/fetch-webpage.tool.ts +30 -22
  161. package/src/tools/firecrawl-client.ts +1 -6
  162. package/src/tools/plan-approval.tool.ts +9 -1
  163. package/src/tools/remember-memory.tool.ts +3 -6
  164. package/src/tools/research-topic.tool.ts +12 -3
  165. package/src/tools/search-web.tool.ts +26 -18
  166. package/src/tools/search.tool.ts +4 -5
  167. package/src/tools/team-think.tool.ts +139 -121
  168. package/src/utils/async.ts +15 -6
  169. package/src/utils/errors.ts +27 -15
  170. package/src/workers/bootstrap.ts +34 -58
  171. package/src/workers/memory-consolidation.worker.ts +4 -1
  172. package/src/workers/organization-learning.worker.ts +16 -3
  173. package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
  174. package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
  175. package/src/workers/skill-extraction.runner.ts +13 -15
  176. package/src/workers/worker-utils.ts +14 -8
  177. package/src/config/search.ts +0 -3
  178. package/src/effect/awaitable-effect.ts +0 -87
  179. package/src/effect/runtime-ref.ts +0 -25
  180. package/src/effect/runtime.ts +0 -31
  181. package/src/redis/runtime-connection.ts +0 -10
  182. package/src/runtime/agent-types.ts +0 -1
@@ -22,7 +22,7 @@ import type {
22
22
  UpdateAutonomousJobInput,
23
23
  } from '@lota-sdk/shared'
24
24
  import type { Job } from 'bullmq'
25
- import { Context, Cron, Schema, Effect, Layer } from 'effect'
25
+ import { Context, Cron, Schema, Effect, Layer, Ref } from 'effect'
26
26
  import { BoundQuery, RecordId } from 'surrealdb'
27
27
  import { z } from 'zod'
28
28
 
@@ -32,7 +32,8 @@ import type { SurrealDBService } from '../db/service'
32
32
  import { TABLES } from '../db/tables'
33
33
  import { makeEffectTryPromiseWithMessage } from '../effect/helpers'
34
34
  import { DatabaseServiceTag, RuntimeConfigServiceTag } from '../effect/services'
35
- import type { AutonomousJobQueuePayload } from '../queues/autonomous-job.queue'
35
+ import type { AutonomousJobQueuePayload, AutonomousJobQueueRuntime } from '../queues/autonomous-job.queue'
36
+ import { LotaQueuesServiceTag } from '../queues/queues.service'
36
37
  import type { ResolvedLotaRuntimeConfig } from '../runtime/runtime-config'
37
38
  import { extractMessageText } from '../runtime/thread-chat-helpers'
38
39
  import { buildAutonomousAtJobId, encodeBullmqId } from '../utils/autonomous-job-ids'
@@ -49,12 +50,8 @@ import { ExecutionPlanServiceTag } from './execution-plan/execution-plan.service
49
50
  import type { makeQueueJobService } from './queue-job.service'
50
51
  import { QueueJobServiceTag } from './queue-job.service'
51
52
  import type { PreparedThreadTurnResult } from './thread/thread-turn'
52
- import type { ThreadTurnParams } from './thread/thread-turn-preparation.service'
53
53
  import type { makeThreadService } from './thread/thread.service'
54
54
  import { ThreadServiceTag } from './thread/thread.service'
55
- // runThreadTurnInBackground is imported dynamically below
56
-
57
- type ThreadTurnModule = { runThreadTurnInBackground(params: ThreadTurnParams): Promise<PreparedThreadTurnResult> }
58
55
 
59
56
  const AUTONOMOUS_JOB_QUEUE_NAME = 'autonomous-job'
60
57
 
@@ -312,27 +309,22 @@ function getRunRowEffect(
312
309
  })
313
310
  }
314
311
 
315
- function unscheduleRowEffect(row: AutonomousJobRow): Effect.Effect<void, AutonomousJobServiceError> {
312
+ function unscheduleRowEffect(
313
+ deps: AutonomousJobDeps,
314
+ row: AutonomousJobRow,
315
+ ): Effect.Effect<void, AutonomousJobServiceError> {
316
316
  if (row.schedule.kind === 'at') {
317
317
  return Effect.gen(function* () {
318
- const { removeAutonomousAtJob } = yield* effectTryPromise(
319
- () => import('../queues/autonomous-job.queue'),
320
- 'Failed to load autonomous job queue helpers.',
321
- )
322
318
  yield* effectTryPromise(
323
- () => removeAutonomousAtJob(recordIdToString(row.id, TABLES.AUTONOMOUS_JOB)),
319
+ () => deps.autonomousJobQueue.removeAutonomousAtJob(recordIdToString(row.id, TABLES.AUTONOMOUS_JOB)),
324
320
  'Failed to remove autonomous at-job.',
325
321
  )
326
322
  })
327
323
  }
328
324
 
329
325
  return Effect.gen(function* () {
330
- const { removeAutonomousJobScheduler } = yield* effectTryPromise(
331
- () => import('../queues/autonomous-job.queue'),
332
- 'Failed to load autonomous job queue helpers.',
333
- )
334
326
  yield* effectTryPromise(
335
- () => removeAutonomousJobScheduler(recordIdToString(row.id, TABLES.AUTONOMOUS_JOB)),
327
+ () => deps.autonomousJobQueue.removeAutonomousJobScheduler(recordIdToString(row.id, TABLES.AUTONOMOUS_JOB)),
336
328
  'Failed to remove autonomous job scheduler.',
337
329
  )
338
330
  })
@@ -386,14 +378,9 @@ function scheduleRowEffect(
386
378
  })
387
379
  : createRunRowEffect(deps, { autonomousJobId: row.id, threadId: row.threadId })
388
380
 
389
- const { enqueueAutonomousJobRun } = yield* effectTryPromise(
390
- () => import('../queues/autonomous-job.queue'),
391
- 'Failed to load autonomous job queue helpers.',
392
- )
393
-
394
381
  const enqueueResult = yield* effectTryPromise(
395
382
  () =>
396
- enqueueAutonomousJobRun({
383
+ deps.autonomousJobQueue.enqueueAutonomousJobRun({
397
384
  payload: {
398
385
  autonomousJobId: jobId,
399
386
  autonomousJobRunId: recordIdToString(queuedRun.id, TABLES.AUTONOMOUS_JOB_RUN),
@@ -428,13 +415,9 @@ function scheduleRowEffect(
428
415
  } else {
429
416
  const recurringSchedule = row.schedule
430
417
  return Effect.gen(function* () {
431
- const { upsertAutonomousJobScheduler } = yield* effectTryPromise(
432
- () => import('../queues/autonomous-job.queue'),
433
- 'Failed to load autonomous job queue helpers.',
434
- )
435
-
436
418
  yield* effectTryPromise(
437
- () => upsertAutonomousJobScheduler({ autonomousJobId: jobId, schedule: recurringSchedule }),
419
+ () =>
420
+ deps.autonomousJobQueue.upsertAutonomousJobScheduler({ autonomousJobId: jobId, schedule: recurringSchedule }),
438
421
  'Failed to upsert autonomous job scheduler.',
439
422
  )
440
423
 
@@ -564,7 +547,7 @@ function updateEffect(
564
547
  return Effect.gen(function* () {
565
548
  const parsed = UpdateAutonomousJobInputSchema.parse(input)
566
549
  const existing = yield* getRowEffect(deps, jobId)
567
- yield* unscheduleRowEffect(existing)
550
+ yield* unscheduleRowEffect(deps, existing)
568
551
  const nextTitle = parsed.title
569
552
  if (typeof nextTitle === 'string' && compactWhitespace(nextTitle) !== compactWhitespace(existing.title)) {
570
553
  const title = nextTitle
@@ -616,7 +599,7 @@ function pauseEffect(
616
599
  ): Effect.Effect<AutonomousJob, AutonomousJobServiceError> {
617
600
  return Effect.gen(function* () {
618
601
  const row = yield* getRowEffect(deps, jobId)
619
- yield* unscheduleRowEffect(row)
602
+ yield* unscheduleRowEffect(deps, row)
620
603
  yield* effectTryPromise(
621
604
  () =>
622
605
  deps.db.update(
@@ -667,14 +650,10 @@ function runNowEffect(
667
650
  return Effect.gen(function* () {
668
651
  const row = yield* getRowEffect(deps, jobId)
669
652
  const queuedRun = yield* createRunRowEffect(deps, { autonomousJobId: row.id, threadId: row.threadId })
670
- const { enqueueAutonomousJobRun } = yield* effectTryPromise(
671
- () => import('../queues/autonomous-job.queue'),
672
- 'Failed to load autonomous job queue helpers.',
673
- )
674
653
 
675
654
  const enqueueResult = yield* effectTryPromise(
676
655
  () =>
677
- enqueueAutonomousJobRun({
656
+ deps.autonomousJobQueue.enqueueAutonomousJobRun({
678
657
  payload: {
679
658
  autonomousJobId: recordIdToString(row.id, TABLES.AUTONOMOUS_JOB),
680
659
  autonomousJobRunId: recordIdToString(queuedRun.id, TABLES.AUTONOMOUS_JOB_RUN),
@@ -710,7 +689,7 @@ function cancelEffect(
710
689
  ): Effect.Effect<AutonomousJob, AutonomousJobServiceError> {
711
690
  return Effect.gen(function* () {
712
691
  const row = yield* getRowEffect(deps, jobId)
713
- yield* unscheduleRowEffect(row)
692
+ yield* unscheduleRowEffect(deps, row)
714
693
  yield* effectTryPromise(
715
694
  () =>
716
695
  deps.db.update(
@@ -923,7 +902,7 @@ function failQueuedRunEffect(
923
902
  )
924
903
 
925
904
  if (autoPause || terminalOneShot) {
926
- yield* unscheduleRowEffect(currentJobRow)
905
+ yield* unscheduleRowEffect(deps, currentJobRow)
927
906
  }
928
907
 
929
908
  yield* effectTryPromise(
@@ -967,39 +946,41 @@ function failQueuedRunEffect(
967
946
  function executeQueuedRunEffect(
968
947
  deps: AutonomousJobDeps,
969
948
  job: Job<AutonomousJobQueuePayload>,
970
- ): Effect.Effect<{ status: string; summary?: string }, AutonomousJobServiceError> {
971
- let autonomousJobRow: AutonomousJobRow | null = null
972
- let runRow: AutonomousJobRunRow | null = null
973
-
949
+ ): Effect.Effect<{ status: string; summary?: string }, AutonomousJobServiceError, unknown> {
974
950
  return Effect.gen(function* () {
975
- yield* effectTryPromise(() => deps.db.connect(), 'Failed to connect to autonomous job database.')
976
- autonomousJobRow = yield* getRowEffect(deps, job.data.autonomousJobId)
977
- const currentJobRow = autonomousJobRow
978
- const { queueJobId, runRow: initialRunRow } = yield* getOrCreateQueuedRunRowEffect(deps, job, currentJobRow)
979
-
980
- runRow = initialRunRow
981
- if (currentJobRow.status !== 'active' && job.data.trigger === 'scheduled') {
982
- return { status: 'skipped' }
983
- }
951
+ const autonomousJobRowRef = yield* Ref.make<AutonomousJobRow | null>(null)
952
+ const runRowRef = yield* Ref.make<AutonomousJobRunRow | null>(null)
953
+
954
+ return yield* Effect.gen(function* () {
955
+ yield* effectTryPromise(() => deps.db.connect(), 'Failed to connect to autonomous job database.')
956
+ const currentJobRow = yield* getRowEffect(deps, job.data.autonomousJobId)
957
+ yield* Ref.set(autonomousJobRowRef, currentJobRow)
958
+ const { queueJobId, runRow: initialRunRow } = yield* getOrCreateQueuedRunRowEffect(deps, job, currentJobRow)
959
+
960
+ yield* Ref.set(runRowRef, initialRunRow)
961
+ if (currentJobRow.status !== 'active' && job.data.trigger === 'scheduled') {
962
+ return { status: 'skipped' }
963
+ }
984
964
 
985
- runRow = yield* markQueuedRunRunningEffect(deps, initialRunRow, queueJobId)
986
- const currentRunRow = runRow
987
- const inputMessage = buildSyntheticUserMessage(currentJobRow.prompt)
965
+ const currentRunRow = yield* markQueuedRunRunningEffect(deps, initialRunRow, queueJobId)
966
+ yield* Ref.set(runRowRef, currentRunRow)
967
+ const inputMessage = buildSyntheticUserMessage(currentJobRow.prompt)
988
968
 
989
- const [thread, turnModule] = yield* Effect.all([
990
- deps.thread
969
+ const thread = yield* deps.thread
991
970
  .getThread(currentJobRow.threadId)
992
971
  .pipe(
993
972
  Effect.mapError(
994
973
  (cause) => new AutonomousJobServiceError({ message: 'Failed to load autonomous job thread.', cause }),
995
974
  ),
996
- ),
997
- effectTryPromise<ThreadTurnModule>(() => import('./thread/thread-turn'), 'Failed to load thread turn runtime.'),
998
- ])
975
+ )
999
976
 
1000
- const turnResult = yield* effectTryPromise(
1001
- () =>
1002
- turnModule.runThreadTurnInBackground({
977
+ const turnModule = yield* Effect.tryPromise({
978
+ try: () => import('./thread/thread-turn'),
979
+ catch: (cause) => new AutonomousJobServiceError({ message: 'Failed to load thread turn runtime.', cause }),
980
+ })
981
+
982
+ const turnResult = yield* turnModule
983
+ .runThreadTurnInBackground({
1003
984
  thread,
1004
985
  threadRef: ensureRecordId(currentJobRow.threadId, TABLES.THREAD),
1005
986
  orgRef: ensureRecordId(currentJobRow.organizationId, TABLES.ORGANIZATION),
@@ -1007,31 +988,35 @@ function executeQueuedRunEffect(
1007
988
  userName: currentJobRow.ownerUserName,
1008
989
  agentIdOverride: currentJobRow.agentId,
1009
990
  inputMessage,
1010
- }),
1011
- 'Failed to run autonomous job thread turn.',
1012
- )
991
+ })
992
+ .pipe(
993
+ Effect.mapError(
994
+ (cause) => new AutonomousJobServiceError({ message: 'Failed to run autonomous job thread turn.', cause }),
995
+ ),
996
+ )
1013
997
 
1014
- const activePlan = yield* deps.executionPlan
1015
- .getActivePlanForThread(currentJobRow.threadId)
1016
- .pipe(
1017
- Effect.mapError(
1018
- (cause) => new AutonomousJobServiceError({ message: 'Failed to load active execution plan.', cause }),
1019
- ),
1020
- )
998
+ const activePlan = yield* deps.executionPlan
999
+ .getActivePlanForThread(currentJobRow.threadId)
1000
+ .pipe(
1001
+ Effect.mapError(
1002
+ (cause) => new AutonomousJobServiceError({ message: 'Failed to load active execution plan.', cause }),
1003
+ ),
1004
+ )
1021
1005
 
1022
- return yield* completeQueuedRunEffect(deps, { job, currentJobRow, currentRunRow, turnResult, activePlan })
1023
- }).pipe(
1024
- Effect.catch((error: unknown) =>
1025
- Effect.gen(function* () {
1026
- const currentJobRow = autonomousJobRow
1027
- const currentRunRow = runRow
1028
- if (!currentJobRow || !currentRunRow) {
1029
- return yield* new AutonomousJobServiceError({ message: 'Failed to execute autonomous job.', cause: error })
1030
- }
1031
- return yield* failQueuedRunEffect(deps, { job, currentJobRow, currentRunRow, error })
1032
- }),
1033
- ),
1034
- )
1006
+ return yield* completeQueuedRunEffect(deps, { job, currentJobRow, currentRunRow, turnResult, activePlan })
1007
+ }).pipe(
1008
+ Effect.catch((error: unknown) =>
1009
+ Effect.gen(function* () {
1010
+ const currentJobRow = yield* Ref.get(autonomousJobRowRef)
1011
+ const currentRunRow = yield* Ref.get(runRowRef)
1012
+ if (!currentJobRow || !currentRunRow) {
1013
+ return yield* new AutonomousJobServiceError({ message: 'Failed to execute autonomous job.', cause: error })
1014
+ }
1015
+ return yield* failQueuedRunEffect(deps, { job, currentJobRow, currentRunRow, error })
1016
+ }),
1017
+ ),
1018
+ )
1019
+ })
1035
1020
  }
1036
1021
 
1037
1022
  function createAutonomousJobService(deps: AutonomousJobDeps) {
@@ -1059,6 +1044,7 @@ interface AutonomousJobDeps {
1059
1044
  executionPlan: ReturnType<typeof makeExecutionPlanService>
1060
1045
  queueJob: ReturnType<typeof makeQueueJobService>
1061
1046
  thread: ReturnType<typeof makeThreadService>
1047
+ autonomousJobQueue: AutonomousJobQueueRuntime
1062
1048
  }
1063
1049
 
1064
1050
  export function makeAutonomousJobService(deps: AutonomousJobDeps) {
@@ -1068,7 +1054,7 @@ export function makeAutonomousJobService(deps: AutonomousJobDeps) {
1068
1054
  export class AutonomousJobServiceTag extends Context.Service<
1069
1055
  AutonomousJobServiceTag,
1070
1056
  ReturnType<typeof makeAutonomousJobService>
1071
- >()('AutonomousJobService') {}
1057
+ >()('@lota-sdk/core/AutonomousJobService') {}
1072
1058
 
1073
1059
  export const AutonomousJobServiceLive = Layer.effect(
1074
1060
  AutonomousJobServiceTag,
@@ -1078,6 +1064,14 @@ export const AutonomousJobServiceLive = Layer.effect(
1078
1064
  const executionPlan = yield* ExecutionPlanServiceTag
1079
1065
  const queueJob = yield* QueueJobServiceTag
1080
1066
  const thread = yield* ThreadServiceTag
1081
- return makeAutonomousJobService({ db, config, executionPlan, queueJob, thread })
1067
+ const queues = yield* LotaQueuesServiceTag
1068
+ return makeAutonomousJobService({
1069
+ db,
1070
+ config,
1071
+ executionPlan,
1072
+ queueJob,
1073
+ thread,
1074
+ autonomousJobQueue: queues.autonomousJob,
1075
+ })
1082
1076
  }),
1083
1077
  )
@@ -0,0 +1,54 @@
1
+ import { Context, Effect, FiberSet, Layer, Schema } from 'effect'
2
+
3
+ /**
4
+ * Tagged error for the BackgroundWorkService surface. The service itself
5
+ * never returns this — it's reserved for future API extensions.
6
+ */
7
+ export class BackgroundWorkError extends Schema.TaggedErrorClass<BackgroundWorkError>()(
8
+ '@lota-sdk/core/BackgroundWorkError',
9
+ { message: Schema.String, cause: Schema.optional(Schema.Defect) },
10
+ ) {}
11
+
12
+ /**
13
+ * Supervised fire-and-forget fork pool.
14
+ *
15
+ * `run` schedules an effect on a process-wide FiberSet that is interrupted
16
+ * when the runtime scope closes — replaces ad-hoc `Effect.runFork`,
17
+ * `Effect.runForkWith`, and `Effect.forkDetach` call sites that would
18
+ * otherwise leak fibers across shutdown.
19
+ *
20
+ * Both methods accept any `Effect.Effect<A, E>`; failures are logged via
21
+ * `Effect.logError` and never propagate to the caller. `runForget` ignores
22
+ * both the result and the cause — use it for best-effort metrics, cache
23
+ * touches, and other strictly cosmetic side effects.
24
+ */
25
+ export class BackgroundWorkService extends Context.Service<
26
+ BackgroundWorkService,
27
+ {
28
+ readonly run: <A, E>(effect: Effect.Effect<A, E>, label?: string) => Effect.Effect<void>
29
+ readonly runForget: <A, E>(effect: Effect.Effect<A, E>, label?: string) => Effect.Effect<void>
30
+ }
31
+ >()('@lota-sdk/core/BackgroundWorkService') {}
32
+
33
+ export const BackgroundWorkServiceLive = Layer.effect(
34
+ BackgroundWorkService,
35
+ Effect.gen(function* () {
36
+ const set = yield* FiberSet.make<unknown, unknown>()
37
+
38
+ const run = <A, E>(effect: Effect.Effect<A, E>, label?: string): Effect.Effect<void> =>
39
+ Effect.asVoid(
40
+ FiberSet.run(
41
+ set,
42
+ effect.pipe(
43
+ Effect.withLogSpan(label ?? 'background'),
44
+ Effect.catchCause((cause) => Effect.logError(cause)),
45
+ ),
46
+ ),
47
+ )
48
+
49
+ const runForget = <A, E>(effect: Effect.Effect<A, E>, label?: string): Effect.Effect<void> =>
50
+ Effect.asVoid(FiberSet.run(set, effect.pipe(Effect.withLogSpan(label ?? 'background-forget'), Effect.ignore)))
51
+
52
+ return { run, runForget } as const
53
+ }),
54
+ )
@@ -2,7 +2,9 @@ import { Context, Effect, FiberMap, Layer } from 'effect'
2
2
 
3
3
  import { ChatRunRegistry } from '../runtime/chat-run-registry'
4
4
 
5
- export class ChatRunRegistryTag extends Context.Service<ChatRunRegistryTag, ChatRunRegistry>()('ChatRunRegistry') {}
5
+ export class ChatRunRegistryTag extends Context.Service<ChatRunRegistryTag, ChatRunRegistry>()(
6
+ '@lota-sdk/core/ChatRunRegistry',
7
+ ) {}
6
8
 
7
9
  export const ChatRunRegistryLive = Layer.effect(
8
10
  ChatRunRegistryTag,
@@ -77,14 +77,12 @@ export function makeContextCompactionService(deps: ContextCompactionDeps) {
77
77
  typeof thread.lastCompactedMessageId === 'string' ? thread.lastCompactedMessageId : undefined,
78
78
  )
79
79
 
80
- const result = yield* Effect.tryPromise(() =>
81
- contextCompactionRuntime.compactHistory({
82
- summaryText: typeof thread.compactionSummary === 'string' ? thread.compactionSummary : '',
83
- liveMessages,
84
- tailMessageCount: THREAD_RAW_TAIL_MESSAGES,
85
- contextSize: params.contextSize,
86
- }),
87
- )
80
+ const result = yield* contextCompactionRuntime.compactHistory({
81
+ summaryText: typeof thread.compactionSummary === 'string' ? thread.compactionSummary : '',
82
+ liveMessages,
83
+ tailMessageCount: THREAD_RAW_TAIL_MESSAGES,
84
+ contextSize: params.contextSize,
85
+ })
88
86
 
89
87
  if (!result.compacted || !result.lastCompactedMessageId) {
90
88
  return { compacted: false }
@@ -122,7 +120,7 @@ export function makeContextCompactionService(deps: ContextCompactionDeps) {
122
120
  })
123
121
 
124
122
  const compactMemoryBlockEffect = (params: { previousSummary: string; newEntriesText: string }) =>
125
- Effect.tryPromise(() => contextCompactionRuntime.compactMemoryBlockSummary(params))
123
+ contextCompactionRuntime.compactMemoryBlockSummary(params)
126
124
 
127
125
  return {
128
126
  createSummaryMessage(summaryText: string) {
@@ -146,7 +144,7 @@ export function makeContextCompactionService(deps: ContextCompactionDeps) {
146
144
  export class ContextCompactionServiceTag extends Context.Service<
147
145
  ContextCompactionServiceTag,
148
146
  ReturnType<typeof makeContextCompactionService>
149
- >()('ContextCompactionService') {}
147
+ >()('@lota-sdk/core/ContextCompactionService') {}
150
148
 
151
149
  export const ContextCompactionServiceLive = Layer.effect(
152
150
  ContextCompactionServiceTag,
@@ -2,6 +2,7 @@ import { Context, Schema, Effect, Layer } from 'effect'
2
2
 
3
3
  import { chunkMarkdownDocument, chunkPagedDocument, chunkPlainTextDocument } from '../document/org-document-chunking'
4
4
  import type { ParsedDocumentChunk } from '../document/org-document-chunking'
5
+ import { makeEffectTryPromiseWithMessage } from '../effect/helpers'
5
6
  import { RuntimeConfigServiceTag } from '../effect/services'
6
7
  import { ProviderEmbeddings } from '../embeddings/provider'
7
8
  import { sha256Hex } from '../utils/crypto'
@@ -71,25 +72,15 @@ class DocumentChunkServiceError extends Schema.TaggedErrorClass<DocumentChunkSer
71
72
  { message: Schema.String, cause: Schema.Defect },
72
73
  ) {}
73
74
 
75
+ const effectTryDocumentChunkPromise = makeEffectTryPromiseWithMessage(
76
+ (message, cause) => new DocumentChunkServiceError({ message, cause }),
77
+ )
78
+
74
79
  function tryDocumentChunkPromise<A>(
75
80
  message: string,
76
- thunk: () => PromiseLike<A> | Effect.Effect<A, unknown>,
81
+ evaluate: () => PromiseLike<A> | Effect.Effect<A, unknown>,
77
82
  ): Effect.Effect<A, DocumentChunkServiceError> {
78
- return Effect.suspend(() => {
79
- try {
80
- const value = thunk()
81
- if (Effect.isEffect(value)) {
82
- return value.pipe(Effect.mapError((cause) => new DocumentChunkServiceError({ message, cause })))
83
- }
84
-
85
- return Effect.tryPromise({
86
- try: () => Promise.resolve(value),
87
- catch: (cause) => new DocumentChunkServiceError({ message, cause }),
88
- })
89
- } catch (cause) {
90
- return Effect.fail(new DocumentChunkServiceError({ message, cause }))
91
- }
92
- })
83
+ return effectTryDocumentChunkPromise(evaluate, message)
93
84
  }
94
85
 
95
86
  export function makeDocumentChunkService(embeddings: DocumentChunkEmbeddings): DocumentChunkService {
@@ -200,7 +191,7 @@ export function makeDocumentChunkService(embeddings: DocumentChunkEmbeddings): D
200
191
  }
201
192
 
202
193
  export class DocumentChunkServiceTag extends Context.Service<DocumentChunkServiceTag, DocumentChunkService>()(
203
- 'DocumentChunkService',
194
+ '@lota-sdk/core/DocumentChunkService',
204
195
  ) {}
205
196
 
206
197
  export const DocumentChunkServiceLive = Layer.effect(