@lota-sdk/core 0.4.13 → 0.4.15

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 (139) hide show
  1. package/package.json +4 -4
  2. package/src/ai/embedding-cache.ts +17 -11
  3. package/src/ai-gateway/ai-gateway.ts +164 -94
  4. package/src/ai-gateway/index.ts +4 -1
  5. package/src/config/agent-defaults.ts +2 -2
  6. package/src/config/agent-types.ts +1 -1
  7. package/src/config/constants.ts +1 -1
  8. package/src/create-runtime.ts +259 -200
  9. package/src/db/cursor-pagination.ts +2 -9
  10. package/src/db/memory-store.ts +194 -175
  11. package/src/db/memory.ts +125 -71
  12. package/src/db/schema-fingerprint.ts +5 -4
  13. package/src/db/service-normalization.ts +4 -3
  14. package/src/db/service.ts +3 -2
  15. package/src/db/startup.ts +15 -16
  16. package/src/effect/errors.ts +161 -21
  17. package/src/effect/index.ts +0 -1
  18. package/src/embeddings/provider.ts +15 -7
  19. package/src/queues/autonomous-job.queue.ts +10 -22
  20. package/src/queues/delayed-node-promotion.queue.ts +8 -14
  21. package/src/queues/document-processor.queue.ts +13 -4
  22. package/src/queues/memory-consolidation.queue.ts +26 -14
  23. package/src/queues/plan-agent-heartbeat.queue.ts +48 -31
  24. package/src/queues/plan-scheduler.queue.ts +37 -15
  25. package/src/queues/queue-factory.ts +59 -35
  26. package/src/queues/standalone-worker.ts +3 -2
  27. package/src/redis/connection.ts +10 -3
  28. package/src/redis/org-memory-lock.ts +1 -1
  29. package/src/redis/redis-lease-lock.ts +5 -5
  30. package/src/redis/stream-context.ts +1 -1
  31. package/src/runtime/chat-message.ts +64 -1
  32. package/src/runtime/chat-run-orchestration.ts +33 -20
  33. package/src/runtime/context-compaction/context-compaction-runtime.ts +14 -7
  34. package/src/runtime/context-compaction/context-compaction.ts +78 -66
  35. package/src/runtime/domain-layer.ts +19 -13
  36. package/src/runtime/execution-plan.ts +7 -3
  37. package/src/runtime/memory/memory-block.ts +3 -9
  38. package/src/runtime/memory/memory-scope.ts +3 -1
  39. package/src/runtime/plugin-resolution.ts +2 -1
  40. package/src/runtime/post-turn-side-effects.ts +6 -5
  41. package/src/runtime/retrieval-adapters.ts +8 -20
  42. package/src/runtime/runtime-config.ts +3 -9
  43. package/src/runtime/runtime-extensions.ts +2 -4
  44. package/src/runtime/runtime-lifecycle.ts +56 -16
  45. package/src/runtime/runtime-services.ts +180 -102
  46. package/src/runtime/runtime-worker-registry.ts +3 -1
  47. package/src/runtime/social-chat/social-chat-agent-runner.ts +1 -1
  48. package/src/runtime/social-chat/social-chat-history.ts +21 -18
  49. package/src/runtime/social-chat/social-chat.ts +356 -223
  50. package/src/runtime/specialist-runner.ts +3 -1
  51. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +3 -2
  52. package/src/runtime/thread-turn-context.ts +142 -102
  53. package/src/runtime/turn-lifecycle.ts +15 -46
  54. package/src/services/agent-activity.service.ts +1 -1
  55. package/src/services/agent-executor.service.ts +107 -77
  56. package/src/services/autonomous-job.service.ts +354 -293
  57. package/src/services/background-work.service.ts +3 -3
  58. package/src/services/context-compaction.service.ts +7 -2
  59. package/src/services/document-chunk.service.ts +50 -32
  60. package/src/services/execution-plan/execution-plan-schedule.ts +5 -3
  61. package/src/services/execution-plan/execution-plan.service.ts +162 -179
  62. package/src/services/feedback-loop.service.ts +5 -4
  63. package/src/services/graph-full-routing.ts +37 -36
  64. package/src/services/institutional-memory.service.ts +28 -30
  65. package/src/services/learned-skill.service.ts +107 -72
  66. package/src/services/memory/memory-errors.ts +4 -23
  67. package/src/services/memory/memory-org-memory.ts +10 -5
  68. package/src/services/memory/memory-rerank.ts +18 -6
  69. package/src/services/memory/memory.service.ts +170 -111
  70. package/src/services/memory/rerank.service.ts +29 -20
  71. package/src/services/organization-member.service.ts +1 -1
  72. package/src/services/organization.service.ts +69 -75
  73. package/src/services/ownership-dispatcher.service.ts +40 -39
  74. package/src/services/plan/plan-agent-heartbeat.service.ts +22 -24
  75. package/src/services/plan/plan-agent-query.service.ts +39 -31
  76. package/src/services/plan/plan-completion-side-effects.ts +13 -17
  77. package/src/services/plan/plan-coordination.service.ts +2 -1
  78. package/src/services/plan/plan-cycle.service.ts +6 -5
  79. package/src/services/plan/plan-deadline.service.ts +57 -54
  80. package/src/services/plan/plan-event-delivery.service.ts +5 -4
  81. package/src/services/plan/plan-executor-graph.ts +18 -15
  82. package/src/services/plan/plan-executor.service.ts +235 -262
  83. package/src/services/plan/plan-run.service.ts +169 -93
  84. package/src/services/plan/plan-scheduler.service.ts +192 -202
  85. package/src/services/plan/plan-template.service.ts +1 -1
  86. package/src/services/plan/plan-transaction-events.ts +1 -1
  87. package/src/services/plan/plan-workspace.service.ts +23 -14
  88. package/src/services/plugin-executor.service.ts +5 -9
  89. package/src/services/queue-job.service.ts +117 -59
  90. package/src/services/recent-activity-title.service.ts +13 -12
  91. package/src/services/recent-activity.service.ts +6 -1
  92. package/src/services/social-chat-history.service.ts +29 -25
  93. package/src/services/system-executor.service.ts +5 -9
  94. package/src/services/thread/thread-active-run.ts +2 -2
  95. package/src/services/thread/thread-listing.ts +61 -57
  96. package/src/services/thread/thread-memory-block.ts +73 -48
  97. package/src/services/thread/thread-message.service.ts +76 -65
  98. package/src/services/thread/thread-record-store.ts +8 -8
  99. package/src/services/thread/thread-title.service.ts +10 -4
  100. package/src/services/thread/thread-turn-execution.ts +43 -45
  101. package/src/services/thread/thread-turn-preparation.service.ts +257 -135
  102. package/src/services/thread/thread-turn-streaming.ts +83 -92
  103. package/src/services/thread/thread-turn.ts +18 -16
  104. package/src/services/thread/thread.service.ts +135 -100
  105. package/src/services/user.service.ts +45 -48
  106. package/src/storage/attachment-parser.ts +6 -2
  107. package/src/storage/attachment-storage.service.ts +5 -6
  108. package/src/storage/generated-document-storage.service.ts +1 -1
  109. package/src/system-agents/context-compaction.agent.ts +10 -9
  110. package/src/system-agents/delegated-agent-factory.ts +30 -6
  111. package/src/system-agents/memory-reranker.agent.ts +10 -9
  112. package/src/system-agents/memory.agent.ts +10 -9
  113. package/src/system-agents/recent-activity-title-refiner.agent.ts +13 -15
  114. package/src/system-agents/regular-chat-memory-digest.agent.ts +13 -12
  115. package/src/system-agents/skill-extractor.agent.ts +13 -12
  116. package/src/system-agents/skill-manager.agent.ts +13 -12
  117. package/src/system-agents/thread-router.agent.ts +11 -7
  118. package/src/system-agents/title-generator.agent.ts +13 -12
  119. package/src/tools/fetch-webpage.tool.ts +13 -13
  120. package/src/tools/memory-block.tool.ts +3 -1
  121. package/src/tools/plan-approval.tool.ts +4 -2
  122. package/src/tools/read-file-parts.tool.ts +10 -4
  123. package/src/tools/remember-memory.tool.ts +3 -1
  124. package/src/tools/research-topic.tool.ts +9 -5
  125. package/src/tools/search-web.tool.ts +16 -16
  126. package/src/tools/search.tool.ts +20 -5
  127. package/src/tools/team-think.tool.ts +61 -38
  128. package/src/utils/async.ts +5 -5
  129. package/src/utils/errors.ts +19 -18
  130. package/src/utils/sse-keepalive.ts +28 -25
  131. package/src/workers/bootstrap.ts +75 -11
  132. package/src/workers/memory-consolidation.worker.ts +82 -91
  133. package/src/workers/organization-learning.worker.ts +14 -4
  134. package/src/workers/regular-chat-memory-digest.runner.ts +105 -67
  135. package/src/workers/skill-extraction.runner.ts +97 -61
  136. package/src/workers/utils/repo-structure-extractor.ts +13 -8
  137. package/src/workers/utils/thread-message-query.ts +24 -24
  138. package/src/workers/worker-utils.ts +23 -4
  139. package/src/effect/helpers.ts +0 -123
