@lota-sdk/core 0.4.7 → 0.4.9

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 (259) hide show
  1. package/package.json +11 -12
  2. package/src/ai/embedding-cache.ts +94 -22
  3. package/src/ai-gateway/ai-gateway.ts +738 -223
  4. package/src/config/agent-defaults.ts +176 -75
  5. package/src/config/agent-types.ts +54 -4
  6. package/src/config/constants.ts +8 -2
  7. package/src/config/logger.ts +286 -19
  8. package/src/config/model-constants.ts +1 -0
  9. package/src/config/thread-defaults.ts +33 -21
  10. package/src/create-runtime.ts +725 -383
  11. package/src/db/base.service.ts +52 -28
  12. package/src/db/cursor-pagination.ts +71 -30
  13. package/src/db/memory-store.helpers.ts +4 -7
  14. package/src/db/memory-store.ts +856 -598
  15. package/src/db/memory.ts +398 -275
  16. package/src/db/record-id.ts +32 -10
  17. package/src/db/schema-fingerprint.ts +30 -12
  18. package/src/db/service-normalization.ts +255 -0
  19. package/src/db/service.ts +726 -761
  20. package/src/db/startup.ts +140 -66
  21. package/src/db/transaction-conflict.ts +15 -0
  22. package/src/effect/awaitable-effect.ts +87 -0
  23. package/src/effect/errors.ts +121 -0
  24. package/src/effect/helpers.ts +98 -0
  25. package/src/effect/index.ts +22 -0
  26. package/src/effect/layers.ts +228 -0
  27. package/src/effect/runtime-ref.ts +25 -0
  28. package/src/effect/runtime.ts +31 -0
  29. package/src/effect/services.ts +57 -0
  30. package/src/effect/zod.ts +43 -0
  31. package/src/embeddings/provider.ts +122 -71
  32. package/src/index.ts +46 -1
  33. package/src/openrouter/direct-provider.ts +29 -0
  34. package/src/queues/autonomous-job.queue.ts +130 -74
  35. package/src/queues/context-compaction.queue.ts +60 -15
  36. package/src/queues/delayed-node-promotion.queue.ts +52 -15
  37. package/src/queues/document-processor.queue.ts +52 -77
  38. package/src/queues/memory-consolidation.queue.ts +47 -32
  39. package/src/queues/organization-learning.queue.ts +13 -4
  40. package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
  41. package/src/queues/plan-scheduler.queue.ts +107 -31
  42. package/src/queues/post-chat-memory.queue.ts +66 -24
  43. package/src/queues/queue-factory.ts +142 -52
  44. package/src/queues/standalone-worker.ts +39 -0
  45. package/src/queues/title-generation.queue.ts +54 -9
  46. package/src/redis/connection.ts +84 -32
  47. package/src/redis/index.ts +6 -8
  48. package/src/redis/org-memory-lock.ts +60 -27
  49. package/src/redis/redis-lease-lock.ts +200 -121
  50. package/src/redis/runtime-connection.ts +10 -0
  51. package/src/redis/stream-context.ts +84 -46
  52. package/src/runtime/agent-identity-overrides.ts +2 -2
  53. package/src/runtime/agent-runtime-policy.ts +4 -1
  54. package/src/runtime/agent-stream-helpers.ts +20 -9
  55. package/src/runtime/chat-run-orchestration.ts +102 -19
  56. package/src/runtime/chat-run-registry.ts +36 -2
  57. package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
  58. package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
  59. package/src/runtime/execution-plan-visibility.ts +2 -2
  60. package/src/runtime/execution-plan.ts +42 -15
  61. package/src/runtime/graph-designer.ts +11 -7
  62. package/src/runtime/helper-model.ts +135 -48
  63. package/src/runtime/index.ts +7 -7
  64. package/src/runtime/indexed-repositories-policy.ts +3 -3
  65. package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
  66. package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
  67. package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
  68. package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
  69. package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
  70. package/src/runtime/plugin-resolution.ts +144 -24
  71. package/src/runtime/plugin-types.ts +9 -1
  72. package/src/runtime/post-turn-side-effects.ts +197 -130
  73. package/src/runtime/retrieval-adapters.ts +38 -4
  74. package/src/runtime/runtime-config.ts +165 -61
  75. package/src/runtime/runtime-extensions.ts +21 -34
  76. package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
  77. package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
  78. package/src/runtime/social-chat/social-chat.ts +594 -0
  79. package/src/runtime/specialist-runner.ts +36 -10
  80. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
  81. package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
  82. package/src/runtime/thread-chat-helpers.ts +2 -2
  83. package/src/runtime/thread-plan-turn.ts +2 -1
  84. package/src/runtime/thread-turn-context.ts +172 -94
  85. package/src/runtime/turn-lifecycle.ts +93 -27
  86. package/src/services/agent-activity.service.ts +287 -203
  87. package/src/services/agent-executor.service.ts +329 -217
  88. package/src/services/artifact.service.ts +225 -148
  89. package/src/services/attachment.service.ts +137 -115
  90. package/src/services/autonomous-job.service.ts +888 -491
  91. package/src/services/chat-run-registry.service.ts +11 -1
  92. package/src/services/context-compaction.service.ts +136 -86
  93. package/src/services/document-chunk.service.ts +162 -90
  94. package/src/services/execution-plan/execution-plan-approval.ts +26 -0
  95. package/src/services/execution-plan/execution-plan-context.ts +29 -0
  96. package/src/services/execution-plan/execution-plan-graph.ts +256 -0
  97. package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
  98. package/src/services/execution-plan/execution-plan-spec.ts +75 -0
  99. package/src/services/execution-plan/execution-plan.service.ts +1041 -0
  100. package/src/services/feedback-loop.service.ts +132 -76
  101. package/src/services/global-orchestrator.service.ts +80 -170
  102. package/src/services/graph-full-routing.ts +182 -0
  103. package/src/services/index.ts +18 -20
  104. package/src/services/institutional-memory.service.ts +220 -123
  105. package/src/services/learned-skill.service.ts +364 -259
  106. package/src/services/memory/memory-conversation.ts +95 -0
  107. package/src/services/memory/memory-org-memory.ts +39 -0
  108. package/src/services/memory/memory-preseeded.ts +80 -0
  109. package/src/services/memory/memory-rerank.ts +297 -0
  110. package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
  111. package/src/services/memory/memory.service.ts +692 -0
  112. package/src/services/memory/rerank.service.ts +209 -0
  113. package/src/services/monitoring-window.service.ts +92 -70
  114. package/src/services/mutating-approval.service.ts +62 -53
  115. package/src/services/node-workspace.service.ts +141 -98
  116. package/src/services/notification.service.ts +17 -16
  117. package/src/services/organization-member.service.ts +120 -66
  118. package/src/services/organization.service.ts +144 -51
  119. package/src/services/ownership-dispatcher.service.ts +415 -264
  120. package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
  121. package/src/services/plan/plan-agent-query.service.ts +322 -0
  122. package/src/services/plan/plan-approval.service.ts +102 -0
  123. package/src/services/plan/plan-artifact.service.ts +60 -0
  124. package/src/services/plan/plan-builder.service.ts +76 -0
  125. package/src/services/plan/plan-checkpoint.service.ts +103 -0
  126. package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
  127. package/src/services/plan/plan-completion-side-effects.ts +175 -0
  128. package/src/services/plan/plan-coordination.service.ts +181 -0
  129. package/src/services/plan/plan-cycle.service.ts +398 -0
  130. package/src/services/plan/plan-deadline.service.ts +547 -0
  131. package/src/services/plan/plan-event-delivery.service.ts +261 -0
  132. package/src/services/plan/plan-executor-context.ts +35 -0
  133. package/src/services/plan/plan-executor-graph.ts +475 -0
  134. package/src/services/plan/plan-executor-helpers.ts +322 -0
  135. package/src/services/plan/plan-executor-persistence.ts +209 -0
  136. package/src/services/plan/plan-executor.service.ts +1654 -0
  137. package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
  138. package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
  139. package/src/services/plan/plan-run-serialization.ts +15 -0
  140. package/src/services/plan/plan-run.service.ts +644 -0
  141. package/src/services/plan/plan-scheduler.service.ts +385 -0
  142. package/src/services/plan/plan-template.service.ts +224 -0
  143. package/src/services/plan/plan-transaction-events.ts +33 -0
  144. package/src/services/plan/plan-validator.service.ts +907 -0
  145. package/src/services/plan/plan-workspace.service.ts +125 -0
  146. package/src/services/plugin-executor.service.ts +97 -68
  147. package/src/services/quality-metrics.service.ts +112 -94
  148. package/src/services/queue-job.service.ts +296 -230
  149. package/src/services/recent-activity-title.service.ts +65 -36
  150. package/src/services/recent-activity.service.ts +274 -259
  151. package/src/services/skill-resolver.service.ts +38 -12
  152. package/src/services/social-chat-history.service.ts +176 -125
  153. package/src/services/system-executor.service.ts +91 -61
  154. package/src/services/thread/thread-active-run.ts +203 -0
  155. package/src/services/thread/thread-bootstrap.ts +369 -0
  156. package/src/services/thread/thread-listing.ts +198 -0
  157. package/src/services/thread/thread-memory-block.ts +117 -0
  158. package/src/services/thread/thread-message.service.ts +363 -0
  159. package/src/services/thread/thread-record-store.ts +155 -0
  160. package/src/services/thread/thread-title.service.ts +74 -0
  161. package/src/services/thread/thread-turn-execution.ts +280 -0
  162. package/src/services/thread/thread-turn-message-context.ts +73 -0
  163. package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
  164. package/src/services/thread/thread-turn-streaming.ts +402 -0
  165. package/src/services/thread/thread-turn-tracing.ts +35 -0
  166. package/src/services/thread/thread-turn.ts +343 -0
  167. package/src/services/thread/thread.service.ts +335 -0
  168. package/src/services/user.service.ts +82 -32
  169. package/src/services/write-intent-validator.service.ts +63 -51
  170. package/src/storage/attachment-parser.ts +69 -27
  171. package/src/storage/attachment-storage.service.ts +331 -275
  172. package/src/storage/generated-document-storage.service.ts +66 -34
  173. package/src/system-agents/agent-result.ts +3 -1
  174. package/src/system-agents/context-compaction.agent.ts +2 -2
  175. package/src/system-agents/delegated-agent-factory.ts +159 -90
  176. package/src/system-agents/memory-reranker.agent.ts +2 -2
  177. package/src/system-agents/memory.agent.ts +2 -2
  178. package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
  179. package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
  180. package/src/system-agents/skill-extractor.agent.ts +2 -2
  181. package/src/system-agents/skill-manager.agent.ts +2 -2
  182. package/src/system-agents/thread-router.agent.ts +157 -113
  183. package/src/system-agents/title-generator.agent.ts +2 -2
  184. package/src/tools/execution-plan.tool.ts +220 -161
  185. package/src/tools/fetch-webpage.tool.ts +21 -17
  186. package/src/tools/firecrawl-client.ts +16 -6
  187. package/src/tools/index.ts +1 -0
  188. package/src/tools/memory-block.tool.ts +14 -6
  189. package/src/tools/plan-approval.tool.ts +49 -47
  190. package/src/tools/read-file-parts.tool.ts +44 -33
  191. package/src/tools/remember-memory.tool.ts +65 -45
  192. package/src/tools/search-web.tool.ts +26 -22
  193. package/src/tools/search.tool.ts +41 -29
  194. package/src/tools/team-think.tool.ts +124 -83
  195. package/src/tools/user-questions.tool.ts +4 -3
  196. package/src/tools/web-tool-shared.ts +6 -0
  197. package/src/utils/async.ts +17 -23
  198. package/src/utils/crypto.ts +21 -0
  199. package/src/utils/date-time.ts +40 -1
  200. package/src/utils/errors.ts +95 -16
  201. package/src/utils/hono-error-handler.ts +24 -39
  202. package/src/utils/index.ts +2 -1
  203. package/src/utils/null-proto-record.ts +41 -0
  204. package/src/utils/sse-keepalive.ts +124 -21
  205. package/src/workers/bootstrap.ts +186 -51
  206. package/src/workers/memory-consolidation.worker.ts +325 -237
  207. package/src/workers/organization-learning.worker.ts +50 -16
  208. package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
  209. package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
  210. package/src/workers/skill-extraction.runner.ts +176 -93
  211. package/src/workers/utils/file-section-chunker.ts +8 -10
  212. package/src/workers/utils/repo-structure-extractor.ts +349 -260
  213. package/src/workers/utils/repomix-file-sections.ts +2 -2
  214. package/src/workers/utils/thread-message-query.ts +97 -38
  215. package/src/workers/worker-utils.ts +56 -31
  216. package/src/config/debug-logger.ts +0 -47
  217. package/src/redis/connection-accessor.ts +0 -26
  218. package/src/runtime/context-compaction-runtime.ts +0 -87
  219. package/src/runtime/social-chat-agent-runner.ts +0 -118
  220. package/src/runtime/social-chat.ts +0 -516
  221. package/src/runtime/team-consultation-orchestrator.ts +0 -272
  222. package/src/services/adaptive-playbook.service.ts +0 -152
  223. package/src/services/artifact-provenance.service.ts +0 -172
  224. package/src/services/chat-attachments.service.ts +0 -17
  225. package/src/services/context-compaction-runtime.singleton.ts +0 -13
  226. package/src/services/execution-plan.service.ts +0 -1118
  227. package/src/services/memory.service.ts +0 -844
  228. package/src/services/plan-agent-heartbeat.service.ts +0 -136
  229. package/src/services/plan-agent-query.service.ts +0 -267
  230. package/src/services/plan-approval.service.ts +0 -83
  231. package/src/services/plan-artifact.service.ts +0 -50
  232. package/src/services/plan-builder.service.ts +0 -67
  233. package/src/services/plan-checkpoint.service.ts +0 -81
  234. package/src/services/plan-completion-side-effects.ts +0 -80
  235. package/src/services/plan-coordination.service.ts +0 -157
  236. package/src/services/plan-cycle.service.ts +0 -284
  237. package/src/services/plan-deadline.service.ts +0 -430
  238. package/src/services/plan-event-delivery.service.ts +0 -166
  239. package/src/services/plan-executor.service.ts +0 -1950
  240. package/src/services/plan-run.service.ts +0 -515
  241. package/src/services/plan-scheduler.service.ts +0 -240
  242. package/src/services/plan-template.service.ts +0 -177
  243. package/src/services/plan-validator.service.ts +0 -818
  244. package/src/services/plan-workspace.service.ts +0 -83
  245. package/src/services/thread-message.service.ts +0 -275
  246. package/src/services/thread-plan-registry.service.ts +0 -22
  247. package/src/services/thread-title.service.ts +0 -39
  248. package/src/services/thread-turn-preparation.service.ts +0 -1147
  249. package/src/services/thread-turn.ts +0 -172
  250. package/src/services/thread.service.ts +0 -869
  251. package/src/utils/env.ts +0 -8
  252. /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
  253. /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
  254. /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
  255. /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
  256. /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
  257. /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
  258. /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
  259. /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
