@lota-sdk/core 0.1.14 → 0.1.16

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 (174) hide show
  1. package/infrastructure/schema/00_identity.surql +0 -2
  2. package/infrastructure/schema/01_memory.surql +1 -1
  3. package/infrastructure/schema/02_execution_plan.surql +62 -1
  4. package/infrastructure/schema/03_learned_skill.surql +1 -1
  5. package/infrastructure/schema/06_playbook.surql +25 -0
  6. package/infrastructure/schema/07_institutional_memory.surql +13 -0
  7. package/infrastructure/schema/08_quality_metrics.surql +17 -0
  8. package/package.json +9 -8
  9. package/src/ai/definitions.ts +80 -2
  10. package/src/ai/embedding-cache.ts +7 -6
  11. package/src/ai/index.ts +0 -1
  12. package/src/bifrost/bifrost.ts +14 -14
  13. package/src/config/agent-defaults.ts +32 -22
  14. package/src/config/agent-types.ts +11 -0
  15. package/src/config/constants.ts +2 -14
  16. package/src/config/debug-logger.ts +5 -1
  17. package/src/config/index.ts +3 -0
  18. package/src/config/logger.ts +7 -9
  19. package/src/config/model-constants.ts +16 -34
  20. package/src/config/search.ts +1 -15
  21. package/src/create-runtime.ts +453 -0
  22. package/src/db/cursor-pagination.ts +3 -6
  23. package/src/db/index.ts +2 -0
  24. package/src/db/memory-store.rows.ts +7 -7
  25. package/src/db/memory-store.ts +24 -24
  26. package/src/db/memory.ts +18 -16
  27. package/src/db/schema-fingerprint.ts +1 -0
  28. package/src/db/service.ts +193 -122
  29. package/src/db/startup.ts +9 -13
  30. package/src/db/surreal-mutation.ts +43 -0
  31. package/src/db/tables.ts +7 -0
  32. package/src/db/workstream-message-row.ts +15 -0
  33. package/src/embeddings/provider.ts +1 -1
  34. package/src/index.ts +1 -1
  35. package/src/queues/context-compaction.queue.ts +17 -52
  36. package/src/queues/delayed-node-promotion.queue.ts +41 -0
  37. package/src/queues/document-processor.queue.ts +7 -7
  38. package/src/queues/index.ts +3 -0
  39. package/src/queues/memory-consolidation.queue.ts +18 -54
  40. package/src/queues/plan-scheduler.queue.ts +97 -0
  41. package/src/queues/post-chat-memory.queue.ts +15 -60
  42. package/src/queues/queue-factory.ts +100 -0
  43. package/src/queues/recent-activity-title-refinement.queue.ts +15 -54
  44. package/src/queues/regular-chat-memory-digest.queue.ts +16 -55
  45. package/src/queues/skill-extraction.queue.ts +15 -50
  46. package/src/queues/workstream-title-generation.queue.ts +15 -51
  47. package/src/redis/connection.ts +12 -3
  48. package/src/redis/index.ts +2 -1
  49. package/src/redis/org-memory-lock.ts +1 -1
  50. package/src/redis/redis-lease-lock.ts +41 -8
  51. package/src/redis/stream-context.ts +11 -0
  52. package/src/runtime/agent-runtime-policy.ts +106 -21
  53. package/src/runtime/agent-stream-helpers.ts +2 -1
  54. package/src/runtime/approval-continuation.ts +12 -6
  55. package/src/runtime/context-compaction-constants.ts +1 -1
  56. package/src/runtime/context-compaction-runtime.ts +7 -5
  57. package/src/runtime/context-compaction.ts +40 -97
  58. package/src/runtime/execution-plan.ts +23 -19
  59. package/src/runtime/graph-designer.ts +15 -0
  60. package/src/runtime/helper-model.ts +10 -196
  61. package/src/runtime/index.ts +14 -1
  62. package/src/runtime/llm-content.ts +1 -1
  63. package/src/runtime/memory-block.ts +11 -12
  64. package/src/runtime/memory-pipeline.ts +26 -10
  65. package/src/runtime/plugin-resolution.ts +35 -0
  66. package/src/runtime/plugin-types.ts +73 -1
  67. package/src/runtime/retrieval-adapters.ts +1 -1
  68. package/src/runtime/runtime-config.ts +25 -12
  69. package/src/runtime/runtime-extensions.ts +91 -15
  70. package/src/runtime/runtime-worker-registry.ts +6 -0
  71. package/src/runtime/team-consultation-orchestrator.ts +45 -28
  72. package/src/runtime/team-consultation-prompts.ts +11 -2
  73. package/src/runtime/title-helpers.ts +11 -4
  74. package/src/runtime/workstream-chat-helpers.ts +6 -7
  75. package/src/runtime/workstream-routing-policy.ts +0 -30
  76. package/src/runtime/workstream-state.ts +17 -7
  77. package/src/services/adaptive-playbook.service.ts +152 -0
  78. package/src/services/agent-executor.service.ts +293 -0
  79. package/src/services/artifact-provenance.service.ts +172 -0
  80. package/src/services/attachment.service.ts +7 -12
  81. package/src/services/context-compaction.service.ts +75 -58
  82. package/src/services/context-enrichment.service.ts +33 -0
  83. package/src/services/coordination-registry.service.ts +117 -0
  84. package/src/services/document-chunk.service.ts +38 -33
  85. package/src/services/domain-agent-executor.service.ts +71 -0
  86. package/src/services/execution-plan.service.ts +271 -50
  87. package/src/services/feedback-loop.service.ts +96 -0
  88. package/src/services/global-orchestrator.service.ts +148 -0
  89. package/src/services/index.ts +26 -0
  90. package/src/services/institutional-memory.service.ts +145 -0
  91. package/src/services/learned-skill.service.ts +30 -15
  92. package/src/services/memory-assessment.service.ts +3 -2
  93. package/src/services/{memory.utils.ts → memory-utils.ts} +4 -13
  94. package/src/services/memory.service.ts +55 -69
  95. package/src/services/monitoring-window.service.ts +86 -0
  96. package/src/services/mutating-approval.service.ts +1 -1
  97. package/src/services/node-workspace.service.ts +155 -0
  98. package/src/services/notification.service.ts +39 -0
  99. package/src/services/organization-member.service.ts +12 -5
  100. package/src/services/organization.service.ts +5 -5
  101. package/src/services/ownership-dispatcher.service.ts +403 -0
  102. package/src/services/plan-approval.service.ts +1 -1
  103. package/src/services/plan-artifact.service.ts +1 -0
  104. package/src/services/plan-builder.service.ts +1 -0
  105. package/src/services/plan-checkpoint.service.ts +30 -2
  106. package/src/services/plan-compiler.service.ts +5 -0
  107. package/src/services/plan-coordination.service.ts +152 -0
  108. package/src/services/plan-cycle.service.ts +284 -0
  109. package/src/services/plan-deadline.service.ts +287 -0
  110. package/src/services/plan-executor.service.ts +386 -58
  111. package/src/services/plan-helpers.ts +15 -0
  112. package/src/services/plan-run.service.ts +41 -7
  113. package/src/services/plan-scheduler.service.ts +240 -0
  114. package/src/services/plan-template.service.ts +117 -0
  115. package/src/services/plan-validator.service.ts +87 -20
  116. package/src/services/plan-workspace.service.ts +83 -0
  117. package/src/services/playbook-registry.service.ts +67 -0
  118. package/src/services/plugin-executor.service.ts +103 -0
  119. package/src/services/quality-metrics.service.ts +132 -0
  120. package/src/services/recent-activity-title.service.ts +3 -10
  121. package/src/services/recent-activity.service.ts +33 -43
  122. package/src/services/skill-resolver.service.ts +19 -0
  123. package/src/services/system-executor.service.ts +105 -0
  124. package/src/services/workstream-message.service.ts +29 -41
  125. package/src/services/workstream-plan-registry.service.ts +22 -0
  126. package/src/services/workstream-title.service.ts +3 -9
  127. package/src/services/{workstream-turn-preparation.ts → workstream-turn-preparation.service.ts} +428 -373
  128. package/src/services/workstream-turn.ts +2 -2
  129. package/src/services/workstream.service.ts +55 -65
  130. package/src/services/workstream.types.ts +10 -19
  131. package/src/services/write-intent-validator.service.ts +81 -0
  132. package/src/storage/attachment-parser.ts +1 -1
  133. package/src/storage/attachment-storage.service.ts +4 -4
  134. package/src/storage/{attachments.utils.ts → attachment-utils.ts} +2 -5
  135. package/src/storage/generated-document-storage.service.ts +3 -2
  136. package/src/storage/index.ts +2 -2
  137. package/src/system-agents/{context-compacter.agent.ts → context-compaction.agent.ts} +4 -4
  138. package/src/system-agents/delegated-agent-factory.ts +5 -2
  139. package/src/system-agents/index.ts +8 -0
  140. package/src/system-agents/memory-reranker.agent.ts +1 -1
  141. package/src/system-agents/memory.agent.ts +1 -1
  142. package/src/system-agents/recent-activity-title-refiner.agent.ts +1 -1
  143. package/src/tools/execution-plan.tool.ts +17 -19
  144. package/src/tools/fetch-webpage.tool.ts +20 -18
  145. package/src/tools/index.ts +2 -3
  146. package/src/tools/read-file-parts.tool.ts +1 -1
  147. package/src/tools/search-web.tool.ts +18 -15
  148. package/src/tools/{search-tools.ts → search.tool.ts} +1 -1
  149. package/src/tools/team-think.tool.ts +14 -8
  150. package/src/tools/{tool-contract.ts → tool-contracts.ts} +9 -2
  151. package/src/utils/async.ts +3 -2
  152. package/src/utils/date-time.ts +4 -32
  153. package/src/utils/env.ts +8 -0
  154. package/src/utils/errors.ts +47 -0
  155. package/src/utils/hono-error-handler.ts +1 -2
  156. package/src/utils/index.ts +19 -2
  157. package/src/utils/string.ts +128 -1
  158. package/src/workers/bootstrap.ts +2 -2
  159. package/src/workers/index.ts +1 -0
  160. package/src/workers/memory-consolidation.worker.ts +12 -12
  161. package/src/workers/regular-chat-memory-digest.helpers.ts +2 -7
  162. package/src/workers/regular-chat-memory-digest.runner.ts +11 -105
  163. package/src/workers/skill-extraction.runner.ts +8 -102
  164. package/src/workers/utils/file-section-chunker.ts +6 -3
  165. package/src/workers/utils/repomix-file-sections.ts +2 -2
  166. package/src/workers/utils/sandbox-error.ts +11 -2
  167. package/src/workers/utils/workstream-message-query.ts +97 -0
  168. package/src/workers/worker-utils.ts +6 -2
  169. package/src/runtime/retrieval-pipeline.ts +0 -3
  170. package/src/runtime.ts +0 -387
  171. package/src/tools/log-hello-world.tool.ts +0 -17
  172. package/src/utils/error.ts +0 -10
  173. /package/src/services/{context-compaction-runtime.ts → context-compaction-runtime.singleton.ts} +0 -0
  174. /package/src/storage/{attachments.types.ts → attachment-types.ts} +0 -0