@@ -1,6 +1,7 @@
1
1
  import { Schema, Effect } from 'effect'
2
2
 
3
- import { createContextCompactionAgent } from '../../system-agents/context-compaction.agent'
3
+ import type { AiGatewayModels } from '../../ai-gateway/ai-gateway'
4
+ import { makeContextCompactionAgentFactory } from '../../system-agents/context-compaction.agent'
4
5
  import type { GenerateHelperStructuredParams, GenerateHelperTextParams } from '../helper-model'
5
6
  import {
6
7
  buildContextCompactionPrompt,
@@ -29,12 +30,13 @@ interface HelperModelRuntime {
29
30
 
30
31
  interface CreateContextCompactionRuntimeDeps {
31
32
  helperModelRuntime: HelperModelRuntime
33
+ aiGatewayModels: AiGatewayModels
32
34
  now?: () => number
33
35
  randomId?: () => string
34
36
  }
35
37
 
36
38
  class ContextCompactionRuntimeError extends Schema.TaggedErrorClass<ContextCompactionRuntimeError>()(
37
- 'ContextCompactionRuntimeError',
39
+ '@lota-sdk/core/ContextCompactionRuntimeError',
38
40
  { message: Schema.String, cause: Schema.Defect },
39
41
  ) {}
40
42
 
@@ -48,11 +50,15 @@ function tryContextCompactionPromise<A>(
48
50
  })
49
51
  }