@@ -1,4 +1,4 @@
1
- import { agentRoster } from '../config/agent-defaults'
1
+ import { getAgentRoster } from '../config/agent-defaults'
2
2
 
3
3
  export type IndexedRepoAgentName = string
4
4
 
@@ -16,13 +16,13 @@ export type RepoSectionName = (typeof REPO_SECTION_NAMES)[number]
16
16
  const ALL_REPO_SECTIONS: RepoSectionName[] = [...REPO_SECTION_NAMES]
17
17
 
18
18
  export function buildDefaultRepoSectionsByAgent(
19
- roster: readonly IndexedRepoAgentName[] = agentRoster,
19
+ roster: readonly IndexedRepoAgentName[] = getAgentRoster(),
20
20
  ): Record<IndexedRepoAgentName, RepoSectionName[]> {
21
21
  return Object.fromEntries(roster.map((agentId) => [agentId, [...ALL_REPO_SECTIONS]]))
22
22
  }
23
23
 
24
24
  export function emptyAgentContextMap(
25
- roster: readonly IndexedRepoAgentName[] = agentRoster,
25
+ roster: readonly IndexedRepoAgentName[] = getAgentRoster(),
26
26
  ): Record<IndexedRepoAgentName, string> {
27
27
  return Object.fromEntries(roster.map((agentId) => [agentId, '']))
28
28
  }