@@ -1,7 +1,9 @@
1
1
  import type { LogLevel } from '@logtape/logtape'
2
2
  import { configure, getAnsiColorFormatter, getConsoleSink, getLogger as getLogTapeLogger } from '@logtape/logtape'
3
3
 
4
- export async function configureLotaLogger(logLevel: LogLevel): Promise<void> {
4
+ const LOG_CATEGORY = 'lota-sdk'
5
+
6
+ export async function configureLotaLogger(logLevel: LogLevel = 'info'): Promise<void> {
5
7
  const formatter = getAnsiColorFormatter({ level: 'FULL' })
6
8
 
7
9
  await configure({
@@ -10,7 +12,7 @@ export async function configureLotaLogger(logLevel: LogLevel): Promise<void> {
10
12
  loggers: [
11
13
  { category: ['logtape', 'meta'], lowestLevel: 'warning', sinks: ['console'] },
12
14
  { category: ['server'], lowestLevel: logLevel, sinks: ['console'] },
13
- { category: ['lota-sdk'], lowestLevel: logLevel, sinks: ['console'] },
15
+ { category: [LOG_CATEGORY], lowestLevel: logLevel, sinks: ['console'] },
14
16
  { category: ['hono'], lowestLevel: logLevel, sinks: ['console'] },
15
17
  ],
16
18
  })
@@ -20,10 +22,6 @@ export function getLogger(category: readonly string[]) {
20
22
  return getLogTapeLogger([...category])
21
23
  }
22
24
 
23
- export async function configureLogger(logLevel?: LogLevel): Promise<void> {
24
- await configureLotaLogger(logLevel ?? 'info')
25
- }
26
-
27
- export const serverLogger = getLogger(['lota-sdk'])
28
- export const chatLogger = getLogger(['lota-sdk', 'chat'])
29
- export const aiLogger = getLogger(['lota-sdk', 'ai'])
25
+ export const serverLogger = getLogger([LOG_CATEGORY])
26
+ export const chatLogger = getLogger([LOG_CATEGORY, 'chat'])
27
+ export const aiLogger = getLogger([LOG_CATEGORY, 'ai'])
@@ -1,34 +1,16 @@
1
- export const OPENAI_REASONING_MODEL_ID = 'openai/gpt-5.4' as const
2
-
3
- export const OPENROUTER_TEAM_AGENT_MODEL_ID = 'openrouter/google/gemini-3.1-pro-preview' as const
4
- export const OPENROUTER_STRUCTURED_HELPER_MODEL_ID = 'openrouter/google/gemini-3-flash-preview:exacto' as const
5
- export const OPENROUTER_DELEGATED_REASONING_MODEL_ID = 'openrouter/google/gemini-3-flash-preview:exacto' as const
6
- export const OPENROUTER_WEB_RESEARCH_MODEL_ID = 'openrouter/stepfun/step-3.5-flash' as const
7
- export const OPENROUTER_FAST_REASONING_MODEL_ID = 'openrouter/openai/gpt-oss-120b:nitro' as const
8
- export const OPENROUTER_STRUCTURED_REASONING_MODEL_ID = 'openrouter/openai/gpt-oss-120b:exacto' as const
9
-
10
- export const BIFROST_REASONING_SUMMARY_LEVEL = 'detailed' as const
11
-
12
- export const OPENAI_HIGH_REASONING_PROVIDER_OPTIONS = {
13
- openai: { forceReasoning: true, reasoningEffort: 'high', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
14
- } as const
15
-
16
- export const OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS = {
17
- openai: { forceReasoning: true, reasoningEffort: 'high', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
18
- } as const
19
-
20
- export const OPENROUTER_XHIGH_REASONING_PROVIDER_OPTIONS = {
21
- openai: { forceReasoning: true, reasoningEffort: 'xhigh', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
22
- } as const
23
-
24
- export const OPENROUTER_MEDIUM_REASONING_PROVIDER_OPTIONS = {
25
- openai: { forceReasoning: true, reasoningEffort: 'medium', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
26
- } as const
27
-
28
- export const OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS = {
29
- openai: { forceReasoning: true, reasoningEffort: 'low', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
30
- } as const
31
-
32
- export const OPENROUTER_MINIMAL_REASONING_PROVIDER_OPTIONS = {
33
- openai: { forceReasoning: true, reasoningEffort: 'minimal', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
34
- } as const
1
+ export {
2
+ BIFROST_REASONING_SUMMARY_LEVEL,
3
+ OPENAI_HIGH_REASONING_PROVIDER_OPTIONS,
4
+ OPENAI_REASONING_MODEL_ID,
5
+ OPENROUTER_DELEGATED_REASONING_MODEL_ID,
6
+ OPENROUTER_FAST_REASONING_MODEL_ID,
7
+ OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
8
+ OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS,
9
+ OPENROUTER_MEDIUM_REASONING_PROVIDER_OPTIONS,
10
+ OPENROUTER_MINIMAL_REASONING_PROVIDER_OPTIONS,
11
+ OPENROUTER_STRUCTURED_HELPER_MODEL_ID,
12
+ OPENROUTER_STRUCTURED_REASONING_MODEL_ID,
13
+ OPENROUTER_TEAM_AGENT_MODEL_ID,
14
+ OPENROUTER_WEB_RESEARCH_MODEL_ID,
15
+ OPENROUTER_XHIGH_REASONING_PROVIDER_OPTIONS,
16
+ } from '@lota-sdk/shared'
@@ -1,17 +1,3 @@
1
- /**
2
- * Search-related constants for vector search and hybrid search
3
- */
1
+ export { VECTOR_SEARCH_OVERFETCH_MULTIPLIER } from '@lota-sdk/shared'
4
2
 
5
- /**
6
- * Multiplier for vector search fetch limit.
7
- * We fetch more candidates than needed (limit * multiplier) to allow for:
8
- * - RRF (Reciprocal Rank Fusion) re-ranking
9
- * - Hybrid search combining vector + full-text results
10
- * - Filtering out low-quality matches before returning final results
11
- */
12
- export const VECTOR_SEARCH_OVERFETCH_MULTIPLIER = 2
13
-
14
- /**
15
- * Default limit for memory search queries
16
- */
17
3
  export const DEFAULT_MEMORY_SEARCH_LIMIT = 10
@@ -0,0 +1,453 @@
1
+ import type { ChatMessage } from '@lota-sdk/shared'
2
+
3
+ import { configureEmbeddingCache } from './ai/embedding-cache'
4
+ import { configureAgentFactory, configureAgents } from './config/agent-defaults'
5
+ import { configureBackgroundProcessing } from './config/background-processing'
6
+ import { configureLotaLogger } from './config/logger'
7
+ import { configureWorkstreams } from './config/workstream-defaults'
8
+ import { ensureRecordId } from './db/record-id'
9
+ import { computeSchemaFingerprint } from './db/schema-fingerprint'
10
+ import { LOTA_SDK_DATABASE_NAME } from './db/sdk-database'
11
+ import type { SurrealDBService } from './db/service'
12
+ import { SurrealDBService as SurrealDBServiceClass, setDatabaseService } from './db/service'
13
+ import { publishDatabaseBootstrap } from './db/startup'
14
+ import { TABLES } from './db/tables'
15
+ import type { RedisConnectionManager } from './redis/connection'
16
+ import { createRedisConnectionManager } from './redis/connection'
17
+ import { setRedisConnectionManager } from './redis/index'
18
+ import { closeSharedSubscriber } from './redis/stream-context'
19
+ import type { isApprovalContinuationRequest } from './runtime/approval-continuation'
20
+ import { routeWorkstreamChatMessages } from './runtime/chat-request-routing'
21
+ import { configureGraphDesigner } from './runtime/graph-designer'
22
+ import type { LotaPlugin, SystemNodeExecutor } from './runtime/plugin-types'
23
+ import { configureRuntimeConfig, LOTA_RUNTIME_ENV_KEYS, parseLotaRuntimeConfig } from './runtime/runtime-config'
24
+ import type { LotaRuntimeConfig, ResolvedLotaRuntimeConfig } from './runtime/runtime-config'
25
+ import { configureRuntimeExtensions } from './runtime/runtime-extensions'
26
+ import type { LotaRuntimeWorkers } from './runtime/runtime-worker-registry'
27
+ import { buildRuntimeWorkerRegistry } from './runtime/runtime-worker-registry'
28
+ import type { attachmentService } from './services/attachment.service'
29
+ import { attachmentService as attachmentServiceSingleton } from './services/attachment.service'
30
+ import { coordinationRegistryService as coordinationRegistryServiceSingleton } from './services/coordination-registry.service'
31
+ import type { documentChunkService } from './services/document-chunk.service'
32
+ import { documentChunkService as documentChunkServiceSingleton } from './services/document-chunk.service'
33
+ import { domainAgentExecutorService } from './services/domain-agent-executor.service'
34
+ import type { executionPlanService } from './services/execution-plan.service'
35
+ import { executionPlanService as executionPlanServiceSingleton } from './services/execution-plan.service'
36
+ import type { memoryService } from './services/memory.service'
37
+ import { memoryService as memoryServiceSingleton } from './services/memory.service'
38
+ import type { verifyMutatingApproval } from './services/mutating-approval.service'
39
+ import { verifyMutatingApproval as verifyMutatingApprovalSingleton } from './services/mutating-approval.service'
40
+ import { configureNotificationService } from './services/notification.service'
41
+ import type { organizationMemberService } from './services/organization-member.service'
42
+ import { organizationMemberService as organizationMemberServiceSingleton } from './services/organization-member.service'
43
+ import type { organizationService } from './services/organization.service'
44
+ import { organizationService as organizationServiceSingleton } from './services/organization.service'
45
+ import { playbookRegistryService } from './services/playbook-registry.service'
46
+ import type { recentActivityTitleService } from './services/recent-activity-title.service'
47
+ import { recentActivityTitleService as recentActivityTitleServiceSingleton } from './services/recent-activity-title.service'
48
+ import type { recentActivityService } from './services/recent-activity.service'
49
+ import { recentActivityService as recentActivityServiceSingleton } from './services/recent-activity.service'
50
+ import { getBuiltInSystemExecutors } from './services/system-executor.service'
51
+ import type { userService } from './services/user.service'
52
+ import { userService as userServiceSingleton } from './services/user.service'
53
+ import type { workstreamMessageService } from './services/workstream-message.service'
54
+ import { workstreamMessageService as workstreamMessageServiceSingleton } from './services/workstream-message.service'
55
+ import type { workstreamTitleService } from './services/workstream-title.service'
56
+ import { workstreamTitleService as workstreamTitleServiceSingleton } from './services/workstream-title.service'
57
+ import type {
58
+ createWorkstreamApprovalContinuationStream,
59
+ createWorkstreamNativeToolApprovalStream,
60
+ createWorkstreamTurnStream,
61
+ runWorkstreamTurnInBackground,
62
+ } from './services/workstream-turn'
63
+ import {
64
+ createWorkstreamApprovalContinuationStream as createWorkstreamApprovalContinuationStreamSingleton,
65
+ createWorkstreamNativeToolApprovalStream as createWorkstreamNativeToolApprovalStreamSingleton,
66
+ createWorkstreamTurnStream as createWorkstreamTurnStreamSingleton,
67
+ isApprovalContinuationRequest as isApprovalContinuationRequestSingleton,
68
+ runWorkstreamTurnInBackground as runWorkstreamTurnInBackgroundSingleton,
69
+ } from './services/workstream-turn'
70
+ import type { workstreamService } from './services/workstream.service'
71
+ import { workstreamService as workstreamServiceSingleton } from './services/workstream.service'
72
+ import type { generatedDocumentStorageService } from './storage/generated-document-storage.service'
73
+ import { generatedDocumentStorageService as generatedDocumentStorageServiceSingleton } from './storage/generated-document-storage.service'
74
+
75
+ type ArchiveSdkWorkstream = (
76
+ workstreamId: Parameters<typeof workstreamServiceSingleton.updateStatus>[0],
77
+ status?: 'archived',
78
+ ) => ReturnType<typeof workstreamServiceSingleton.updateStatus>
79
+
80
+ type UnarchiveSdkWorkstream = (
81
+ workstreamId: Parameters<typeof workstreamServiceSingleton.updateStatus>[0],
82
+ status?: 'regular',
83
+ ) => ReturnType<typeof workstreamServiceSingleton.updateStatus>
84
+
85
+ let activeRuntimeToken: symbol | null = null
86
+
87
+ function claimRuntimeToken(): symbol {
88
+ if (activeRuntimeToken) {
89
+ throw new Error('createLotaRuntime() is process-scoped. Disconnect the active runtime before creating another one.')
90
+ }
91
+
92
+ const token = Symbol('lota-runtime')
93
+ activeRuntimeToken = token
94
+ return token
95
+ }
96
+
97
+ function releaseRuntimeToken(token: symbol) {
98
+ if (activeRuntimeToken === token) {
99
+ activeRuntimeToken = null
100
+ }
101
+ }
102
+
103
+ export interface LotaRuntime {
104
+ services: {
105
+ database: SurrealDBService
106
+ redis: RedisConnectionManager
107
+ closeRedisConnection: () => Promise<void>
108
+ attachmentService: typeof attachmentService
109
+ documentChunkService: typeof documentChunkService
110
+ generatedDocumentStorageService: typeof generatedDocumentStorageService
111
+ memoryService: typeof memoryService
112
+ verifyMutatingApproval: typeof verifyMutatingApproval
113
+ organizationService: typeof organizationService
114
+ organizationMemberService: typeof organizationMemberService
115
+ userService: typeof userService
116
+ recentActivityService: typeof recentActivityService
117
+ recentActivityTitleService: typeof recentActivityTitleService
118
+ executionPlanService: typeof executionPlanService
119
+ workstreamMessageService: typeof workstreamMessageService
120
+ workstreamService: typeof workstreamService
121
+ workstreamTitleService: typeof workstreamTitleService
122
+ createWorkstreamApprovalContinuationStream: typeof createWorkstreamApprovalContinuationStream
123
+ createWorkstreamNativeToolApprovalStream: typeof createWorkstreamNativeToolApprovalStream
124
+ createWorkstreamTurnStream: typeof createWorkstreamTurnStream
125
+ isApprovalContinuationRequest: typeof isApprovalContinuationRequest
126
+ runWorkstreamTurnInBackground: typeof runWorkstreamTurnInBackground
127
+ syncPlaybookTemplates: typeof playbookRegistryService.syncPlaybookTemplates
128
+ }
129
+ lota: {
130
+ organizations: {
131
+ create: typeof organizationServiceSingleton.createOrganization
132
+ upsert: typeof organizationServiceSingleton.upsertOrganization
133
+ get: typeof organizationServiceSingleton.getOrganization
134
+ list: typeof organizationServiceSingleton.listOrganizations
135
+ update: typeof organizationServiceSingleton.updateOrganization
136
+ delete: typeof organizationServiceSingleton.deleteOrganization
137
+ }
138
+ users: {
139
+ upsert: typeof userServiceSingleton.upsertUser
140
+ get: typeof userServiceSingleton.getUser
141
+ list: typeof userServiceSingleton.listUsers
142
+ update: typeof userServiceSingleton.updateUser
143
+ delete: typeof userServiceSingleton.deleteUser
144
+ }
145
+ memberships: {
146
+ add: typeof organizationMemberServiceSingleton.addMembership
147
+ listForOrganization: typeof organizationMemberServiceSingleton.listMembershipsForOrganization
148
+ listForUser: typeof organizationMemberServiceSingleton.listMembershipsForUser
149
+ remove: typeof organizationMemberServiceSingleton.removeMembership
150
+ isMember: typeof organizationMemberServiceSingleton.isMember
151
+ }
152
+ workstreams: {
153
+ create: typeof workstreamServiceSingleton.createWorkstream
154
+ list: typeof workstreamServiceSingleton.listWorkstreams
155
+ get: typeof workstreamServiceSingleton.getWorkstream
156
+ update: typeof workstreamServiceSingleton.updateTitle
157
+ archive: ArchiveSdkWorkstream
158
+ unarchive: UnarchiveSdkWorkstream
159
+ delete: typeof workstreamServiceSingleton.deleteWorkstream
160
+ stop: typeof workstreamServiceSingleton.stopActiveRun
161
+ listMessages: typeof workstreamMessageServiceSingleton.listMessageHistoryPage
162
+ getMessage: (params: { workstreamId: string; messageId: string }) => Promise<ChatMessage>
163
+ sendMessage: (params: {
164
+ workstreamId: string
165
+ organizationId: string
166
+ userId: string
167
+ userName: string
168
+ messages: Parameters<typeof routeWorkstreamChatMessages>[0]
169
+ }) => Promise<Awaited<ReturnType<typeof createWorkstreamTurnStream>>>
170
+ continueApproval: (params: {
171
+ workstreamId: string
172
+ organizationId: string
173
+ userId: string
174
+ userName: string
175
+ messages: Parameters<typeof routeWorkstreamChatMessages>[0]
176
+ }) => Promise<Awaited<ReturnType<typeof createWorkstreamApprovalContinuationStream>>>
177
+ uploadAttachment: typeof attachmentServiceSingleton.uploadWorkstreamAttachment
178
+ }
179
+ }
180
+ redis: {
181
+ manager: RedisConnectionManager
182
+ getConnection: () => ReturnType<RedisConnectionManager['getConnection']>
183
+ getConnectionForBullMQ: () => ReturnType<RedisConnectionManager['getConnectionForBullMQ']>
184
+ closeConnection: () => Promise<void>
185
+ }
186
+ workers: LotaRuntimeWorkers
187
+ schemaFiles: Array<string | URL>
188
+ contributions: { envKeys: readonly string[]; schemaFiles: Array<string | URL> }
189
+ config: ResolvedLotaRuntimeConfig
190
+ plugins: Record<string, LotaPlugin>
191
+ systemExecutors: Record<string, SystemNodeExecutor>
192
+ connectPluginDatabases(): Promise<void>
193
+ connect(): Promise<void>
194
+ disconnect(): Promise<void>
195
+ }
196
+
197
+ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntime> {
198
+ const runtimeToken = claimRuntimeToken()
199
+
200
+ try {
201
+ const resolvedConfig = parseLotaRuntimeConfig(config)
202
+ const systemExecutors = { ...getBuiltInSystemExecutors(), ...resolvedConfig.systemExecutors }
203
+ const runtimeConfig = { ...resolvedConfig, systemExecutors } satisfies ResolvedLotaRuntimeConfig
204
+ configureRuntimeConfig(runtimeConfig)
205
+
206
+ await configureLotaLogger(runtimeConfig.logging.level)
207
+
208
+ const db = new SurrealDBServiceClass({
209
+ url: runtimeConfig.database.url,
210
+ namespace: runtimeConfig.database.namespace,
211
+ database: LOTA_SDK_DATABASE_NAME,
212
+ username: runtimeConfig.database.username,
213
+ password: runtimeConfig.database.password,
214
+ })
215
+ setDatabaseService(db)
216
+
217
+ const redisManager = createRedisConnectionManager({ url: runtimeConfig.redis.url })
218
+ setRedisConnectionManager(redisManager)
219
+ configureEmbeddingCache(redisManager.getConnection(), runtimeConfig.memory.embeddingCacheTtlSeconds)
220
+ configureBackgroundProcessing(runtimeConfig.backgroundProcessing)
221
+
222
+ configureAgents({
223
+ roster: runtimeConfig.agents.roster,
224
+ leadAgentId: runtimeConfig.agents.leadAgentId,
225
+ displayNames: runtimeConfig.agents.displayNames,
226
+ shortDisplayNames: runtimeConfig.agents.shortDisplayNames,
227
+ teamConsultParticipants: runtimeConfig.agents.teamConsultParticipants,
228
+ getCoreWorkstreamProfile: runtimeConfig.agents.getCoreWorkstreamProfile,
229
+ })
230
+ configureAgentFactory({
231
+ createAgent: runtimeConfig.agents.createAgent,
232
+ buildAgentTools: runtimeConfig.agents.buildAgentTools,
233
+ getAgentRuntimeConfig: runtimeConfig.agents.getAgentRuntimeConfig,
234
+ pluginRuntime: runtimeConfig.pluginRuntime,
235
+ })
236
+ configureWorkstreams({ agentRoster: runtimeConfig.agents.roster, config: runtimeConfig.workstreams })
237
+ configureNotificationService(runtimeConfig.notificationService ?? null)
238
+ configureRuntimeExtensions({
239
+ adapters: runtimeConfig.runtimeAdapters,
240
+ turnHooks: runtimeConfig.turnHooks,
241
+ toolProviders: (runtimeConfig.toolProviders ?? {}) as never,
242
+ extraWorkers: runtimeConfig.extraWorkers,
243
+ })
244
+
245
+ const pluginRuntime = runtimeConfig.pluginRuntime ?? {}
246
+ domainAgentExecutorService.configure(pluginRuntime)
247
+ if (runtimeConfig.graphDesigner) {
248
+ configureGraphDesigner(runtimeConfig.graphDesigner)
249
+ }
250
+
251
+ for (const [pluginRef, plugin] of Object.entries(pluginRuntime)) {
252
+ const signals = plugin.contributions.signals
253
+ if (signals && signals.length > 0) {
254
+ coordinationRegistryServiceSingleton.register(pluginRef, [...signals])
255
+ }
256
+ }
257
+ coordinationRegistryServiceSingleton.validate()
258
+ // Collect playbook contributions early to fail fast on misconfiguration
259
+ playbookRegistryService.collectPlaybooks()
260
+
261
+ const pluginContributions = Object.values(pluginRuntime).map((plugin) => plugin.contributions)
262
+ const schemaFiles = [...getBuiltInSchemaFiles(), ...(runtimeConfig.extraSchemaFiles ?? [])]
263
+ const hostContributionSchemaFiles = pluginContributions.flatMap((plugin) => plugin.schemaFiles)
264
+ const contributionEnvKeys = [...LOTA_RUNTIME_ENV_KEYS, ...pluginContributions.flatMap((plugin) => plugin.envKeys)]
265
+ const connectPluginDatabases = createPluginDatabaseConnector(pluginRuntime)
266
+ const workers = buildRuntimeWorkerRegistry(runtimeConfig.extraWorkers)
267
+
268
+ const lota = {
269
+ organizations: {
270
+ create: organizationServiceSingleton.createOrganization.bind(organizationServiceSingleton),
271
+ upsert: organizationServiceSingleton.upsertOrganization.bind(organizationServiceSingleton),
272
+ get: organizationServiceSingleton.getOrganization.bind(organizationServiceSingleton),
273
+ list: organizationServiceSingleton.listOrganizations.bind(organizationServiceSingleton),
274
+ update: organizationServiceSingleton.updateOrganization.bind(organizationServiceSingleton),
275
+ delete: organizationServiceSingleton.deleteOrganization.bind(organizationServiceSingleton),
276
+ },
277
+ users: {
278
+ upsert: userServiceSingleton.upsertUser.bind(userServiceSingleton),
279
+ get: userServiceSingleton.getUser.bind(userServiceSingleton),
280
+ list: userServiceSingleton.listUsers.bind(userServiceSingleton),
281
+ update: userServiceSingleton.updateUser.bind(userServiceSingleton),
282
+ delete: userServiceSingleton.deleteUser.bind(userServiceSingleton),
283
+ },
284
+ memberships: {
285
+ add: organizationMemberServiceSingleton.addMembership.bind(organizationMemberServiceSingleton),
286
+ listForOrganization: organizationMemberServiceSingleton.listMembershipsForOrganization.bind(
287
+ organizationMemberServiceSingleton,
288
+ ),
289
+ listForUser: organizationMemberServiceSingleton.listMembershipsForUser.bind(organizationMemberServiceSingleton),
290
+ remove: organizationMemberServiceSingleton.removeMembership.bind(organizationMemberServiceSingleton),
291
+ isMember: organizationMemberServiceSingleton.isMember.bind(organizationMemberServiceSingleton),
292
+ },
293
+ workstreams: {
294
+ create: workstreamServiceSingleton.createWorkstream.bind(workstreamServiceSingleton),
295
+ list: workstreamServiceSingleton.listWorkstreams.bind(workstreamServiceSingleton),
296
+ get: workstreamServiceSingleton.getWorkstream.bind(workstreamServiceSingleton),
297
+ update: workstreamServiceSingleton.updateTitle.bind(workstreamServiceSingleton),
298
+ archive: async (workstreamId, status = 'archived') =>
299
+ await workstreamServiceSingleton.updateStatus(workstreamId, status),
300
+ unarchive: async (workstreamId, status = 'regular') =>
301
+ await workstreamServiceSingleton.updateStatus(workstreamId, status),
302
+ delete: workstreamServiceSingleton.deleteWorkstream.bind(workstreamServiceSingleton),
303
+ stop: workstreamServiceSingleton.stopActiveRun.bind(workstreamServiceSingleton),
304
+ listMessages: workstreamMessageServiceSingleton.listMessageHistoryPage.bind(workstreamMessageServiceSingleton),
305
+ getMessage: async ({ workstreamId, messageId }) => {
306
+ const messages = await workstreamMessageServiceSingleton.listMessages(
307
+ ensureRecordId(workstreamId, TABLES.WORKSTREAM),
308
+ )
309
+ const message = messages.find((candidate) => candidate.id === messageId)
310
+ if (!message) {
311
+ throw new Error(`Workstream message not found: ${messageId}`)
312
+ }
313
+ return message
314
+ },
315
+ sendMessage: async ({ workstreamId, organizationId, userId, userName, messages }) => {
316
+ const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
317
+ const workstream = await workstreamServiceSingleton.getWorkstream(workstreamRef)
318
+ const routed = routeWorkstreamChatMessages(messages)
319
+ if (routed.kind !== 'turn') {
320
+ throw new Error(routed.kind === 'invalid' ? routed.message : 'Expected a user turn payload.')
321
+ }
322
+
323
+ return createWorkstreamTurnStreamSingleton({
324
+ workstream,
325
+ workstreamRef,
326
+ orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
327
+ userRef: ensureRecordId(userId, TABLES.USER),
328
+ userName,
329
+ inputMessage: routed.inputMessage,
330
+ })
331
+ },
332
+ continueApproval: async ({ workstreamId, organizationId, userId, userName, messages }) => {
333
+ const workstreamRef = ensureRecordId(workstreamId, TABLES.WORKSTREAM)
334
+ const workstream = await workstreamServiceSingleton.getWorkstream(workstreamRef)
335
+ const routed = routeWorkstreamChatMessages(messages)
336
+ if (routed.kind !== 'approval-continuation') {
337
+ throw new Error(
338
+ routed.kind === 'invalid' ? routed.message : 'Expected approval continuation messages payload.',
339
+ )
340
+ }
341
+
342
+ return createWorkstreamApprovalContinuationStreamSingleton({
343
+ workstream,
344
+ workstreamRef,
345
+ orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
346
+ userRef: ensureRecordId(userId, TABLES.USER),
347
+ userName,
348
+ approvalMessages: routed.approvalMessages,
349
+ })
350
+ },
351
+ uploadAttachment: attachmentServiceSingleton.uploadWorkstreamAttachment.bind(attachmentServiceSingleton),
352
+ },
353
+ } satisfies LotaRuntime['lota']
354
+
355
+ let disconnected = false
356
+
357
+ return {
358
+ services: {
359
+ database: db,
360
+ redis: redisManager,
361
+ closeRedisConnection: async () => await redisManager.closeConnection(),
362
+ attachmentService: attachmentServiceSingleton,
363
+ documentChunkService: documentChunkServiceSingleton,
364
+ generatedDocumentStorageService: generatedDocumentStorageServiceSingleton,
365
+ memoryService: memoryServiceSingleton,
366
+ verifyMutatingApproval: verifyMutatingApprovalSingleton,
367
+ organizationService: organizationServiceSingleton,
368
+ organizationMemberService: organizationMemberServiceSingleton,
369
+ userService: userServiceSingleton,
370
+ recentActivityService: recentActivityServiceSingleton,
371
+ recentActivityTitleService: recentActivityTitleServiceSingleton,
372
+ executionPlanService: executionPlanServiceSingleton,
373
+ workstreamMessageService: workstreamMessageServiceSingleton,
374
+ workstreamService: workstreamServiceSingleton,
375
+ workstreamTitleService: workstreamTitleServiceSingleton,
376
+ createWorkstreamApprovalContinuationStream: createWorkstreamApprovalContinuationStreamSingleton,
377
+ createWorkstreamNativeToolApprovalStream: createWorkstreamNativeToolApprovalStreamSingleton,
378
+ createWorkstreamTurnStream: createWorkstreamTurnStreamSingleton,
379
+ isApprovalContinuationRequest: isApprovalContinuationRequestSingleton,
380
+ runWorkstreamTurnInBackground: runWorkstreamTurnInBackgroundSingleton,
381
+ syncPlaybookTemplates: playbookRegistryService.syncPlaybookTemplates.bind(playbookRegistryService),
382
+ },
383
+ lota,
384
+ redis: {
385
+ manager: redisManager,
386
+ getConnection: () => redisManager.getConnection(),
387
+ getConnectionForBullMQ: () => redisManager.getConnectionForBullMQ(),
388
+ closeConnection: async () => await redisManager.closeConnection(),
389
+ },
390
+ workers,
391
+ schemaFiles,
392
+ contributions: { envKeys: [...new Set(contributionEnvKeys)], schemaFiles: hostContributionSchemaFiles },
393
+ config: runtimeConfig,
394
+ plugins: pluginRuntime,
395
+ systemExecutors,
396
+ async connectPluginDatabases() {
397
+ await connectPluginDatabases()
398
+ },
399
+ async connect() {
400
+ await db.connect()
401
+ const bunFiles = schemaFiles.map((schemaFile) =>
402
+ schemaFile instanceof URL ? Bun.file(schemaFile.pathname) : Bun.file(schemaFile),
403
+ )
404
+ await db.applySchema(bunFiles)
405
+ const schemaFingerprint = await computeSchemaFingerprint(schemaFiles)
406
+ await publishDatabaseBootstrap({ databaseService: db, schemaFingerprint })
407
+ },
408
+ async disconnect() {
409
+ if (disconnected) {
410
+ return
411
+ }
412
+ disconnected = true
413
+
414
+ try {
415
+ await closeSharedSubscriber()
416
+ await db.disconnect()
417
+ await redisManager.closeConnection()
418
+ } finally {
419
+ releaseRuntimeToken(runtimeToken)
420
+ }
421
+ },
422
+ }
423
+ } catch (error) {
424
+ releaseRuntimeToken(runtimeToken)
425
+ throw error
426
+ }
427
+ }
428
+
429
+ function getBuiltInSchemaFiles(): URL[] {
430
+ return [
431
+ new URL('../infrastructure/schema/00_identity.surql', import.meta.url),
432
+ new URL('../infrastructure/schema/00_workstream.surql', import.meta.url),
433
+ new URL('../infrastructure/schema/01_memory.surql', import.meta.url),
434
+ new URL('../infrastructure/schema/02_execution_plan.surql', import.meta.url),
435
+ new URL('../infrastructure/schema/03_learned_skill.surql', import.meta.url),
436
+ new URL('../infrastructure/schema/05_recent_activity.surql', import.meta.url),
437
+ new URL('../infrastructure/schema/04_runtime_bootstrap.surql', import.meta.url),
438
+ ]
439
+ }
440
+
441
+ function createPluginDatabaseConnector(pluginRuntime: Record<string, LotaPlugin>): () => Promise<void> {
442
+ return async () => {
443
+ for (const plugin of Object.values(pluginRuntime)) {
444
+ const services = plugin.services
445
+ const connectDatabase = services.connectDatabase
446
+ if (typeof connectDatabase !== 'function') {
447
+ continue
448
+ }
449
+
450
+ await Reflect.apply(connectDatabase, services, [])
451
+ }
452
+ }
453
+ }
@@ -1,4 +1,3 @@
1
- import { toTimestamp } from '@lota-sdk/shared'
2
1
  import type { ChatMessage } from '@lota-sdk/shared'
3
2
  import type { BoundQuery, RecordId } from 'surrealdb'
4
3
  import { z } from 'zod'
@@ -7,7 +6,7 @@ import type { RecordIdRef } from './record-id'
7
6
  import { databaseService } from './service'
8
7
  import type { DatabaseTable } from './tables'
9
8
 
10
- export const CursorRowSchema = z.object({ createdAt: z.union([z.date(), z.string(), z.number()]) })
9
+ export const CursorRowSchema = z.object({ createdAt: z.coerce.date() })
11
10
 
12
11
  export interface MessageHistoryPage {
13
12
  messages: ChatMessage[]
@@ -64,10 +63,8 @@ async function listRowsBefore(
64
63
  throw new Error(`Cursor message not found in ${config.table}: ${params.beforeMessageId}`)
65
64
  }
66
65
 
67
- const cursorCreatedAt = new Date(toTimestamp(cursorRow.createdAt))
66
+ const cursorCreatedAt = cursorRow.createdAt
68
67
  const cursorId = config.toRowId(params.parentId, params.beforeMessageId)
69
68
 
70
- return await databaseService.query<unknown>(
71
- config.queryBefore(params.parentId, cursorCreatedAt, cursorId, params.take),
72
- )
69
+ return databaseService.query<unknown>(config.queryBefore(params.parentId, cursorCreatedAt, cursorId, params.take))
73
70
  }
package/src/db/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './base.service'
1
2
  export * from './cursor-pagination'
2
3
  export * from './memory'
3
4
  export * from './memory-store'
@@ -7,4 +8,5 @@ export * from './record-id'
7
8
  export * from './sdk-database'
8
9
  export * from './service'
9
10
  export * from './startup'
11
+ export * from './surreal-mutation'
10
12
  export * from './tables'
@@ -13,17 +13,17 @@ export interface SurrealMemoryRow {
13
13
  importance: number
14
14
  accessCount: number
15
15
  needsReview: boolean
16
- lastAccessedAt?: Date | string
17
- createdAt: Date | string
18
- updatedAt?: Date | string
19
- validFrom: Date | string
20
- validUntil?: Date | string
21
- archivedAt?: Date | string
16
+ lastAccessedAt?: Date
17
+ createdAt: Date
18
+ updatedAt?: Date
19
+ validFrom: Date
20
+ validUntil?: Date
21
+ archivedAt?: Date
22
22
  }
23
23
 
24
24
  export interface BasicSearchRow {
25
25
  id: RecordIdInput
26
26
  content: string
27
27
  metadata: Record<string, unknown>
28
- createdAt?: Date | string
28
+ createdAt?: Date
29
29
  }