50
52
 
51
- function runContextCompacterEffect(helperModelRuntime: HelperModelRuntime, params: ContextCompactionRunnerParams) {
53
+ function runContextCompacterEffect(
54
+ helperModelRuntime: HelperModelRuntime,
55
+ aiGatewayModels: AiGatewayModels,
56
+ params: ContextCompactionRunnerParams,
57
+ ) {
52
58
  return tryContextCompactionPromise('Failed to compact runtime context.', () =>
53
59
  helperModelRuntime.generateHelperStructured({
54
60
  tag: 'context-compaction',
55
- createAgent: createContextCompactionAgent,
61
+ createAgent: makeContextCompactionAgentFactory(aiGatewayModels),
56
62
  messages: [
57
63
  {
58
64
  role: 'user',
@@ -69,10 +75,11 @@ function runContextCompacterEffect(helperModelRuntime: HelperModelRuntime, param
69
75
  }
70
76
 
71
77
  export function createWiredContextCompactionRuntime(deps: CreateContextCompactionRuntimeDeps) {
72
- const { helperModelRuntime } = deps
78
+ const { helperModelRuntime, aiGatewayModels } = deps
79
+ const createAgent = makeContextCompactionAgentFactory(aiGatewayModels)
73
80
 
74
81
  const runtime = createContextCompactionRuntime({
75
- runCompacter: (params) => runContextCompacterEffect(helperModelRuntime, params),
82
+ runCompacter: (params) => runContextCompacterEffect(helperModelRuntime, aiGatewayModels, params),
76
83
  now: deps.now,
77
84
  randomId: deps.randomId,
78
85
  thresholdRatio: CONTEXT_COMPACTION_THRESHOLD_RATIO,
@@ -92,7 +99,7 @@ export function createWiredContextCompactionRuntime(deps: CreateContextCompactio
92
99
  return tryContextCompactionPromise('Failed to compact memory block summary.', () =>
93
100
  helperModelRuntime.generateHelperText({
94
101
  tag: 'memory-block-compaction',
95
- createAgent: createContextCompactionAgent,
102
+ createAgent,
96
103
  messages: [{ role: 'user', content: buildMemoryBlockCompactionPrompt({ previousSummary, newEntriesText }) }],
97
104
  maxOutputTokens: CONTEXT_COMPACTION_MAX_OUTPUT_TOKENS,
98
105
  }),
@@ -2,7 +2,7 @@ import type { ChatMessage } from '@lota-sdk/shared'
2
2
  import { Duration, Effect, Schedule, Schema } from 'effect'
3
3
  import { z } from 'zod'
4
4
 
5
- import { iterateEffect } from '../../effect/helpers'
5
+ import { ERROR_TAGS } from '../../effect/errors'
6
6
  import { nowEpochMillis } from '../../utils/date-time'
7
7
  import {
8
8
  CHARS_PER_TOKEN_ESTIMATE,
@@ -60,12 +60,12 @@ export interface ContextCompactionRunnerParams {
60
60
  transcript: string
61
61
  }
62
62
 
63
- class CompactionError extends Schema.TaggedErrorClass<CompactionError>()('CompactionError', {
63
+ class CompactionError extends Schema.TaggedErrorClass<CompactionError>()(ERROR_TAGS.CompactionError, {
64
64
  message: Schema.String,
65
65
  cause: Schema.optional(Schema.Defect),
66
66
  }) {}
67
67
 
68
- class CompactionParseError extends Schema.TaggedErrorClass<CompactionParseError>()('CompactionParseError', {
68
+ class CompactionParseError extends Schema.TaggedErrorClass<CompactionParseError>()(ERROR_TAGS.CompactionParseError, {
69
69
  message: Schema.String,
70
70
  cause: Schema.optional(Schema.Defect),
71
71
  }) {}
@@ -88,9 +88,11 @@ export interface CompactionOutput {
88
88
  summary: string
89
89
  }
90
90
 
91
+ type ContextCompactionRunnerError = { readonly _tag: string; readonly message?: string }
92
+
91
93
  export type ContextCompactionRunner = (
92
94
  params: ContextCompactionRunnerParams,
93
- ) => Effect.Effect<CompactionOutput, unknown>
95
+ ) => Effect.Effect<CompactionOutput, ContextCompactionRunnerError, never>
94
96
 
95
97
  export interface CreateContextCompactionRuntimeOptions {
96
98
  runCompacter: ContextCompactionRunner
@@ -342,22 +344,29 @@ export function createContextCompactionRuntime(
342
344
  const chunks = splitByCharBudget(params.newMessages, compactionChunkMaxChars)
343
345
  const initialSummary = normalizeSummary(params.previousSummary)
344
346
 
345
- const finalSummary = yield* iterateEffect<{ summary: string; index: number }, CompactionError, never>(
346
- { summary: initialSummary, index: 0 },
347
- {
348
- while: (state) => state.index < chunks.length,
349
- body: (state) =>
350
- Effect.gen(function* () {
347
+ const stepSummary = (state: {
348
+ summary: string
349
+ index: number
350
+ }): Effect.Effect<{ summary: string; index: number }, CompactionError> =>
351
+ state.index >= chunks.length
352
+ ? Effect.succeed(state)
353
+ : Effect.gen(function* () {
351
354
  const chunk = chunks[state.index]
352
355
  const transcript = toCompactionTranscript(chunk)
353
356
  const output = yield* options.runCompacter({ previousSummary: state.summary, chunk, transcript }).pipe(
354
- Effect.mapError((error) => new CompactionError({ message: String(error), cause: error })),
357
+ Effect.mapError(
358
+ (error) =>
359
+ new CompactionError({
360
+ message: error.message ?? `Context compaction runner failed with ${error._tag}.`,
361
+ cause: error,
362
+ }),
363
+ ),
355
364
  Effect.retry(COMPACTION_RUNNER_RETRY_OPTIONS),
356
365
  )
357
- return { summary: normalizeSummary(output.summary), index: state.index + 1 }
358
- }),
359
- },
360
- )
366
+ return yield* stepSummary({ summary: normalizeSummary(output.summary), index: state.index + 1 })
367
+ })
368
+
369
+ const finalSummary = yield* stepSummary({ summary: initialSummary, index: 0 })
361
370
 
362
371
  return { summary: finalSummary.summary }
363
372
  })
@@ -419,59 +428,62 @@ export function createContextCompactionRuntime(
419
428
  done: false,
420
429
  }
421
430
 
422
- const finalState = yield* iterateEffect<CompactionLoopState, CompactionError, never>(initialState, {
423
- while: (state) => !state.done,
424
- body: (state) =>
425
- Effect.gen(function* () {
426
- const assessment = shouldCompactHistory({
427
- summaryText: state.summaryText,
428
- liveMessages: state.remainingMessages,
429
- contextSize: params.contextSize,
431
+ const stepHistory = (state: CompactionLoopState): Effect.Effect<CompactionLoopState, CompactionError> =>
432
+ state.done
433
+ ? Effect.succeed(state)
434
+ : Effect.gen(function* () {
435
+ const assessment = shouldCompactHistory({
436
+ summaryText: state.summaryText,
437
+ liveMessages: state.remainingMessages,
438
+ contextSize: params.contextSize,
439
+ })
440
+
441
+ if (!assessment.shouldCompact) {
442
+ return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
443
+ }
444
+
445
+ const boundary = Math.max(0, state.remainingMessages.length - params.tailMessageCount)
446
+ if (boundary <= 0) {
447
+ return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
448
+ }
449
+
450
+ const candidatePrefix = state.remainingMessages.slice(0, boundary)
451
+ const messagesToCompact = candidatePrefix.filter((message) => !readIsCompacted(message))
452
+ const contextMessages = messagesToCompact
453
+ .map(toContextMessageFromChatMessage)
454
+ .filter((message) => compactWhitespace(message.text).length > 0)
455
+ const sourceText = toCompactionTranscript(contextMessages)
456
+
457
+ if (!compactWhitespace(sourceText)) {
458
+ return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
459
+ }
460
+
461
+ const compacted = yield* compactContextMessagesEffect({
462
+ previousSummary: state.summaryText,
463
+ newMessages: contextMessages,
464
+ })
465
+ const rolledSummary = yield* rollupSummaryIfOversizedEffect(normalizeSummary(compacted.summary))
466
+
467
+ if (rolledSummary.length >= sourceText.length) {
468
+ return yield* new CompactionError({
469
+ message: 'Compaction summary is not shorter than compacted source',
470
+ })
471
+ }
472
+
473
+ return yield* stepHistory({
474
+ summaryText: rolledSummary,
475
+ remainingMessages: state.remainingMessages.slice(boundary),
476
+ compactedMessages: [
477
+ ...state.compactedMessages,
478
+ ...candidatePrefix.map((message) => markMessageCompacted(message, now)),
479
+ ],
480
+ lastCompactedMessageId: candidatePrefix.at(-1)?.id ?? state.lastCompactedMessageId,
481
+ estimatedTokens: assessment.estimatedTokens,
482
+ done: false,
483
+ })
430
484
  })
431
485
 
432
- if (!assessment.shouldCompact) {
433
- return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
434
- }
435
-
436
- const boundary = Math.max(0, state.remainingMessages.length - params.tailMessageCount)
437
- if (boundary <= 0) {
438
- return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
439
- }
440
-
441
- const candidatePrefix = state.remainingMessages.slice(0, boundary)
442
- const messagesToCompact = candidatePrefix.filter((message) => !readIsCompacted(message))
443
- const contextMessages = messagesToCompact
444
- .map(toContextMessageFromChatMessage)
445
- .filter((message) => compactWhitespace(message.text).length > 0)
446
- const sourceText = toCompactionTranscript(contextMessages)
447
-
448
- if (!compactWhitespace(sourceText)) {
449
- return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
450
- }
451
-
452
- const compacted = yield* compactContextMessagesEffect({
453
- previousSummary: state.summaryText,
454
- newMessages: contextMessages,
455
- })
456
- const rolledSummary = yield* rollupSummaryIfOversizedEffect(normalizeSummary(compacted.summary))
457
-
458
- if (rolledSummary.length >= sourceText.length) {
459
- return yield* new CompactionError({ message: 'Compaction summary is not shorter than compacted source' })
460
- }
461
-
462
- return {
463
- summaryText: rolledSummary,
464
- remainingMessages: state.remainingMessages.slice(boundary),
465
- compactedMessages: [
466
- ...state.compactedMessages,
467
- ...candidatePrefix.map((message) => markMessageCompacted(message, now)),
468
- ],
469
- lastCompactedMessageId: candidatePrefix.at(-1)?.id ?? state.lastCompactedMessageId,
470
- estimatedTokens: assessment.estimatedTokens,
471
- done: false,
472
- }
473
- }),
474
- })
486
+ const finalState = yield* stepHistory(initialState)
475
487
 
476
488
  return buildExitResult(finalState)
477
489
  })
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Builds the domain-service Layer tree for `createLotaRuntime`.
3
3
  *
4
- * The services form a 9-tier dependency graph on top of the infrastructure
4
+ * The services form a tiered dependency graph on top of the infrastructure
5
5
  * layer (config, logging, database, redis, agents, threads, extensions).
6
6
  * Each tier is provided with the accumulated context of earlier tiers so
7
7
  * every service resolves cleanly when the ManagedRuntime eagerly loads them.
@@ -10,7 +10,7 @@
10
10
  import type { Layer as LayerType } from 'effect'
11
11
  import { Layer } from 'effect'
12
12
 
13
- import { AiGatewayLive } from '../ai-gateway/ai-gateway'
13
+ import type { AiGatewayModelsTag, AiGatewayTag, RuntimeBridgeTag } from '../ai-gateway/ai-gateway'
14
14
  import { EmbeddingCacheLive } from '../ai/embedding-cache'
15
15
  import type { buildInfrastructureLayer } from '../effect/layers'
16
16
  import { LotaQueuesLive } from '../queues/queues.service'
@@ -85,12 +85,18 @@ function provide<A, E, R extends RCtx, RCtx, E2>(
85
85
 
86
86
  type InfrastructureLayer = ReturnType<typeof buildInfrastructureLayer>
87
87
 
88
+ type BridgeLayer = LayerType.Layer<AiGatewayTag | AiGatewayModelsTag | RuntimeBridgeTag, never, never>
89
+
88
90
  /**
89
91
  * Compose the domain service layer tree on top of the supplied infrastructure
90
- * layer. The returned layer has no remaining requirements and can be fed
91
- * straight into `ManagedRuntime.make`.
92
+ * layer. `bridgeLayer` provides `AiGatewayModelsTag` and `RuntimeBridgeTag`
93
+ * these are constructed at the host boundary (`createLotaRuntime`) via
94
+ * `Deferred` because they reference the `ManagedRuntime` that is being built.
95
+ * They are threaded into the domain context so service layers that need them
96
+ * can `yield*` the tags directly instead of prop-drilling `runPromise`.
92
97
  */
93
- export function buildDomainServiceLayer(infrastructureLayer: InfrastructureLayer) {
98
+ export function buildDomainServiceLayer(infrastructureLayer: InfrastructureLayer, bridgeLayer: BridgeLayer) {
99
+ const baseCtx = Layer.mergeAll(infrastructureLayer, bridgeLayer)
94
100
  const tier0 = provide(
95
101
  Layer.mergeAll(
96
102
  BackgroundWorkServiceLive,
@@ -103,11 +109,11 @@ export function buildDomainServiceLayer(infrastructureLayer: InfrastructureLayer
103
109
  PlanBuilderServiceLive,
104
110
  WriteIntentValidatorServiceLive,
105
111
  ),
106
- infrastructureLayer,
112
+ baseCtx,
107
113
  )
108
114
  const ctx0 = Layer.mergeAll(
109
- infrastructureLayer,
110
- provide(Layer.mergeAll(AiGatewayLive, EmbeddingCacheLive, FirecrawlLive, HelperModelLive), infrastructureLayer),
115
+ baseCtx,
116
+ provide(Layer.mergeAll(EmbeddingCacheLive, FirecrawlLive, HelperModelLive), baseCtx),
111
117
  tier0,
112
118
  )
113
119
 
@@ -178,10 +184,7 @@ export function buildDomainServiceLayer(infrastructureLayer: InfrastructureLayer
178
184
  const tier5 = provide(PlanExecutorServiceLive, ctx4)
179
185
  const ctx5 = Layer.mergeAll(ctx4, tier5)
180
186
 
181
- const tier6 = provide(
182
- Layer.mergeAll(OwnershipDispatcherServiceLive, PlanAgentHeartbeatServiceLive, PlanDeadlineServiceLive),
183
- ctx5,
184
- )
187
+ const tier6 = provide(Layer.mergeAll(OwnershipDispatcherServiceLive, PlanDeadlineServiceLive), ctx5)
185
188
  const ctx6 = Layer.mergeAll(ctx5, tier6)
186
189
 
187
190
  const tier7 = provide(Layer.mergeAll(ExecutionPlanServiceLive, GlobalOrchestratorServiceLive), ctx6)
@@ -199,5 +202,8 @@ export function buildDomainServiceLayer(infrastructureLayer: InfrastructureLayer
199
202
  const ctx8 = Layer.mergeAll(ctx7, tier8)
200
203
 
201
204
  const tier9 = provide(Layer.mergeAll(PlanCycleServiceLive, ThreadTurnServiceLive), ctx8)
202
- return Layer.mergeAll(ctx8, tier9)
205
+ const ctx9 = Layer.mergeAll(ctx8, tier9)
206
+
207
+ const tier10 = provide(PlanAgentHeartbeatServiceLive, ctx9)
208
+ return Layer.mergeAll(ctx9, tier10)
203
209
  }
@@ -26,7 +26,7 @@ function formatExecutionPlansForPrompt(plans: SerializableExecutionPlan[]): stri
26
26
  }
27
27
 
28
28
  export class ExecutionPlanCacheError extends Schema.TaggedErrorClass<ExecutionPlanCacheError>()(
29
- 'ExecutionPlanCacheError',
29
+ '@lota-sdk/core/ExecutionPlanCacheError',
30
30
  { message: Schema.String, cause: Schema.Defect },
31
31
  ) {}
32
32
 
@@ -42,7 +42,11 @@ export function buildExecutionPlanInstructionSections(plans: SerializableExecuti
42
42
  export function createExecutionPlanInstructionSectionCache(params: {
43
43
  disabled?: boolean
44
44
  loadPlansEffect: () => Effect.Effect<SerializableExecutionPlan[], ExecutionPlanCacheError>
45
+ /** Promise adapter used by the `getPlans()` / `getSections()` Promise API.
46
+ * Required so this module never reaches for an ambient `Effect.runPromise`. */
47
+ runPromise: <A, E>(effect: Effect.Effect<A, E>) => Promise<A>
45
48
  }) {
49
+ const runPromise = params.runPromise
46
50
  const [getPlansCachedEffect, invalidatePlansEffect] = Effect.runSync(
47
51
  Effect.cachedInvalidateWithTTL(
48
52
  Effect.suspend(() => (params.disabled ? Effect.succeed([]) : params.loadPlansEffect())),
@@ -75,10 +79,10 @@ export function createExecutionPlanInstructionSectionCache(params: {
75
79
  getPlansEffect,
76
80
  getSectionsEffect,
77
81
  getPlans() {
78
- return Effect.runPromise(getPlansEffect())
82
+ return runPromise(getPlansEffect())
79
83
  },
80
84
  getSections() {
81
- return Effect.runPromise(getSectionsEffect())
85
+ return runPromise(getSectionsEffect())
82
86
  },
83
87
  }
84
88
  }
@@ -5,7 +5,7 @@ import { nowDate } from '../../utils/date-time'
5
5
  import { compactWhitespace } from '../../utils/string'
6
6
 
7
7
  export class MemoryBlockCompactError extends Schema.TaggedErrorClass<MemoryBlockCompactError>()(
8
- 'MemoryBlockCompactError',
8
+ '@lota-sdk/core/MemoryBlockCompactError',
9
9
  { message: Schema.String, cause: Schema.Defect },
10
10
  ) {}
11
11
 
@@ -65,7 +65,7 @@ export interface CompactMemoryBlockEntriesParams {
65
65
  compact: (params: {
66
66
  previousSummary: string
67
67
  newEntriesText: string
68
- }) => PromiseLike<string> | Effect.Effect<string, MemoryBlockCompactError>
68
+ }) => Effect.Effect<string, MemoryBlockCompactError>
69
69
  }
70
70
 
71
71
  export interface CompactMemoryBlockEntriesResult {
@@ -119,13 +119,7 @@ export function compactMemoryBlockEntries(
119
119
  while (entries.length >= params.triggerEntries) {
120
120
  const chunk = entries.slice(0, params.chunkEntries)
121
121
  const compactParams = { previousSummary: summary, newEntriesText: toMemoryBlockEntriesSource(chunk) }
122
- const value = params.compact(compactParams)
123
- const raw = yield* Effect.isEffect(value)
124
- ? value
125
- : Effect.tryPromise({
126
- try: () => Promise.resolve(value),
127
- catch: (cause) => new MemoryBlockCompactError({ message: 'compact callback failed', cause }),
128
- })
122
+ const raw = yield* params.compact(compactParams)
129
123
  const nextSummary = raw.trim()
130
124
 
131
125
  if (!nextSummary) {
@@ -1,11 +1,13 @@
1
1
  import { Effect, Schema } from 'effect'
2
2
 
3
+ import { ERROR_TAGS } from '../../effect/errors'
4
+
3
5
  export const ORG_SCOPE_PREFIX = 'org'
4
6
 
5
7
  const SCOPE_ID_MAX_LENGTH = 255
6
8
  const SCOPE_PREFIX_REGEX = /^[a-z][a-z0-9_]*$/
7
9
 
8
- export class MemoryScopeError extends Schema.TaggedErrorClass<MemoryScopeError>()('MemoryScopeError', {
10
+ export class MemoryScopeError extends Schema.TaggedErrorClass<MemoryScopeError>()(ERROR_TAGS.MemoryScopeError, {
9
11
  message: Schema.String,
10
12
  }) {}
11
13
 
@@ -1,13 +1,14 @@
1
1
  import { Schema, Effect } from 'effect'
2
2
 
3
3
  import type { RecordIdRef } from '../db/record-id'
4
+ import { ERROR_TAGS } from '../effect/errors'
4
5
  import type { LotaRuntimeAdapters, LotaRuntimeIndexedRepositoriesContext } from './runtime-extensions'
5
6
 
6
7
  function isRecord(value: unknown): value is Record<string, unknown> {
7
8
  return typeof value === 'object' && value !== null
8
9
  }
9
10
 
10
- class PluginResolutionError extends Schema.TaggedErrorClass<PluginResolutionError>()('PluginResolutionError', {
11
+ class PluginResolutionError extends Schema.TaggedErrorClass<PluginResolutionError>()(ERROR_TAGS.PluginResolutionError, {
11
12
  stage: Schema.Literals([
12
13
  'configuration',
13
14
  'linear-installation',
@@ -3,6 +3,7 @@ import { Schema, Effect } from 'effect'
3
3
 
4
4
  import type { ResolvedAgentConfig } from '../config/agent-defaults'
5
5
  import type { RecordIdRef } from '../db/record-id'
6
+ import { ERROR_TAGS } from '../effect/errors'
6
7
  import { AgentConfigServiceTag, RuntimeAdaptersServiceTag } from '../effect/services'
7
8
  import { LotaQueuesServiceTag } from '../queues/queues.service'
8
9
  import { RecentActivityServiceTag } from '../services/recent-activity.service'
@@ -27,10 +28,10 @@ import {
27
28
  toHistoryMessages,
28
29
  } from './thread-chat-helpers'
29
30
 
30
- class PostTurnSideEffectsError extends Schema.TaggedErrorClass<PostTurnSideEffectsError>()('PostTurnSideEffectsError', {
31
- message: Schema.String,
32
- cause: Schema.Defect,
33
- }) {}
31
+ class PostTurnSideEffectsError extends Schema.TaggedErrorClass<PostTurnSideEffectsError>()(
32
+ ERROR_TAGS.PostTurnSideEffectsError,
33
+ { message: Schema.String, cause: Schema.Defect },
34
+ ) {}
34
35
 
35
36
  function tryPostTurnSideEffect<A>(
36
37
  message: string,
@@ -214,7 +215,7 @@ export const runPostTurnSideEffects = Effect.fn('PostTurnSideEffects.run')(funct
214
215
  () => {
215
216
  const enqueuePostChatOrgAction = runtimeAdapters.enqueuePostChatOrgAction
216
217
  if (!enqueuePostChatOrgAction) {
217
- return
218
+ return Promise.resolve()
218
219
  }
219
220
 
220
221
  const sourceCreatedAt = referenceUserMessage.metadata?.createdAt ?? nowEpochMillis()
@@ -1,8 +1,10 @@
1
1
  import { Schema, Effect } from 'effect'
2
2
 
3
+ import { ERROR_TAGS } from '../effect/errors'
4
+
3
5
  interface ScopedRetrievalTask<TCandidate, E = never> {
4
6
  scopeTag: string
5
- retrieve: () => PromiseLike<TCandidate[]> | Effect.Effect<TCandidate[], E>
7
+ retrieve: () => Effect.Effect<TCandidate[], E>
6
8
  }
7
9
 
8
10
  interface ScopedRetrievalResult<TCandidate> {
@@ -10,7 +12,7 @@ interface ScopedRetrievalResult<TCandidate> {
10
12
  candidates: TCandidate[]
11
13
  }
12
14
 
13
- class ScopedRetrievalError extends Schema.TaggedErrorClass<ScopedRetrievalError>()('ScopedRetrievalError', {
15
+ class ScopedRetrievalError extends Schema.TaggedErrorClass<ScopedRetrievalError>()(ERROR_TAGS.ScopedRetrievalError, {
14
16
  scopeTag: Schema.String,
15
17
  message: Schema.String,
16
18
  cause: Schema.Defect,
@@ -26,24 +28,10 @@ export function executeScopedRetrieval<TCandidate, E>(
26
28
  return Effect.forEach(
27
29
  tasks,
28
30
  (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
- }),
31
+ task.retrieve().pipe(
32
+ Effect.mapError((cause) => toScopedRetrievalError(task.scopeTag, cause)),
33
+ Effect.map((candidates) => ({ scopeTag: task.scopeTag, candidates })),
34
+ ),
47
35
  { concurrency: 'unbounded' },
48
36
  )
49
37
  }
@@ -105,16 +105,10 @@ export interface LotaRuntimeSocialChatConfig {
105
105
  slack?: LotaSocialChatSlackConfig
106
106
  historyRedisKeyPrefix?: string
107
107
  stateRedisKeyPrefix?: string
108
- resolveContext: (
109
- params: LotaSocialChatResolveContextParams,
110
- ) => LotaSocialChatResolvedContext | Promise<LotaSocialChatResolvedContext>
111
- buildAgentTools: (params: BuildSocialChatAgentToolsParams) => ToolSet | Promise<ToolSet>
108
+ resolveContext: (params: LotaSocialChatResolveContextParams) => Promise<LotaSocialChatResolvedContext>
109
+ buildAgentTools: (params: BuildSocialChatAgentToolsParams) => Promise<ToolSet>
112
110
  getConsultParticipants?:
113
- | ((params: {
114
- workspaceId: RecordIdRef
115
- workspaceIdString: string
116
- platform: 'slack'
117
- }) => string[] | Promise<string[]>)
111
+ | ((params: { workspaceId: RecordIdRef; workspaceIdString: string; platform: 'slack' }) => Promise<string[]>)
118
112
  | undefined
119
113
  }
120
114
 
@@ -35,12 +35,10 @@ export interface LotaRuntimeProfileProjection {
35
35
 
36
36
  export interface LotaRuntimeWorkspaceProvider {
37
37
  getWorkspace(workspaceId: RecordIdRef): Promise<Record<string, unknown>>
38
- getLifecycleState?(
39
- workspace: Record<string, unknown>,
40
- ): Promise<LotaRuntimeWorkspaceLifecycleState> | LotaRuntimeWorkspaceLifecycleState
38
+ getLifecycleState?(workspace: Record<string, unknown>): Promise<LotaRuntimeWorkspaceLifecycleState>
41
39
  readProfileProjectionState?(
42
40
  workspace: Record<string, unknown>,
43
- ): Promise<LotaRuntimeWorkspaceProjectionState | undefined> | LotaRuntimeWorkspaceProjectionState | undefined
41
+ ): Promise<LotaRuntimeWorkspaceProjectionState | undefined>
44
42
  buildPromptSummary?(workspaceId: RecordIdRef): Promise<string | undefined>
45
43
  listRecentDomainEvents?(workspaceId: RecordIdRef, limit?: number): Promise<Array<Record<string, unknown>>>
46
44
  hasActiveKnowledgeSources?(workspaceId: string): Promise<boolean>