@@ -1,31 +1,30 @@
1
+ import type { Cause } from 'effect'
2
+ import { DateTime, Effect } from 'effect'
1
3
  import { z } from 'zod'
2
4
 
3
- import { agentDisplayNames, agentShortDisplayNames, resolveAgentNameAlias } from '../config/agent-defaults'
4
- import { compactWhitespace } from '../utils/string'
5
+ import { effectTryPromise } from '../../effect/helpers'
6
+ import { compactWhitespace } from '../../utils/string'
5
7
 
6
8
  function escapeRegex(value: string): string {
7
9
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
8
10
  }
9
11
 
10
12
  function normalizeMemoryBlockRole(role: string): string {
11
- const canonicalRole = resolveAgentNameAlias(role)
12
- if (canonicalRole) return canonicalRole
13
13
  return role.trim().toLowerCase()
14
14
  }
15
15
 
16
+ function toLabelAlias(role: string): string {
17
+ const trimmed = role.trim()
18
+ if (!trimmed) return ''
19
+ return trimmed.length === 1 ? trimmed.toUpperCase() : `${trimmed[0].toUpperCase()}${trimmed.slice(1).toLowerCase()}`
20
+ }
21
+
16
22
  function getMemoryBlockRoleAliases(role: string): string[] {
17
23
  const normalizedRole = role.trim()
18
24
  if (!normalizedRole) return []
19
-
20
- const canonicalRole = resolveAgentNameAlias(normalizedRole)
21
- if (!canonicalRole) return [normalizedRole]
22
-
23
- return [
24
- normalizedRole,
25
- canonicalRole,
26
- agentDisplayNames[canonicalRole],
27
- agentShortDisplayNames[canonicalRole],
28
- ].filter((value): value is string => typeof value === 'string' && value.trim().length > 0)
25
+ return [normalizedRole, normalizedRole.toLowerCase(), toLabelAlias(normalizedRole)].filter(
26
+ (value): value is string => typeof value === 'string' && value.trim().length > 0,
27
+ )
29
28
  }
