@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
@@ -1,7 +1,8 @@
1
1
  import type { ChatMessage } from '@lota-sdk/shared'
2
- import { Schema, Effect } from 'effect'
2
+ import { Duration, Effect, Schedule, Schema } from 'effect'
3
3
  import { z } from 'zod'
4
4
 
5
+ import { iterateEffect } from '../../effect/helpers'
5
6
  import { nowEpochMillis } from '../../utils/date-time'
6
7
  import {
7
8
  CHARS_PER_TOKEN_ESTIMATE,
@@ -64,6 +65,13 @@ class CompactionError extends Schema.TaggedErrorClass<CompactionError>()('Compac
64
65
  cause: Schema.optional(Schema.Defect),
65
66
  }) {}
66
67
 
68
+ class CompactionParseError extends Schema.TaggedErrorClass<CompactionParseError>()('CompactionParseError', {
69
+ message: Schema.String,
70
+ cause: Schema.optional(Schema.Defect),
71
+ }) {}
72
+
73
+ const COMPACTION_RUNNER_RETRY_OPTIONS = { times: 2, schedule: Schedule.exponential(Duration.millis(500), 2) } as const
74
+
67
75
  export interface ContextCompactionPromptParams {
68
76
  previousSummary: string
69
77
  transcript: string
@@ -325,22 +333,32 @@ export function createContextCompactionRuntime(
325
333
  return { estimatedTokens, threshold, shouldCompact: estimatedTokens >= threshold }
326
334
  }
327
335
 
328
- const compactContextMessagesEffect = (params: { previousSummary: string; newMessages: ContextMessage[] }) =>
329
- Effect.gen(function* () {
330
- const chunks = splitByCharBudget(params.newMessages, compactionChunkMaxChars)
331
- let summary = normalizeSummary(params.previousSummary)
332
-
333
- for (const chunk of chunks) {
334
- const transcript = toCompactionTranscript(chunk)
335
- const output = yield* Effect.tryPromise({
336
- try: () => options.runCompacter({ previousSummary: summary, chunk, transcript }),
337
- catch: (error: unknown) => new CompactionError({ message: String(error), cause: error }),
338
- })
339
- summary = normalizeSummary(output.summary)
340
- }
341
-
342
- return { summary }
343
- })
336
+ const compactContextMessagesEffect = Effect.fn('ContextCompaction.compactContextMessages')(function* (params: {
337
+ previousSummary: string
338
+ newMessages: ContextMessage[]
339
+ }) {
340
+ const chunks = splitByCharBudget(params.newMessages, compactionChunkMaxChars)
341
+ const initialSummary = normalizeSummary(params.previousSummary)
342
+
343
+ const finalSummary = yield* iterateEffect<{ summary: string; index: number }, CompactionError, never>(
344
+ { summary: initialSummary, index: 0 },
345
+ {
346
+ while: (state) => state.index < chunks.length,
347
+ body: (state) =>
348
+ Effect.gen(function* () {
349
+ const chunk = chunks[state.index]
350
+ const transcript = toCompactionTranscript(chunk)
351
+ const output = yield* Effect.tryPromise({
352
+ try: () => options.runCompacter({ previousSummary: state.summary, chunk, transcript }),
353
+ catch: (error: unknown) => new CompactionError({ message: String(error), cause: error }),
354
+ }).pipe(Effect.retry(COMPACTION_RUNNER_RETRY_OPTIONS))
355
+ return { summary: normalizeSummary(output.summary), index: state.index + 1 }
356
+ }),
357
+ },
358
+ )
359
+
360
+ return { summary: finalSummary.summary }
361
+ })
344
362
 
345
363
  const rollupSummaryIfOversizedEffect = (summary: string) =>
346
364
  Effect.gen(function* () {
@@ -356,81 +374,104 @@ export function createContextCompactionRuntime(
356
374
  return normalizeSummary(output.summary)
357
375
  })
358
376
 
377
+ type CompactionLoopState = {
378
+ summaryText: string
379
+ remainingMessages: ChatMessage[]
380
+ compactedMessages: ChatMessage[]
381
+ lastCompactedMessageId: string | undefined
382
+ estimatedTokens: number
383
+ done: boolean
384
+ }
385
+
359
386
  const compactHistoryEffect = (params: CompactHistoryParams) =>
360
387
  Effect.gen(function* () {
361
- let summaryText = normalizeSummary(params.summaryText)
362
- let remainingMessages = [...params.liveMessages]
363
- let compactedMessages: ChatMessage[] = []
364
- let lastCompactedMessageId: string | undefined
365
- const summaryPayload = buildSyntheticSummaryPayload(summaryText)
366
- const initialPayload = stringifyUnknown([...(summaryPayload ? [summaryPayload] : []), ...remainingMessages]) ?? ''
388
+ const initialSummaryText = normalizeSummary(params.summaryText)
389
+ const initialRemaining = [...params.liveMessages]
390
+ const summaryPayload = buildSyntheticSummaryPayload(initialSummaryText)
391
+ const initialPayload = stringifyUnknown([...(summaryPayload ? [summaryPayload] : []), ...initialRemaining]) ?? ''
367
392
  const inputChars = initialPayload.length
368
393
 
369
- const buildEarlyExitResult = (estimatedTokens: number): CompactHistoryResult => {
370
- const exitSummaryPayload = buildSyntheticSummaryPayload(summaryText)
394
+ const buildExitResult = (state: CompactionLoopState): CompactHistoryResult => {
395
+ const exitSummaryPayload = buildSyntheticSummaryPayload(state.summaryText)
371
396
  const outputPayload =
372
- stringifyUnknown([...(exitSummaryPayload ? [exitSummaryPayload] : []), ...remainingMessages]) ?? ''
397
+ stringifyUnknown([...(exitSummaryPayload ? [exitSummaryPayload] : []), ...state.remainingMessages]) ?? ''
373
398
  return {
374
- compacted: compactedMessages.length > 0,
375
- summaryText,
376
- ...(lastCompactedMessageId ? { lastCompactedMessageId } : {}),
377
- compactedMessages,
378
- compactedMessageCount: compactedMessages.length,
379
- remainingMessageCount: remainingMessages.length,
380
- estimatedTokens,
399
+ compacted: state.compactedMessages.length > 0,
400
+ summaryText: state.summaryText,
401
+ ...(state.lastCompactedMessageId ? { lastCompactedMessageId: state.lastCompactedMessageId } : {}),
402
+ compactedMessages: state.compactedMessages,
403
+ compactedMessageCount: state.compactedMessages.length,
404
+ remainingMessageCount: state.remainingMessages.length,
405
+ estimatedTokens: state.estimatedTokens,
381
406
  inputChars,
382
407
  outputChars: outputPayload.length,
383
408
  }
384
409
  }
385
410
 
386
- for (;;) {
387
- const assessment = shouldCompactHistory({
388
- summaryText,
389
- liveMessages: remainingMessages,
390
- contextSize: params.contextSize,
391
- })
392
-
393
- if (!assessment.shouldCompact) {
394
- return buildEarlyExitResult(assessment.estimatedTokens)
395
- }
396
-
397
- const boundary = Math.max(0, remainingMessages.length - params.tailMessageCount)
398
- if (boundary <= 0) {
399
- return buildEarlyExitResult(assessment.estimatedTokens)
400
- }
401
-
402
- const candidatePrefix = remainingMessages.slice(0, boundary)
403
- const messagesToCompact = candidatePrefix.filter((message) => !readIsCompacted(message))
404
- const contextMessages = messagesToCompact
405
- .map(toContextMessageFromChatMessage)
406
- .filter((message) => compactWhitespace(message.text).length > 0)
407
- const sourceText = toCompactionTranscript(contextMessages)
408
-
409
- if (!compactWhitespace(sourceText)) {
410
- return buildEarlyExitResult(assessment.estimatedTokens)
411
- }
412
-
413
- let nextSummary = normalizeSummary(
414
- (yield* compactContextMessagesEffect({ previousSummary: summaryText, newMessages: contextMessages })).summary,
415
- )
416
- nextSummary = yield* rollupSummaryIfOversizedEffect(nextSummary)
417
-
418
- if (nextSummary.length >= sourceText.length) {
419
- return yield* new CompactionError({ message: 'Compaction summary is not shorter than compacted source' })
420
- }
411
+ const initialState: CompactionLoopState = {
412
+ summaryText: initialSummaryText,
413
+ remainingMessages: initialRemaining,
414
+ compactedMessages: [],
415
+ lastCompactedMessageId: undefined,
416
+ estimatedTokens: 0,
417
+ done: false,
418
+ }
421
419
 
422
- summaryText = nextSummary
423
- compactedMessages = [
424
- ...compactedMessages,
425
- ...candidatePrefix.map((message) => markMessageCompacted(message, now)),
426
- ]
427
- lastCompactedMessageId = candidatePrefix.at(-1)?.id ?? lastCompactedMessageId
428
- remainingMessages = remainingMessages.slice(boundary)
420
+ const finalState = yield* iterateEffect<CompactionLoopState, CompactionError, never>(initialState, {
421
+ while: (state) => !state.done,
422
+ body: (state) =>
423
+ Effect.gen(function* () {
424
+ const assessment = shouldCompactHistory({
425
+ summaryText: state.summaryText,
426
+ liveMessages: state.remainingMessages,
427
+ contextSize: params.contextSize,
428
+ })
429
+
430
+ if (!assessment.shouldCompact) {
431
+ return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
432
+ }
433
+
434
+ const boundary = Math.max(0, state.remainingMessages.length - params.tailMessageCount)
435
+ if (boundary <= 0) {
436
+ return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
437
+ }
438
+
439
+ const candidatePrefix = state.remainingMessages.slice(0, boundary)
440
+ const messagesToCompact = candidatePrefix.filter((message) => !readIsCompacted(message))
441
+ const contextMessages = messagesToCompact
442
+ .map(toContextMessageFromChatMessage)
443
+ .filter((message) => compactWhitespace(message.text).length > 0)
444
+ const sourceText = toCompactionTranscript(contextMessages)
445
+
446
+ if (!compactWhitespace(sourceText)) {
447
+ return { ...state, estimatedTokens: assessment.estimatedTokens, done: true }
448
+ }
449
+
450
+ const compacted = yield* compactContextMessagesEffect({
451
+ previousSummary: state.summaryText,
452
+ newMessages: contextMessages,
453
+ })
454
+ const rolledSummary = yield* rollupSummaryIfOversizedEffect(normalizeSummary(compacted.summary))
455
+
456
+ if (rolledSummary.length >= sourceText.length) {
457
+ return yield* new CompactionError({ message: 'Compaction summary is not shorter than compacted source' })
458
+ }
459
+
460
+ return {
461
+ summaryText: rolledSummary,
462
+ remainingMessages: state.remainingMessages.slice(boundary),
463
+ compactedMessages: [
464
+ ...state.compactedMessages,
465
+ ...candidatePrefix.map((message) => markMessageCompacted(message, now)),
466
+ ],
467
+ lastCompactedMessageId: candidatePrefix.at(-1)?.id ?? state.lastCompactedMessageId,
468
+ estimatedTokens: assessment.estimatedTokens,
469
+ done: false,
470
+ }
471
+ }),
472
+ })
429
473
 
430
- if (remainingMessages.length <= params.tailMessageCount) {
431
- continue
432
- }
433
- }
474
+ return buildExitResult(finalState)
434
475
  })
435
476
 
436
477
  return {
@@ -442,7 +483,10 @@ export function createContextCompactionRuntime(
442
483
  }
443
484
  }
444
485
 
445
- export function parseCompactionOutput(value: unknown): CompactionOutput {
446
- const parsed = ContextCompactionOutputSchema.parse(value)
447
- return { summary: parsed.summary }
486
+ export function parseCompactionOutput(value: unknown): Effect.Effect<CompactionOutput, CompactionParseError> {
487
+ const parsed = ContextCompactionOutputSchema.safeParse(value)
488
+ if (!parsed.success) {
489
+ return Effect.fail(new CompactionParseError({ message: 'Failed to parse compaction output', cause: parsed.error }))
490
+ }
491
+ return Effect.succeed({ summary: parsed.data.summary })
448
492
  }
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Builds the domain-service Layer tree for `createLotaRuntime`.
3
+ *
4
+ * The services form a 9-tier dependency graph on top of the infrastructure
5
+ * layer (config, logging, database, redis, agents, threads, extensions).
6
+ * Each tier is provided with the accumulated context of earlier tiers so
7
+ * every service resolves cleanly when the ManagedRuntime eagerly loads them.
8
+ */
9
+
10
+ import type { Layer as LayerType } from 'effect'
11
+ import { Layer } from 'effect'
12
+
13
+ import { AiGatewayLive } from '../ai-gateway/ai-gateway'
14
+ import { EmbeddingCacheLive } from '../ai/embedding-cache'
15
+ import type { buildInfrastructureLayer } from '../effect/layers'
16
+ import { SharedThreadStreamSubscriberLive } from '../redis/stream-context'
17
+ import { AgentActivityServiceLive } from '../services/agent-activity.service'
18
+ import { AgentExecutorServiceLive } from '../services/agent-executor.service'
19
+ import { ArtifactServiceLive } from '../services/artifact.service'
20
+ import { AttachmentServiceLive } from '../services/attachment.service'
21
+ import { AutonomousJobServiceLive } from '../services/autonomous-job.service'
22
+ import { BackgroundWorkServiceLive } from '../services/background-work.service'
23
+ import { ChatRunRegistryLive } from '../services/chat-run-registry.service'
24
+ import { ContextCompactionServiceLive } from '../services/context-compaction.service'
25
+ import { DocumentChunkServiceLive } from '../services/document-chunk.service'
26
+ import { ExecutionPlanServiceLive } from '../services/execution-plan/execution-plan.service'
27
+ import { FeedbackLoopServiceLive } from '../services/feedback-loop.service'
28
+ import { GlobalOrchestratorServiceLive } from '../services/global-orchestrator.service'
29
+ import { InstitutionalMemoryServiceLive } from '../services/institutional-memory.service'
30
+ import { LearnedSkillServiceLive } from '../services/learned-skill.service'
31
+ import { MemoryServiceLive } from '../services/memory/memory.service'
32
+ import { RerankServiceLive } from '../services/memory/rerank.service'
33
+ import { MonitoringWindowServiceLive } from '../services/monitoring-window.service'
34
+ import { MutatingApprovalServiceLive } from '../services/mutating-approval.service'
35
+ import { NodeWorkspaceServiceLive } from '../services/node-workspace.service'
36
+ import { NotificationServiceLive } from '../services/notification.service'
37
+ import { OrganizationMemberServiceLive } from '../services/organization-member.service'
38
+ import { OrganizationServiceLive } from '../services/organization.service'
39
+ import { OwnershipDispatcherServiceLive } from '../services/ownership-dispatcher.service'
40
+ import { PlanAgentHeartbeatServiceLive } from '../services/plan/plan-agent-heartbeat.service'
41
+ import { PlanAgentQueryServiceLive } from '../services/plan/plan-agent-query.service'
42
+ import { PlanApprovalServiceLive } from '../services/plan/plan-approval.service'
43
+ import { PlanArtifactServiceLive } from '../services/plan/plan-artifact.service'
44
+ import { PlanBuilderServiceLive } from '../services/plan/plan-builder.service'
45
+ import { PlanCheckpointServiceLive } from '../services/plan/plan-checkpoint.service'
46
+ import { PlanCompilerServiceLive } from '../services/plan/plan-compiler.service'
47
+ import { PlanCoordinationServiceLive } from '../services/plan/plan-coordination.service'
48
+ import { PlanCycleServiceLive } from '../services/plan/plan-cycle.service'
49
+ import { PlanDeadlineServiceLive } from '../services/plan/plan-deadline.service'
50
+ import { PlanEventDeliveryServiceLive } from '../services/plan/plan-event-delivery.service'
51
+ import { PlanExecutorServiceLive } from '../services/plan/plan-executor.service'
52
+ import { PlanRunServiceLive } from '../services/plan/plan-run.service'
53
+ import { PlanSchedulerServiceLive } from '../services/plan/plan-scheduler.service'
54
+ import { PlanTemplateServiceLive } from '../services/plan/plan-template.service'
55
+ import { PlanValidatorServiceLive } from '../services/plan/plan-validator.service'
56
+ import { PlanWorkspaceServiceLive } from '../services/plan/plan-workspace.service'
57
+ import { PluginExecutorServiceLive } from '../services/plugin-executor.service'
58
+ import { QualityMetricsServiceLive } from '../services/quality-metrics.service'
59
+ import { QueueJobServiceLive } from '../services/queue-job.service'
60
+ import { RecentActivityTitleServiceLive } from '../services/recent-activity-title.service'
61
+ import { RecentActivityServiceLive } from '../services/recent-activity.service'
62
+ import { SkillResolverServiceLive } from '../services/skill-resolver.service'
63
+ import { SocialChatHistoryServiceLive } from '../services/social-chat-history.service'
64
+ import { SystemExecutorServiceLive } from '../services/system-executor.service'
65
+ import { ThreadMessageServiceLive } from '../services/thread/thread-message.service'
66
+ import { ThreadTitleServiceLive } from '../services/thread/thread-title.service'
67
+ import { ThreadTurnServiceLive } from '../services/thread/thread-turn'
68
+ import { ThreadTurnPreparationServiceLive } from '../services/thread/thread-turn-preparation.service'
69
+ import { ThreadServiceLive } from '../services/thread/thread.service'
70
+ import { UserServiceLive } from '../services/user.service'
71
+ import { WriteIntentValidatorServiceLive } from '../services/write-intent-validator.service'
72
+ import { AttachmentStorageServiceLive } from '../storage/attachment-storage.service'
73
+ import { GeneratedDocumentStorageServiceLive } from '../storage/generated-document-storage.service'
74
+ import { FirecrawlLive } from '../tools/firecrawl-client'
75
+ import { CompactionCoordinationLive } from './chat-run-orchestration'
76
+ import { HelperModelLive } from './helper-model'
77
+
78
+ function provide<A, E, R extends RCtx, RCtx, E2>(
79
+ layer: LayerType.Layer<A, E, R>,
80
+ ctx: LayerType.Layer<RCtx, E2, never>,
81
+ ): LayerType.Layer<A, E | E2, never> {
82
+ return Layer.provideMerge(ctx)(layer)
83
+ }
84
+
85
+ type InfrastructureLayer = ReturnType<typeof buildInfrastructureLayer>
86
+
87
+ /**
88
+ * Compose the domain service layer tree on top of the supplied infrastructure
89
+ * layer. The returned layer has no remaining requirements and can be fed
90
+ * straight into `ManagedRuntime.make`.
91
+ */
92
+ export function buildDomainServiceLayer(infrastructureLayer: InfrastructureLayer) {
93
+ const tier0 = provide(
94
+ Layer.mergeAll(
95
+ BackgroundWorkServiceLive,
96
+ ChatRunRegistryLive,
97
+ CompactionCoordinationLive,
98
+ DocumentChunkServiceLive,
99
+ NodeWorkspaceServiceLive,
100
+ NotificationServiceLive,
101
+ PlanArtifactServiceLive,
102
+ PlanBuilderServiceLive,
103
+ WriteIntentValidatorServiceLive,
104
+ ),
105
+ infrastructureLayer,
106
+ )
107
+ const ctx0 = Layer.mergeAll(
108
+ infrastructureLayer,
109
+ provide(Layer.mergeAll(AiGatewayLive, EmbeddingCacheLive, FirecrawlLive, HelperModelLive), infrastructureLayer),
110
+ tier0,
111
+ )
112
+
113
+ const tier1 = provide(
114
+ Layer.mergeAll(
115
+ SharedThreadStreamSubscriberLive,
116
+ AgentExecutorServiceLive,
117
+ AttachmentStorageServiceLive,
118
+ GeneratedDocumentStorageServiceLive,
119
+ LearnedSkillServiceLive,
120
+ OrganizationServiceLive,
121
+ OrganizationMemberServiceLive,
122
+ PlanApprovalServiceLive,
123
+ PlanRunServiceLive,
124
+ PlanSchedulerServiceLive,
125
+ PlanWorkspaceServiceLive,
126
+ PluginExecutorServiceLive,
127
+ QualityMetricsServiceLive,
128
+ QueueJobServiceLive,
129
+ RecentActivityServiceLive,
130
+ RerankServiceLive,
131
+ SocialChatHistoryServiceLive,
132
+ SystemExecutorServiceLive,
133
+ ThreadMessageServiceLive,
134
+ UserServiceLive,
135
+ ),
136
+ ctx0,
137
+ )
138
+ const ctx1 = Layer.mergeAll(ctx0, tier1)
139
+
140
+ const tier2 = provide(
141
+ Layer.mergeAll(
142
+ ArtifactServiceLive,
143
+ AttachmentServiceLive,
144
+ ContextCompactionServiceLive,
145
+ FeedbackLoopServiceLive,
146
+ InstitutionalMemoryServiceLive,
147
+ MemoryServiceLive,
148
+ MonitoringWindowServiceLive,
149
+ MutatingApprovalServiceLive,
150
+ PlanAgentQueryServiceLive,
151
+ PlanCheckpointServiceLive,
152
+ PlanCoordinationServiceLive,
153
+ PlanEventDeliveryServiceLive,
154
+ SkillResolverServiceLive,
155
+ RecentActivityTitleServiceLive,
156
+ ),
157
+ ctx1,
158
+ )
159
+ const ctx2 = Layer.mergeAll(ctx1, tier2)
160
+
161
+ const tier3 = provide(Layer.mergeAll(PlanValidatorServiceLive, ThreadServiceLive), ctx2)
162
+ const ctx3 = Layer.mergeAll(ctx2, tier3)
163
+
164
+ const tier4 = provide(Layer.mergeAll(PlanCompilerServiceLive, ThreadTitleServiceLive), ctx3)
165
+ const ctx4 = Layer.mergeAll(ctx3, tier4)
166
+
167
+ const tier5 = provide(PlanExecutorServiceLive, ctx4)
168
+ const ctx5 = Layer.mergeAll(ctx4, tier5)
169
+
170
+ const tier6 = provide(
171
+ Layer.mergeAll(OwnershipDispatcherServiceLive, PlanAgentHeartbeatServiceLive, PlanDeadlineServiceLive),
172
+ ctx5,
173
+ )
174
+ const ctx6 = Layer.mergeAll(ctx5, tier6)
175
+
176
+ const tier7 = provide(Layer.mergeAll(ExecutionPlanServiceLive, GlobalOrchestratorServiceLive), ctx6)
177
+ const ctx7 = Layer.mergeAll(ctx6, tier7)
178
+
179
+ const tier8 = provide(
180
+ Layer.mergeAll(
181
+ PlanTemplateServiceLive,
182
+ AutonomousJobServiceLive,
183
+ AgentActivityServiceLive,
184
+ ThreadTurnPreparationServiceLive,
185
+ ),
186
+ ctx7,
187
+ )
188
+ const ctx8 = Layer.mergeAll(ctx7, tier8)
189
+
190
+ const tier9 = provide(Layer.mergeAll(PlanCycleServiceLive, ThreadTurnServiceLive), ctx8)
191
+ return Layer.mergeAll(ctx8, tier9)
192
+ }
@@ -1,19 +1,27 @@
1
1
  import type { GraphDesignRequest, GraphDesignResponse } from '@lota-sdk/shared'
2
- import { Effect } from 'effect'
3
2
 
4
- import { getOptionalCurrentRuntime } from '../effect/runtime-ref'
3
+ import { resolveOptionalLotaService } from '../effect/runtime'
5
4
  import { RuntimeConfigServiceTag } from '../effect/services'
6
5
 
7
6
  export interface GraphDesigner {
8
7
  designGraph(request: GraphDesignRequest): Promise<GraphDesignResponse>
9
8
  }
10
9
 
10
+ let currentGraphDesigner: GraphDesigner | null = null
11
+
12
+ export function configureGraphDesigner(graphDesigner: GraphDesigner | null | undefined): void {
13
+ currentGraphDesigner = graphDesigner ?? null
14
+ }
15
+
16
+ export function clearGraphDesigner(): void {
17
+ currentGraphDesigner = null
18
+ }
19
+
11
20
  export function getGraphDesigner(): GraphDesigner | null {
12
- const runtime = getOptionalCurrentRuntime()
13
- if (!runtime) {
14
- return null
21
+ if (currentGraphDesigner) {
22
+ return currentGraphDesigner
15
23
  }
16
24
 
17
- const runtimeConfig = runtime.runSync(Effect.service(RuntimeConfigServiceTag))
18
- return runtimeConfig.graphDesigner ?? null
25
+ const runtimeConfig = resolveOptionalLotaService(RuntimeConfigServiceTag)
26
+ return runtimeConfig?.graphDesigner ?? null
19
27
  }
@@ -253,7 +253,7 @@ export function createHelperModelRuntime() {
253
253
  }
254
254
 
255
255
  function generateHelperText(params: GenerateHelperTextParams): Promise<string> {
256
- return Effect.runPromise(generateHelperTextEffect(params))
256
+ return Effect.runPromise(generateHelperTextEffect(params).pipe(Effect.withSpan('HelperModel.generateHelperText')))
257
257
  }
258
258
 
259
259
  function generateHelperStructuredEffect<T>(
@@ -300,7 +300,9 @@ export function createHelperModelRuntime() {
300
300
  }
301
301
 
302
302
  function generateHelperStructured<T>(params: GenerateHelperStructuredParams<T>): Promise<T> {
303
- return Effect.runPromise(generateHelperStructuredEffect(params))
303
+ return Effect.runPromise(
304
+ generateHelperStructuredEffect(params).pipe(Effect.withSpan('HelperModel.generateHelperStructured')),
305
+ )
304
306
  }
305
307
 
306
308
  return { generateHelperTextEffect, generateHelperText, generateHelperStructuredEffect, generateHelperStructured }
@@ -308,6 +310,8 @@ export function createHelperModelRuntime() {
308
310
 
309
311
  export type HelperModelRuntime = ReturnType<typeof createHelperModelRuntime>
310
312
 
311
- export class HelperModelTag extends Context.Service<HelperModelTag, HelperModelRuntime>()('HelperModel') {}
313
+ export class HelperModelTag extends Context.Service<HelperModelTag, HelperModelRuntime>()(
314
+ '@lota-sdk/core/HelperModel',
315
+ ) {}
312
316
 
313
- export const HelperModelLive = Layer.succeed(HelperModelTag, createHelperModelRuntime())
317
+ export const HelperModelLive = Layer.sync(HelperModelTag, () => createHelperModelRuntime())
@@ -1,7 +1,6 @@
1
1
  export * from './approval-continuation'
2
2
  export * from './agent-runtime-policy'
3
3
  export * from './agent-stream-helpers'
4
- export * from './agent-types'
5
4
  export * from './chat-request-routing'
6
5
  export * from './chat-run-registry'
7
6
  export * from './context-compaction/context-compaction'
@@ -1,10 +1,14 @@
1
- import type { Cause } from 'effect'
2
- import { DateTime, Effect } from 'effect'
1
+ import { Effect, Schema } from 'effect'
3
2
  import { z } from 'zod'
4
3
 
5
- import { effectTryPromise } from '../../effect/helpers'
4
+ import { nowDate } from '../../utils/date-time'
6
5
  import { compactWhitespace } from '../../utils/string'
7
6
 
7
+ export class MemoryBlockCompactError extends Schema.TaggedErrorClass<MemoryBlockCompactError>()(
8
+ 'MemoryBlockCompactError',
9
+ { message: Schema.String, cause: Schema.Defect },
10
+ ) {}
11
+
8
12
  function escapeRegex(value: string): string {
9
13
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
10
14
  }
@@ -61,7 +65,7 @@ export interface CompactMemoryBlockEntriesParams {
61
65
  compact: (params: {
62
66
  previousSummary: string
63
67
  newEntriesText: string
64
- }) => PromiseLike<string> | Effect.Effect<string, unknown>
68
+ }) => PromiseLike<string> | Effect.Effect<string, MemoryBlockCompactError>
65
69
  }
66
70
 
67
71
  export interface CompactMemoryBlockEntriesResult {
@@ -106,7 +110,7 @@ function toMemoryBlockEntriesSource(entries: Array<{ role: string; content: stri
106
110
 
107
111
  export function compactMemoryBlockEntries(
108
112
  params: CompactMemoryBlockEntriesParams,
109
- ): Effect.Effect<CompactMemoryBlockEntriesResult, Cause.UnknownError> {
113
+ ): Effect.Effect<CompactMemoryBlockEntriesResult, MemoryBlockCompactError> {
110
114
  return Effect.gen(function* () {
111
115
  let summary = typeof params.previousSummary === 'string' ? params.previousSummary.trim() : ''
112
116
  let entries = [...params.entries]
@@ -114,9 +118,15 @@ export function compactMemoryBlockEntries(
114
118
 
115
119
  while (entries.length >= params.triggerEntries) {
116
120
  const chunk = entries.slice(0, params.chunkEntries)
117
- const nextSummary = (yield* effectTryPromise(() =>
118
- params.compact({ previousSummary: summary, newEntriesText: toMemoryBlockEntriesSource(chunk) }),
119
- )).trim()
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
+ })
129
+ const nextSummary = raw.trim()
120
130
 
121
131
  if (!nextSummary) {
122
132
  break
@@ -162,7 +172,7 @@ export interface CreateMemoryBlockRuntimeOptions {
162
172
  export function createMemoryBlockRuntime(options: CreateMemoryBlockRuntimeOptions = {}): MemoryBlockRuntime {
163
173
  const labelPrefixRegex = createLabelPrefixRegex(options.labelRoles ?? [])
164
174
  const memoryBlockMaxChars = options.maxChars ?? 400
165
- const now = options.now ?? (() => Effect.runSync(DateTime.nowAsDate))
175
+ const now = options.now ?? nowDate
166
176
 
167
177
  const normalizeMemoryBlockEntry = (entry: string): string => {
168
178
  const normalizedLines = entry