@lota-sdk/core 0.4.8 → 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/thread-defaults.ts +33 -21
  9. package/src/create-runtime.ts +725 -387
  10. package/src/db/base.service.ts +52 -28
  11. package/src/db/cursor-pagination.ts +71 -30
  12. package/src/db/memory-store.helpers.ts +4 -7
  13. package/src/db/memory-store.ts +856 -598
  14. package/src/db/memory.ts +398 -275
  15. package/src/db/record-id.ts +32 -10
  16. package/src/db/schema-fingerprint.ts +30 -12
  17. package/src/db/service-normalization.ts +255 -0
  18. package/src/db/service.ts +726 -761
  19. package/src/db/startup.ts +140 -66
  20. package/src/db/transaction-conflict.ts +15 -0
  21. package/src/effect/awaitable-effect.ts +87 -0
  22. package/src/effect/errors.ts +121 -0
  23. package/src/effect/helpers.ts +98 -0
  24. package/src/effect/index.ts +22 -0
  25. package/src/effect/layers.ts +228 -0
  26. package/src/effect/runtime-ref.ts +25 -0
  27. package/src/effect/runtime.ts +31 -0
  28. package/src/effect/services.ts +57 -0
  29. package/src/effect/zod.ts +43 -0
  30. package/src/embeddings/provider.ts +122 -76
  31. package/src/index.ts +46 -1
  32. package/src/openrouter/direct-provider.ts +11 -35
  33. package/src/queues/autonomous-job.queue.ts +130 -74
  34. package/src/queues/context-compaction.queue.ts +60 -15
  35. package/src/queues/delayed-node-promotion.queue.ts +52 -15
  36. package/src/queues/document-processor.queue.ts +52 -77
  37. package/src/queues/memory-consolidation.queue.ts +47 -32
  38. package/src/queues/organization-learning.queue.ts +13 -4
  39. package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
  40. package/src/queues/plan-scheduler.queue.ts +107 -31
  41. package/src/queues/post-chat-memory.queue.ts +66 -24
  42. package/src/queues/queue-factory.ts +142 -52
  43. package/src/queues/standalone-worker.ts +39 -0
  44. package/src/queues/title-generation.queue.ts +54 -9
  45. package/src/redis/connection.ts +84 -32
  46. package/src/redis/index.ts +6 -8
  47. package/src/redis/org-memory-lock.ts +60 -27
  48. package/src/redis/redis-lease-lock.ts +200 -121
  49. package/src/redis/runtime-connection.ts +10 -0
  50. package/src/redis/stream-context.ts +84 -46
  51. package/src/runtime/agent-identity-overrides.ts +2 -2
  52. package/src/runtime/agent-runtime-policy.ts +4 -1
  53. package/src/runtime/agent-stream-helpers.ts +20 -9
  54. package/src/runtime/chat-run-orchestration.ts +102 -19
  55. package/src/runtime/chat-run-registry.ts +36 -2
  56. package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
  57. package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
  58. package/src/runtime/execution-plan-visibility.ts +2 -2
  59. package/src/runtime/execution-plan.ts +42 -15
  60. package/src/runtime/graph-designer.ts +11 -7
  61. package/src/runtime/helper-model.ts +135 -48
  62. package/src/runtime/index.ts +7 -7
  63. package/src/runtime/indexed-repositories-policy.ts +3 -3
  64. package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
  65. package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
  66. package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
  67. package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
  68. package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
  69. package/src/runtime/plugin-resolution.ts +144 -24
  70. package/src/runtime/plugin-types.ts +9 -1
  71. package/src/runtime/post-turn-side-effects.ts +197 -130
  72. package/src/runtime/retrieval-adapters.ts +38 -4
  73. package/src/runtime/runtime-config.ts +150 -61
  74. package/src/runtime/runtime-extensions.ts +21 -34
  75. package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
  76. package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
  77. package/src/runtime/social-chat/social-chat.ts +594 -0
  78. package/src/runtime/specialist-runner.ts +36 -10
  79. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
  80. package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
  81. package/src/runtime/thread-chat-helpers.ts +2 -2
  82. package/src/runtime/thread-plan-turn.ts +2 -1
  83. package/src/runtime/thread-turn-context.ts +172 -94
  84. package/src/runtime/turn-lifecycle.ts +93 -27
  85. package/src/services/agent-activity.service.ts +287 -203
  86. package/src/services/agent-executor.service.ts +329 -217
  87. package/src/services/artifact.service.ts +225 -148
  88. package/src/services/attachment.service.ts +137 -115
  89. package/src/services/autonomous-job.service.ts +888 -491
  90. package/src/services/chat-run-registry.service.ts +11 -1
  91. package/src/services/context-compaction.service.ts +136 -86
  92. package/src/services/document-chunk.service.ts +162 -90
  93. package/src/services/execution-plan/execution-plan-approval.ts +26 -0
  94. package/src/services/execution-plan/execution-plan-context.ts +29 -0
  95. package/src/services/execution-plan/execution-plan-graph.ts +256 -0
  96. package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
  97. package/src/services/execution-plan/execution-plan-spec.ts +75 -0
  98. package/src/services/execution-plan/execution-plan.service.ts +1041 -0
  99. package/src/services/feedback-loop.service.ts +132 -76
  100. package/src/services/global-orchestrator.service.ts +80 -170
  101. package/src/services/graph-full-routing.ts +182 -0
  102. package/src/services/index.ts +18 -21
  103. package/src/services/institutional-memory.service.ts +220 -123
  104. package/src/services/learned-skill.service.ts +364 -259
  105. package/src/services/memory/memory-conversation.ts +95 -0
  106. package/src/services/memory/memory-org-memory.ts +39 -0
  107. package/src/services/memory/memory-preseeded.ts +80 -0
  108. package/src/services/memory/memory-rerank.ts +297 -0
  109. package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
  110. package/src/services/memory/memory.service.ts +692 -0
  111. package/src/services/memory/rerank.service.ts +209 -0
  112. package/src/services/monitoring-window.service.ts +92 -70
  113. package/src/services/mutating-approval.service.ts +62 -53
  114. package/src/services/node-workspace.service.ts +141 -98
  115. package/src/services/notification.service.ts +17 -16
  116. package/src/services/organization-member.service.ts +120 -66
  117. package/src/services/organization.service.ts +144 -51
  118. package/src/services/ownership-dispatcher.service.ts +415 -264
  119. package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
  120. package/src/services/plan/plan-agent-query.service.ts +322 -0
  121. package/src/services/plan/plan-approval.service.ts +102 -0
  122. package/src/services/plan/plan-artifact.service.ts +60 -0
  123. package/src/services/plan/plan-builder.service.ts +76 -0
  124. package/src/services/plan/plan-checkpoint.service.ts +103 -0
  125. package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
  126. package/src/services/plan/plan-completion-side-effects.ts +175 -0
  127. package/src/services/plan/plan-coordination.service.ts +181 -0
  128. package/src/services/plan/plan-cycle.service.ts +398 -0
  129. package/src/services/plan/plan-deadline.service.ts +547 -0
  130. package/src/services/plan/plan-event-delivery.service.ts +261 -0
  131. package/src/services/plan/plan-executor-context.ts +35 -0
  132. package/src/services/plan/plan-executor-graph.ts +475 -0
  133. package/src/services/plan/plan-executor-helpers.ts +322 -0
  134. package/src/services/plan/plan-executor-persistence.ts +209 -0
  135. package/src/services/plan/plan-executor.service.ts +1654 -0
  136. package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
  137. package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
  138. package/src/services/plan/plan-run-serialization.ts +15 -0
  139. package/src/services/plan/plan-run.service.ts +644 -0
  140. package/src/services/plan/plan-scheduler.service.ts +385 -0
  141. package/src/services/plan/plan-template.service.ts +224 -0
  142. package/src/services/plan/plan-transaction-events.ts +33 -0
  143. package/src/services/plan/plan-validator.service.ts +907 -0
  144. package/src/services/plan/plan-workspace.service.ts +125 -0
  145. package/src/services/plugin-executor.service.ts +97 -68
  146. package/src/services/quality-metrics.service.ts +112 -94
  147. package/src/services/queue-job.service.ts +296 -230
  148. package/src/services/recent-activity-title.service.ts +65 -36
  149. package/src/services/recent-activity.service.ts +274 -259
  150. package/src/services/skill-resolver.service.ts +38 -12
  151. package/src/services/social-chat-history.service.ts +176 -125
  152. package/src/services/system-executor.service.ts +91 -61
  153. package/src/services/thread/thread-active-run.ts +203 -0
  154. package/src/services/thread/thread-bootstrap.ts +369 -0
  155. package/src/services/thread/thread-listing.ts +198 -0
  156. package/src/services/thread/thread-memory-block.ts +117 -0
  157. package/src/services/thread/thread-message.service.ts +363 -0
  158. package/src/services/thread/thread-record-store.ts +155 -0
  159. package/src/services/thread/thread-title.service.ts +74 -0
  160. package/src/services/thread/thread-turn-execution.ts +280 -0
  161. package/src/services/thread/thread-turn-message-context.ts +73 -0
  162. package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
  163. package/src/services/thread/thread-turn-streaming.ts +402 -0
  164. package/src/services/thread/thread-turn-tracing.ts +35 -0
  165. package/src/services/thread/thread-turn.ts +343 -0
  166. package/src/services/thread/thread.service.ts +335 -0
  167. package/src/services/user.service.ts +82 -32
  168. package/src/services/write-intent-validator.service.ts +63 -51
  169. package/src/storage/attachment-parser.ts +69 -27
  170. package/src/storage/attachment-storage.service.ts +331 -275
  171. package/src/storage/generated-document-storage.service.ts +66 -34
  172. package/src/system-agents/agent-result.ts +3 -1
  173. package/src/system-agents/context-compaction.agent.ts +2 -2
  174. package/src/system-agents/delegated-agent-factory.ts +159 -90
  175. package/src/system-agents/memory-reranker.agent.ts +2 -2
  176. package/src/system-agents/memory.agent.ts +2 -2
  177. package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
  178. package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
  179. package/src/system-agents/skill-extractor.agent.ts +2 -2
  180. package/src/system-agents/skill-manager.agent.ts +2 -2
  181. package/src/system-agents/thread-router.agent.ts +157 -113
  182. package/src/system-agents/title-generator.agent.ts +2 -2
  183. package/src/tools/execution-plan.tool.ts +220 -161
  184. package/src/tools/fetch-webpage.tool.ts +21 -17
  185. package/src/tools/firecrawl-client.ts +16 -6
  186. package/src/tools/index.ts +1 -0
  187. package/src/tools/memory-block.tool.ts +14 -6
  188. package/src/tools/plan-approval.tool.ts +49 -47
  189. package/src/tools/read-file-parts.tool.ts +44 -33
  190. package/src/tools/remember-memory.tool.ts +65 -45
  191. package/src/tools/search-web.tool.ts +26 -22
  192. package/src/tools/search.tool.ts +41 -29
  193. package/src/tools/team-think.tool.ts +124 -83
  194. package/src/tools/user-questions.tool.ts +4 -3
  195. package/src/tools/web-tool-shared.ts +6 -0
  196. package/src/utils/async.ts +17 -23
  197. package/src/utils/crypto.ts +21 -0
  198. package/src/utils/date-time.ts +40 -1
  199. package/src/utils/errors.ts +95 -16
  200. package/src/utils/hono-error-handler.ts +24 -39
  201. package/src/utils/index.ts +2 -1
  202. package/src/utils/null-proto-record.ts +41 -0
  203. package/src/utils/sse-keepalive.ts +124 -21
  204. package/src/workers/bootstrap.ts +186 -51
  205. package/src/workers/memory-consolidation.worker.ts +325 -237
  206. package/src/workers/organization-learning.worker.ts +50 -16
  207. package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
  208. package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
  209. package/src/workers/skill-extraction.runner.ts +176 -93
  210. package/src/workers/utils/file-section-chunker.ts +8 -10
  211. package/src/workers/utils/repo-structure-extractor.ts +349 -260
  212. package/src/workers/utils/repomix-file-sections.ts +2 -2
  213. package/src/workers/utils/thread-message-query.ts +97 -38
  214. package/src/workers/worker-utils.ts +56 -31
  215. package/src/config/debug-logger.ts +0 -47
  216. package/src/redis/connection-accessor.ts +0 -26
  217. package/src/runtime/context-compaction-runtime.ts +0 -87
  218. package/src/runtime/social-chat-agent-runner.ts +0 -118
  219. package/src/runtime/social-chat.ts +0 -516
  220. package/src/runtime/team-consultation-orchestrator.ts +0 -272
  221. package/src/services/adaptive-playbook.service.ts +0 -152
  222. package/src/services/artifact-provenance.service.ts +0 -172
  223. package/src/services/chat-attachments.service.ts +0 -17
  224. package/src/services/context-compaction-runtime.singleton.ts +0 -13
  225. package/src/services/execution-plan.service.ts +0 -1118
  226. package/src/services/memory.service.ts +0 -914
  227. package/src/services/plan-agent-heartbeat.service.ts +0 -136
  228. package/src/services/plan-agent-query.service.ts +0 -267
  229. package/src/services/plan-approval.service.ts +0 -83
  230. package/src/services/plan-artifact.service.ts +0 -50
  231. package/src/services/plan-builder.service.ts +0 -67
  232. package/src/services/plan-checkpoint.service.ts +0 -81
  233. package/src/services/plan-completion-side-effects.ts +0 -80
  234. package/src/services/plan-coordination.service.ts +0 -157
  235. package/src/services/plan-cycle.service.ts +0 -284
  236. package/src/services/plan-deadline.service.ts +0 -430
  237. package/src/services/plan-event-delivery.service.ts +0 -166
  238. package/src/services/plan-executor.service.ts +0 -1950
  239. package/src/services/plan-run.service.ts +0 -515
  240. package/src/services/plan-scheduler.service.ts +0 -240
  241. package/src/services/plan-template.service.ts +0 -177
  242. package/src/services/plan-validator.service.ts +0 -818
  243. package/src/services/plan-workspace.service.ts +0 -83
  244. package/src/services/rerank.service.ts +0 -156
  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