30
29
 
31
30
  function createLabelPrefixRegex(labelRoles: readonly string[]): RegExp | null {
@@ -59,7 +58,10 @@ export interface CompactMemoryBlockEntriesParams {
59
58
  entries: MemoryBlockEntry[]
60
59
  triggerEntries: number
61
60
  chunkEntries: number
62
- compact: (params: { previousSummary: string; newEntriesText: string }) => Promise<string>
61
+ compact: (params: {
62
+ previousSummary: string
63
+ newEntriesText: string
64
+ }) => PromiseLike<string> | Effect.Effect<string, unknown>
63
65
  }
64
66
 
65
67
  export interface CompactMemoryBlockEntriesResult {
@@ -102,29 +104,31 @@ function toMemoryBlockEntriesSource(entries: Array<{ role: string; content: stri
102
104
  return entries.map((entry) => `${entry.role}: ${entry.content}`).join('\n')
103
105
  }
104
106
 
105
- export async function compactMemoryBlockEntries(
107
+ export function compactMemoryBlockEntries(
106
108
  params: CompactMemoryBlockEntriesParams,
107
- ): Promise<CompactMemoryBlockEntriesResult> {
108
- let summary = typeof params.previousSummary === 'string' ? params.previousSummary.trim() : ''
109
- let entries = [...params.entries]
110
- let compacted = false
111
-
112
- while (entries.length >= params.triggerEntries) {
113
- const chunk = entries.slice(0, params.chunkEntries)
114
- const nextSummary = (
115
- await params.compact({ previousSummary: summary, newEntriesText: toMemoryBlockEntriesSource(chunk) })
116
- ).trim()
117
-
118
- if (!nextSummary) {
119
- break
109
+ ): Effect.Effect<CompactMemoryBlockEntriesResult, Cause.UnknownError> {
110
+ return Effect.gen(function* () {
111
+ let summary = typeof params.previousSummary === 'string' ? params.previousSummary.trim() : ''
112
+ let entries = [...params.entries]
113
+ let compacted = false
114
+
115
+ while (entries.length >= params.triggerEntries) {
116
+ const chunk = entries.slice(0, params.chunkEntries)
117
+ const nextSummary = (yield* effectTryPromise(() =>
118
+ params.compact({ previousSummary: summary, newEntriesText: toMemoryBlockEntriesSource(chunk) }),
119
+ )).trim()
120
+
121
+ if (!nextSummary) {
122
+ break
123
+ }
124
+
125
+ summary = nextSummary
126
+ entries = entries.slice(params.chunkEntries)
127
+ compacted = true
120
128
  }
121
129
 
122
- summary = nextSummary
123
- entries = entries.slice(params.chunkEntries)
124
- compacted = true
125
- }
126
-
127
- return { compacted, summary, entries }
130
+ return { compacted, summary, entries }
131
+ })
128
132
  }
129
133
 
130
134
  export function prepareMemoryBlockAppend(params: PrepareMemoryBlockAppendParams): PrepareMemoryBlockAppendResult {
@@ -158,7 +162,7 @@ export interface CreateMemoryBlockRuntimeOptions {
158
162
  export function createMemoryBlockRuntime(options: CreateMemoryBlockRuntimeOptions = {}): MemoryBlockRuntime {
159
163
  const labelPrefixRegex = createLabelPrefixRegex(options.labelRoles ?? [])
160
164
  const memoryBlockMaxChars = options.maxChars ?? 400
161
- const now = options.now ?? (() => new Date())
165
+ const now = options.now ?? (() => Effect.runSync(DateTime.nowAsDate))
162
166
 
163
167
  const normalizeMemoryBlockEntry = (entry: string): string => {
164
168
  const normalizedLines = entry
@@ -1,4 +1,4 @@
1
- import { getBackgroundProcessingConfig, shouldRunAtFrequency } from '../config/background-processing'
1
+ import { getBackgroundProcessingConfig, shouldRunAtFrequency } from '../../config/background-processing'
2
2
 
3
3
  export function shouldEnqueueOnboardingPostChatMemory(params: {
4
4
  onboardingActive: boolean
@@ -1,4 +1,4 @@
1
- import { clampImportance, compactWhitespace } from '../utils/string'
1
+ import { clampImportance, compactWhitespace } from '../../utils/string'
2
2
 
3
3
  const SCORE_WEIGHTS = {
4
4
  durability: { core: 0.35, standard: 0.2, weak: 0.05 },
@@ -1,4 +1,4 @@
1
- import { formatUtcPromptDate } from '../utils/date-time'
1
+ import { formatUtcPromptDate, nowDate } from '../../utils/date-time'
2
2
 
3
3
  export function getFactRetrievalMessages(
4
4
  parsedMessages: string,
@@ -56,7 +56,7 @@ Hard rules:
56
56
  - Prefer returning fewer items. If uncertain, return an empty list.
57
57
  - Max ${maxFacts} facts.
58
58
 
59
- Today's date is ${formatUtcPromptDate(new Date())}.
59
+ Today's date is ${formatUtcPromptDate(nowDate())}.
60
60
  ${baseInstructions}`
61
61
 
62
62
  const userPrompt = `Conversation:\n${parsedMessages}`
@@ -1,11 +1,17 @@
1
+ import { Schema } from 'effect'
2
+
1
3
  export const ORG_SCOPE_PREFIX = 'org'
2
4
 
3
5
  const SCOPE_ID_MAX_LENGTH = 255
4
6
  const SCOPE_PREFIX_REGEX = /^[a-z][a-z0-9_]*$/
5
7
 
8
+ export class MemoryScopeError extends Schema.TaggedErrorClass<MemoryScopeError>()('MemoryScopeError', {
9
+ message: Schema.String,
10
+ }) {}
11
+
6
12
  function stripRecordPrefix(id: string): string {
7
13
  if (typeof id !== 'string' || id.length === 0) {
8
- throw new TypeError('id must be a non-empty string')
14
+ throw new MemoryScopeError({ message: 'id must be a non-empty string' })
9
15
  }
10
16
  const [, ...rest] = id.split(':')
11
17
  return rest.length > 0 ? rest.join(':') : id
@@ -13,16 +19,16 @@ function stripRecordPrefix(id: string): string {
13
19
 
14
20
  export function scopeId(prefix: string, id: string): string {
15
21
  if (typeof prefix !== 'string' || prefix.length === 0) {
16
- throw new TypeError('prefix must be a non-empty string')
22
+ throw new MemoryScopeError({ message: 'prefix must be a non-empty string' })
17
23
  }
18
24
  if (!SCOPE_PREFIX_REGEX.test(prefix)) {
19
- throw new Error(`Invalid scope prefix: ${prefix}`)
25
+ throw new MemoryScopeError({ message: `Invalid scope prefix: ${prefix}` })
20
26
  }
21
27
 
22
28
  const stripped = stripRecordPrefix(id)
23
29
  const scoped = `${prefix}:${stripped}`
24
30
  if (scoped.length > SCOPE_ID_MAX_LENGTH) {
25
- throw new Error('scopeId exceeds maximum length')
31
+ throw new MemoryScopeError({ message: 'scopeId exceeds maximum length' })
26
32
  }
27
33
 
28
34
  return scoped
@@ -30,13 +36,13 @@ export function scopeId(prefix: string, id: string): string {
30
36
 
31
37
  export function agentScopeId(orgId: string, agentName: string): string {
32
38
  if (typeof agentName !== 'string' || agentName.trim().length === 0) {
33
- throw new TypeError('agentName must be a non-empty string')
39
+ throw new MemoryScopeError({ message: 'agentName must be a non-empty string' })
34
40
  }
35
41
  const strippedOrgId = stripRecordPrefix(orgId)
36
42
  const scoped = `agent:${strippedOrgId}:${agentName.trim()}`
37
43
 
38
44
  if (scoped.length > SCOPE_ID_MAX_LENGTH) {
39
- throw new Error('scopeId exceeds maximum length')
45
+ throw new MemoryScopeError({ message: 'scopeId exceeds maximum length' })
40
46
  }
41
47
 
42
48
  return scoped
@@ -1,36 +1,156 @@
1
- import { pluginRuntime } from '../config/agent-defaults'
1
+ import { Schema, Effect } from 'effect'
2
+
3
+ import { getPluginRuntime } from '../config/agent-defaults'
4
+ import type { RecordIdRef } from '../db/record-id'
2
5
  import type { LotaRuntimeIndexedRepositoriesContext } from './runtime-extensions'
3
6
  import { getRuntimeAdapters } from './runtime-extensions'
4
7
 
5
- export function getPluginService(path: string[]): ((...args: unknown[]) => unknown) | undefined {
6
- let current: unknown = pluginRuntime
7
- let owner: unknown = undefined
8
- for (const key of path) {
9
- if (current === null || current === undefined || typeof current !== 'object') return undefined
10
- owner = current
11
- current = (current as Record<string, unknown>)[key]
8
+ function isRecord(value: unknown): value is Record<string, unknown> {
9
+ return typeof value === 'object' && value !== null
10
+ }
11
+
12
+ class PluginResolutionError extends Schema.TaggedErrorClass<PluginResolutionError>()('PluginResolutionError', {
13
+ stage: Schema.Literals([
14
+ 'configuration',
15
+ 'linear-installation',
16
+ 'github-installation',
17
+ 'indexed-repositories-context',
18
+ ]),
19
+ message: Schema.String,
20
+ cause: Schema.Defect,
21
+ }) {}
22
+
23
+ function toPluginResolutionError(stage: PluginResolutionError['stage'], cause: unknown): PluginResolutionError {
24
+ return new PluginResolutionError({ stage, message: cause instanceof Error ? cause.message : String(cause), cause })
25
+ }
26
+
27
+ function readFunctionEffect(
28
+ value: unknown,
29
+ errorMessage: string,
30
+ ): Effect.Effect<(...args: unknown[]) => PromiseLike<unknown>, PluginResolutionError> {
31
+ if (typeof value !== 'function') {
32
+ return Effect.fail(new PluginResolutionError({ stage: 'configuration', message: errorMessage, cause: undefined }))
33
+ }
34
+
35
+ return Effect.succeed(value as (...args: unknown[]) => PromiseLike<unknown>)
36
+ }
37
+
38
+ function resolvePluginServiceEffect(
39
+ pluginName: string,
40
+ serviceName: string,
41
+ methodName: string,
42
+ ): Effect.Effect<(...args: unknown[]) => PromiseLike<unknown>, PluginResolutionError> {
43
+ const pluginRuntime = getPluginRuntime()
44
+ if (!pluginRuntime) {
45
+ return Effect.fail(
46
+ new PluginResolutionError({
47
+ stage: 'configuration',
48
+ message: `Plugin runtime is not configured. Missing "${pluginName}" integration.`,
49
+ cause: undefined,
50
+ }),
51
+ )
52
+ }
53
+
54
+ const plugin = pluginRuntime[pluginName]
55
+ if (!isRecord(plugin)) {
56
+ return Effect.fail(
57
+ new PluginResolutionError({
58
+ stage: 'configuration',
59
+ message: `Plugin "${pluginName}" is not configured in the current runtime.`,
60
+ cause: undefined,
61
+ }),
62
+ )
63
+ }
64
+
65
+ const services = plugin.services
66
+ if (!isRecord(services)) {
67
+ return Effect.fail(
68
+ new PluginResolutionError({
69
+ stage: 'configuration',
70
+ message: `Plugin "${pluginName}" does not expose a services registry.`,
71
+ cause: undefined,
72
+ }),
73
+ )
12
74
  }
13
- if (typeof current !== 'function') {
14
- return undefined
75
+
76
+ const service = services[serviceName]
77
+ if (!isRecord(service)) {
78
+ return Effect.fail(
79
+ new PluginResolutionError({
80
+ stage: 'configuration',
81
+ message: `Plugin "${pluginName}" service "${serviceName}" is not configured.`,
82
+ cause: undefined,
83
+ }),
84
+ )
15
85
  }
16
86
 
17
- return owner && typeof owner === 'object'
18
- ? (current as (...args: unknown[]) => unknown).bind(owner)
19
- : (current as (...args: unknown[]) => unknown)
87
+ return readFunctionEffect(
88
+ service[methodName],
89
+ `Plugin "${pluginName}" service "${serviceName}" is missing method "${methodName}".`,
90
+ ).pipe(
91
+ Effect.map(
92
+ (method) =>
93
+ (...args: unknown[]) =>
94
+ Reflect.apply(method, service, args),
95
+ ),
96
+ )
97
+ }
98
+
99
+ function tryResolvePluginServiceEffect(
100
+ pluginName: string,
101
+ serviceName: string,
102
+ methodName: string,
103
+ ): Effect.Effect<((...args: unknown[]) => PromiseLike<unknown>) | undefined> {
104
+ return Effect.catch(resolvePluginServiceEffect(pluginName, serviceName, methodName), () => Effect.succeed(undefined))
20
105
  }
21
106
 
22
- export async function buildIndexedRepositoriesContext(
107
+ export function getLinearInstallationByOrgId(organizationId: RecordIdRef): Promise<unknown> {
108
+ return Effect.runPromise(
109
+ Effect.gen(function* () {
110
+ const fn = yield* tryResolvePluginServiceEffect('linear', 'linearService', 'getInstallationByOrgId')
111
+ if (!fn) return null
112
+ return yield* Effect.tryPromise({
113
+ try: () => fn(organizationId),
114
+ catch: (cause) => toPluginResolutionError('linear-installation', cause),
115
+ })
116
+ }),
117
+ )
118
+ }
119
+
120
+ export function getGithubInstallationForOrganization(organizationId: string): Promise<unknown> {
121
+ return Effect.runPromise(
122
+ Effect.gen(function* () {
123
+ const fn = yield* tryResolvePluginServiceEffect('github', 'githubService', 'getInstallationForOrganization')
124
+ if (!fn) return null
125
+ return yield* Effect.tryPromise({
126
+ try: () => fn(organizationId),
127
+ catch: (cause) => toPluginResolutionError('github-installation', cause),
128
+ })
129
+ }),
130
+ )
131
+ }
132
+
133
+ const EMPTY_INDEXED_REPO_CONTEXT: LotaRuntimeIndexedRepositoriesContext = {
134
+ provideRepoTool: false,
135
+ defaultSectionsByAgent: {},
136
+ context: '',
137
+ }
138
+
139
+ export function buildIndexedRepositoriesContext(
23
140
  organizationId: string,
24
141
  ): Promise<LotaRuntimeIndexedRepositoriesContext> {
25
142
  const buildContext = getRuntimeAdapters().buildIndexedRepositoriesContext
26
- if (!buildContext) {
27
- return { provideRepoTool: false, defaultSectionsByAgent: {}, context: '' }
28
- }
29
-
30
- const result = await buildContext(organizationId)
31
- return {
32
- provideRepoTool: result.provideRepoTool,
33
- defaultSectionsByAgent: result.defaultSectionsByAgent,
34
- context: result.context ?? '',
35
- }
143
+ if (!buildContext) return Promise.resolve(EMPTY_INDEXED_REPO_CONTEXT)
144
+ return Effect.runPromise(
145
+ Effect.tryPromise({
146
+ try: () => buildContext(organizationId),
147
+ catch: (cause) => toPluginResolutionError('indexed-repositories-context', cause),
148
+ }).pipe(
149
+ Effect.map((result) => ({
150
+ provideRepoTool: result.provideRepoTool,
151
+ defaultSectionsByAgent: result.defaultSectionsByAgent,
152
+ context: result.context ?? '',
153
+ })),
154
+ ),
155
+ )
36
156
  }
@@ -33,7 +33,15 @@ export interface SystemNodeExecutor {
33
33
  executeNode(params: PluginNodeExecutionParams): Promise<PlanNodeResult>
34
34
  }
35
35
 
36
- export interface LotaPlugin<TServices = Record<string, unknown>, TTools = Record<string, unknown>> {
36
+ export interface PluginLifecycleServices {
37
+ connectDatabase?(): Promise<void>
38
+ disconnectDatabase?(): Promise<void>
39
+ }
40
+
41
+ export interface LotaPlugin<
42
+ TServices extends Record<string, unknown> = Record<string, unknown>,
43
+ TTools = Record<string, unknown>,
44
+ > {
37
45
  services: TServices
38
46
  nodeExecutor?: PluginNodeExecutor
39
47
  tools?: TTools