@lota-sdk/core 0.4.8 → 0.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/package.json +11 -12
  2. package/src/ai/embedding-cache.ts +96 -22
  3. package/src/ai-gateway/ai-gateway.ts +766 -223
  4. package/src/config/agent-defaults.ts +189 -75
  5. package/src/config/agent-types.ts +54 -4
  6. package/src/config/background-processing.ts +1 -1
  7. package/src/config/constants.ts +8 -2
  8. package/src/config/index.ts +0 -1
  9. package/src/config/logger.ts +299 -19
  10. package/src/config/thread-defaults.ts +40 -20
  11. package/src/create-runtime.ts +200 -449
  12. package/src/db/base.service.ts +52 -28
  13. package/src/db/cursor-pagination.ts +71 -30
  14. package/src/db/memory-query-builder.ts +2 -1
  15. package/src/db/memory-store.helpers.ts +4 -7
  16. package/src/db/memory-store.ts +868 -601
  17. package/src/db/memory.ts +396 -280
  18. package/src/db/record-id.ts +32 -10
  19. package/src/db/schema-fingerprint.ts +30 -12
  20. package/src/db/service-normalization.ts +288 -0
  21. package/src/db/service.ts +912 -779
  22. package/src/db/startup.ts +153 -68
  23. package/src/db/transaction-conflict.ts +15 -0
  24. package/src/effect/awaitable-effect.ts +96 -0
  25. package/src/effect/errors.ts +121 -0
  26. package/src/effect/helpers.ts +123 -0
  27. package/src/effect/index.ts +24 -0
  28. package/src/effect/layers.ts +238 -0
  29. package/src/effect/runtime-ref.ts +25 -0
  30. package/src/effect/runtime.ts +46 -0
  31. package/src/effect/services.ts +61 -0
  32. package/src/effect/zod.ts +43 -0
  33. package/src/embeddings/provider.ts +128 -83
  34. package/src/index.ts +48 -1
  35. package/src/openrouter/direct-provider.ts +11 -35
  36. package/src/queues/autonomous-job.queue.ts +117 -73
  37. package/src/queues/context-compaction.queue.ts +50 -17
  38. package/src/queues/delayed-node-promotion.queue.ts +46 -17
  39. package/src/queues/document-processor.queue.ts +52 -77
  40. package/src/queues/memory-consolidation.queue.ts +47 -32
  41. package/src/queues/organization-learning.queue.ts +26 -4
  42. package/src/queues/plan-agent-heartbeat.queue.ts +71 -24
  43. package/src/queues/plan-scheduler.queue.ts +97 -33
  44. package/src/queues/post-chat-memory.queue.ts +56 -26
  45. package/src/queues/queue-factory.ts +227 -59
  46. package/src/queues/standalone-worker.ts +39 -0
  47. package/src/queues/title-generation.queue.ts +45 -11
  48. package/src/redis/connection.ts +182 -113
  49. package/src/redis/index.ts +6 -8
  50. package/src/redis/org-memory-lock.ts +60 -27
  51. package/src/redis/redis-lease-lock.ts +200 -121
  52. package/src/redis/runtime-connection.ts +20 -0
  53. package/src/redis/stream-context.ts +92 -46
  54. package/src/runtime/agent-identity-overrides.ts +2 -2
  55. package/src/runtime/agent-runtime-policy.ts +5 -2
  56. package/src/runtime/agent-stream-helpers.ts +24 -9
  57. package/src/runtime/chat-run-orchestration.ts +102 -19
  58. package/src/runtime/chat-run-registry.ts +36 -2
  59. package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
  60. package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +161 -94
  61. package/src/runtime/domain-layer.ts +192 -0
  62. package/src/runtime/execution-plan-visibility.ts +2 -2
  63. package/src/runtime/execution-plan.ts +42 -15
  64. package/src/runtime/graph-designer.ts +16 -4
  65. package/src/runtime/helper-model.ts +139 -48
  66. package/src/runtime/index.ts +7 -8
  67. package/src/runtime/indexed-repositories-policy.ts +3 -3
  68. package/src/runtime/{memory-block.ts → memory/memory-block.ts} +50 -36
  69. package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
  70. package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +54 -67
  71. package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
  72. package/src/runtime/memory/memory-scope.ts +53 -0
  73. package/src/runtime/plugin-resolution.ts +124 -25
  74. package/src/runtime/plugin-types.ts +9 -1
  75. package/src/runtime/post-turn-side-effects.ts +177 -130
  76. package/src/runtime/retrieval-adapters.ts +40 -6
  77. package/src/runtime/runtime-accessors.ts +92 -0
  78. package/src/runtime/runtime-config.ts +150 -61
  79. package/src/runtime/runtime-extensions.ts +23 -25
  80. package/src/runtime/runtime-lifecycle.ts +124 -0
  81. package/src/runtime/runtime-services.ts +386 -0
  82. package/src/runtime/runtime-token.ts +47 -0
  83. package/src/runtime/social-chat/social-chat-agent-runner.ts +159 -0
  84. package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +51 -20
  85. package/src/runtime/social-chat/social-chat.ts +630 -0
  86. package/src/runtime/specialist-runner.ts +36 -10
  87. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +433 -0
  88. package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
  89. package/src/runtime/thread-chat-helpers.ts +2 -2
  90. package/src/runtime/thread-plan-turn.ts +2 -1
  91. package/src/runtime/thread-turn-context.ts +183 -111
  92. package/src/runtime/turn-lifecycle.ts +93 -27
  93. package/src/services/agent-activity.service.ts +287 -203
  94. package/src/services/agent-executor.service.ts +253 -149
  95. package/src/services/artifact.service.ts +231 -149
  96. package/src/services/attachment.service.ts +171 -115
  97. package/src/services/autonomous-job.service.ts +890 -491
  98. package/src/services/background-work.service.ts +54 -0
  99. package/src/services/chat-run-registry.service.ts +13 -1
  100. package/src/services/context-compaction.service.ts +136 -86
  101. package/src/services/document-chunk.service.ts +151 -88
  102. package/src/services/execution-plan/execution-plan-approval.ts +26 -0
  103. package/src/services/execution-plan/execution-plan-context.ts +29 -0
  104. package/src/services/execution-plan/execution-plan-graph.ts +278 -0
  105. package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
  106. package/src/services/execution-plan/execution-plan-spec.ts +75 -0
  107. package/src/services/execution-plan/execution-plan.service.ts +1041 -0
  108. package/src/services/feedback-loop.service.ts +132 -76
  109. package/src/services/global-orchestrator.service.ts +101 -168
  110. package/src/services/graph-full-routing.ts +193 -0
  111. package/src/services/index.ts +19 -21
  112. package/src/services/institutional-memory.service.ts +213 -125
  113. package/src/services/learned-skill.service.ts +368 -260
  114. package/src/services/memory/memory-conversation.ts +95 -0
  115. package/src/services/memory/memory-errors.ts +27 -0
  116. package/src/services/memory/memory-org-memory.ts +50 -0
  117. package/src/services/memory/memory-preseeded.ts +86 -0
  118. package/src/services/memory/memory-rerank.ts +297 -0
  119. package/src/services/{memory-utils.ts → memory/memory-utils.ts} +6 -5
  120. package/src/services/memory/memory.service.ts +674 -0
  121. package/src/services/memory/rerank.service.ts +201 -0
  122. package/src/services/monitoring-window.service.ts +92 -70
  123. package/src/services/mutating-approval.service.ts +62 -53
  124. package/src/services/node-workspace.service.ts +141 -98
  125. package/src/services/notification.service.ts +29 -16
  126. package/src/services/organization-member.service.ts +120 -66
  127. package/src/services/organization.service.ts +153 -77
  128. package/src/services/ownership-dispatcher.service.ts +456 -263
  129. package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
  130. package/src/services/plan/plan-agent-query.service.ts +322 -0
  131. package/src/services/{plan-approval.service.ts → plan/plan-approval.service.ts} +45 -22
  132. package/src/services/plan/plan-artifact.service.ts +60 -0
  133. package/src/services/plan/plan-builder.service.ts +76 -0
  134. package/src/services/plan/plan-checkpoint.service.ts +103 -0
  135. package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
  136. package/src/services/plan/plan-completion-side-effects.ts +169 -0
  137. package/src/services/plan/plan-coordination.service.ts +181 -0
  138. package/src/services/plan/plan-cycle.service.ts +405 -0
  139. package/src/services/plan/plan-deadline.service.ts +533 -0
  140. package/src/services/plan/plan-event-delivery.service.ts +266 -0
  141. package/src/services/plan/plan-executor-context.ts +35 -0
  142. package/src/services/plan/plan-executor-graph.ts +522 -0
  143. package/src/services/plan/plan-executor-helpers.ts +307 -0
  144. package/src/services/plan/plan-executor-persistence.ts +209 -0
  145. package/src/services/plan/plan-executor.service.ts +1737 -0
  146. package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
  147. package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
  148. package/src/services/plan/plan-run-serialization.ts +15 -0
  149. package/src/services/plan/plan-run.service.ts +637 -0
  150. package/src/services/plan/plan-scheduler.service.ts +379 -0
  151. package/src/services/plan/plan-template.service.ts +224 -0
  152. package/src/services/plan/plan-transaction-events.ts +36 -0
  153. package/src/services/plan/plan-validator.service.ts +907 -0
  154. package/src/services/plan/plan-workspace.service.ts +131 -0
  155. package/src/services/plugin-executor.service.ts +102 -68
  156. package/src/services/quality-metrics.service.ts +112 -94
  157. package/src/services/queue-job.service.ts +288 -231
  158. package/src/services/recent-activity-title.service.ts +73 -36
  159. package/src/services/recent-activity.service.ts +274 -259
  160. package/src/services/skill-resolver.service.ts +38 -12
  161. package/src/services/social-chat-history.service.ts +190 -122
  162. package/src/services/system-executor.service.ts +96 -61
  163. package/src/services/thread/thread-active-run.ts +203 -0
  164. package/src/services/thread/thread-bootstrap.ts +385 -0
  165. package/src/services/thread/thread-listing.ts +199 -0
  166. package/src/services/thread/thread-memory-block.ts +130 -0
  167. package/src/services/thread/thread-message.service.ts +379 -0
  168. package/src/services/thread/thread-record-store.ts +155 -0
  169. package/src/services/thread/thread-title.service.ts +74 -0
  170. package/src/services/thread/thread-turn-execution.ts +280 -0
  171. package/src/services/thread/thread-turn-message-context.ts +73 -0
  172. package/src/services/thread/thread-turn-preparation.service.ts +1148 -0
  173. package/src/services/thread/thread-turn-streaming.ts +403 -0
  174. package/src/services/thread/thread-turn-tracing.ts +35 -0
  175. package/src/services/thread/thread-turn.ts +376 -0
  176. package/src/services/thread/thread.service.ts +344 -0
  177. package/src/services/user.service.ts +82 -32
  178. package/src/services/write-intent-validator.service.ts +63 -51
  179. package/src/storage/attachment-parser.ts +69 -27
  180. package/src/storage/attachment-storage.service.ts +334 -275
  181. package/src/storage/generated-document-storage.service.ts +66 -34
  182. package/src/system-agents/agent-result.ts +3 -1
  183. package/src/system-agents/context-compaction.agent.ts +3 -3
  184. package/src/system-agents/delegated-agent-factory.ts +159 -90
  185. package/src/system-agents/helper-agent-options.ts +1 -1
  186. package/src/system-agents/memory-reranker.agent.ts +3 -3
  187. package/src/system-agents/memory.agent.ts +3 -3
  188. package/src/system-agents/recent-activity-title-refiner.agent.ts +3 -3
  189. package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -3
  190. package/src/system-agents/skill-extractor.agent.ts +3 -3
  191. package/src/system-agents/skill-manager.agent.ts +3 -3
  192. package/src/system-agents/thread-router.agent.ts +157 -113
  193. package/src/system-agents/title-generator.agent.ts +3 -3
  194. package/src/tools/execution-plan.tool.ts +241 -171
  195. package/src/tools/fetch-webpage.tool.ts +29 -18
  196. package/src/tools/firecrawl-client.ts +26 -6
  197. package/src/tools/index.ts +1 -0
  198. package/src/tools/memory-block.tool.ts +14 -6
  199. package/src/tools/plan-approval.tool.ts +57 -47
  200. package/src/tools/read-file-parts.tool.ts +44 -33
  201. package/src/tools/remember-memory.tool.ts +65 -45
  202. package/src/tools/search-web.tool.ts +33 -22
  203. package/src/tools/search.tool.ts +41 -29
  204. package/src/tools/team-think.tool.ts +125 -84
  205. package/src/tools/user-questions.tool.ts +4 -3
  206. package/src/tools/web-tool-shared.ts +6 -0
  207. package/src/utils/async.ts +25 -22
  208. package/src/utils/crypto.ts +21 -0
  209. package/src/utils/date-time.ts +40 -1
  210. package/src/utils/errors.ts +111 -20
  211. package/src/utils/hono-error-handler.ts +24 -39
  212. package/src/utils/index.ts +2 -1
  213. package/src/utils/null-proto-record.ts +41 -0
  214. package/src/utils/sse-keepalive.ts +124 -21
  215. package/src/workers/bootstrap.ts +164 -52
  216. package/src/workers/memory-consolidation.worker.ts +325 -237
  217. package/src/workers/organization-learning.worker.ts +50 -16
  218. package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
  219. package/src/workers/regular-chat-memory-digest.runner.ts +185 -114
  220. package/src/workers/skill-extraction.runner.ts +176 -93
  221. package/src/workers/utils/file-section-chunker.ts +8 -10
  222. package/src/workers/utils/repo-structure-extractor.ts +349 -260
  223. package/src/workers/utils/repomix-file-sections.ts +2 -2
  224. package/src/workers/utils/thread-message-query.ts +97 -38
  225. package/src/workers/worker-utils.ts +74 -31
  226. package/src/config/debug-logger.ts +0 -47
  227. package/src/config/search.ts +0 -3
  228. package/src/redis/connection-accessor.ts +0 -26
  229. package/src/runtime/agent-types.ts +0 -1
  230. package/src/runtime/context-compaction-runtime.ts +0 -87
  231. package/src/runtime/memory-scope.ts +0 -43
  232. package/src/runtime/social-chat-agent-runner.ts +0 -118
  233. package/src/runtime/social-chat.ts +0 -516
  234. package/src/runtime/team-consultation-orchestrator.ts +0 -272
  235. package/src/services/adaptive-playbook.service.ts +0 -152
  236. package/src/services/artifact-provenance.service.ts +0 -172
  237. package/src/services/chat-attachments.service.ts +0 -17
  238. package/src/services/context-compaction-runtime.singleton.ts +0 -13
  239. package/src/services/execution-plan.service.ts +0 -1118
  240. package/src/services/memory.service.ts +0 -914
  241. package/src/services/plan-agent-heartbeat.service.ts +0 -136
  242. package/src/services/plan-agent-query.service.ts +0 -267
  243. package/src/services/plan-artifact.service.ts +0 -50
  244. package/src/services/plan-builder.service.ts +0 -67
  245. package/src/services/plan-checkpoint.service.ts +0 -81
  246. package/src/services/plan-completion-side-effects.ts +0 -80
  247. package/src/services/plan-coordination.service.ts +0 -157
  248. package/src/services/plan-cycle.service.ts +0 -284
  249. package/src/services/plan-deadline.service.ts +0 -430
  250. package/src/services/plan-event-delivery.service.ts +0 -166
  251. package/src/services/plan-executor.service.ts +0 -1950
  252. package/src/services/plan-run.service.ts +0 -515
  253. package/src/services/plan-scheduler.service.ts +0 -240
  254. package/src/services/plan-template.service.ts +0 -177
  255. package/src/services/plan-validator.service.ts +0 -818
  256. package/src/services/plan-workspace.service.ts +0 -83
  257. package/src/services/rerank.service.ts +0 -156
  258. package/src/services/thread-message.service.ts +0 -275
  259. package/src/services/thread-plan-registry.service.ts +0 -22
  260. package/src/services/thread-title.service.ts +0 -39
  261. package/src/services/thread-turn-preparation.service.ts +0 -1147
  262. package/src/services/thread-turn.ts +0 -172
  263. package/src/services/thread.service.ts +0 -869
  264. package/src/utils/env.ts +0 -8
  265. /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
  266. /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
  267. /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
  268. /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
  269. /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
  270. /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
  271. /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
  272. /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
@@ -0,0 +1,278 @@
1
+ import type { PlanEventRecord, PlanNodeRunRecord, PlanNodeSpecRecord, PlanSpecRecord } from '@lota-sdk/shared'
2
+ import {
3
+ PlanCheckpointSchema,
4
+ PlanEventSchema,
5
+ PlanNodeRunSchema,
6
+ PlanNodeSpecRecordSchema,
7
+ PlanRunSchema,
8
+ } from '@lota-sdk/shared'
9
+ import { Effect } from 'effect'
10
+ import { RecordId } from 'surrealdb'
11
+ import type { z } from 'zod'
12
+
13
+ import type { RecordIdInput } from '../../db/record-id'
14
+ import { ensureRecordId, recordIdToString } from '../../db/record-id'
15
+ import type { DatabaseTransaction } from '../../db/service'
16
+ import { TABLES } from '../../db/tables'
17
+ import { ServiceError } from '../../effect/errors'
18
+ import { runPromise } from '../../effect/runtime'
19
+ import { nowDate } from '../../utils/date-time'
20
+ import type { CompiledPlanNode } from '../plan/plan-compiler.service'
21
+ import type { syncRunGraph } from '../plan/plan-executor-graph'
22
+ import { toRunData } from '../plan/plan-run-data'
23
+
24
+ function parseRowOrFail<TSchema extends z.ZodTypeAny>(
25
+ schema: TSchema,
26
+ value: unknown,
27
+ operation: string,
28
+ ): Effect.Effect<z.infer<TSchema>, ServiceError> {
29
+ return Effect.try({
30
+ try: () => schema.parse(value) as z.infer<TSchema>,
31
+ catch: (cause) => new ServiceError({ message: `Failed to parse row for ${operation}.`, cause }),
32
+ })
33
+ }
34
+
35
+ type SyncRunGraphParams = Parameters<typeof syncRunGraph>[1]
36
+ type SyncRunGraphResult = Awaited<ReturnType<typeof syncRunGraph>>
37
+
38
+ interface ExecutionPlanGraphExecutor {
39
+ syncRunGraph(params: SyncRunGraphParams): Promise<SyncRunGraphResult>
40
+ }
41
+
42
+ function buildNodeSpecCreateContent(compiledNode: CompiledPlanNode, planSpecId: RecordIdInput) {
43
+ return {
44
+ planSpecId: ensureRecordId(planSpecId, TABLES.PLAN_SPEC),
45
+ nodeId: compiledNode.node.id,
46
+ position: compiledNode.position,
47
+ type: compiledNode.node.type,
48
+ label: compiledNode.node.label,
49
+ owner: compiledNode.node.owner,
50
+ objective: compiledNode.node.objective,
51
+ instructions: compiledNode.node.instructions,
52
+ ...(compiledNode.node.inputSchemaRef ? { inputSchemaRef: compiledNode.node.inputSchemaRef } : {}),
53
+ ...(compiledNode.node.outputSchemaRef ? { outputSchemaRef: compiledNode.node.outputSchemaRef } : {}),
54
+ deliverables: [...compiledNode.node.deliverables],
55
+ successCriteria: [...compiledNode.node.successCriteria],
56
+ completionChecks: [...compiledNode.node.completionChecks],
57
+ retryPolicy: { ...compiledNode.node.retryPolicy, retryOn: [...compiledNode.node.retryPolicy.retryOn] },
58
+ failurePolicy: [...compiledNode.node.failurePolicy],
59
+ ...(compiledNode.node.timeoutMs ? { timeoutMs: compiledNode.node.timeoutMs } : {}),
60
+ toolPolicy: { allow: [...compiledNode.node.toolPolicy.allow], deny: [...compiledNode.node.toolPolicy.deny] },
61
+ contextPolicy: {
62
+ retrievalScopes: [...compiledNode.node.contextPolicy.retrievalScopes],
63
+ attachmentPolicy: compiledNode.node.contextPolicy.attachmentPolicy,
64
+ webPolicy: compiledNode.node.contextPolicy.webPolicy,
65
+ },
66
+ executionVisibility: compiledNode.node.executionVisibility,
67
+ ...(compiledNode.node.schedule ? { schedule: compiledNode.node.schedule } : {}),
68
+ ...(compiledNode.node.deadline ? { deadline: compiledNode.node.deadline } : {}),
69
+ ...(compiledNode.node.escalation ? { escalation: compiledNode.node.escalation } : {}),
70
+ ...(compiledNode.node.monitoringConfig ? { monitoringConfig: compiledNode.node.monitoringConfig } : {}),
71
+ ...(compiledNode.node.delayAfterPredecessorMs
72
+ ? { delayAfterPredecessorMs: compiledNode.node.delayAfterPredecessorMs }
73
+ : {}),
74
+ ...(compiledNode.node.deliberationConfig ? { deliberationConfig: compiledNode.node.deliberationConfig } : {}),
75
+ upstreamNodeIds: [...compiledNode.upstreamNodeIds],
76
+ downstreamNodeIds: [...compiledNode.downstreamNodeIds],
77
+ }
78
+ }
79
+
80
+ function buildNodeRunCreateContent(runId: RecordIdInput, planSpecId: RecordIdInput, nodeSpec: PlanNodeSpecRecord) {
81
+ return {
82
+ runId: ensureRecordId(runId, TABLES.PLAN_RUN),
83
+ planSpecId: ensureRecordId(planSpecId, TABLES.PLAN_SPEC),
84
+ nodeId: nodeSpec.nodeId,
85
+ status: 'pending' as const,
86
+ attemptCount: 0,
87
+ retryCount: 0,
88
+ }
89
+ }
90
+
91
+ function createNodeSpecs(tx: DatabaseTransaction, planSpecId: RecordIdInput, nodes: CompiledPlanNode[]) {
92
+ return Effect.gen(function* () {
93
+ const createdRecords: PlanNodeSpecRecord[] = []
94
+
95
+ // Sequential: SurrealDB transactions require ordered operations
96
+ for (const compiledNode of nodes) {
97
+ const nodeSpecId = new RecordId(TABLES.PLAN_NODE_SPEC, Bun.randomUUIDv7())
98
+ const created = yield* tx
99
+ .create(nodeSpecId)
100
+ .content(buildNodeSpecCreateContent(compiledNode, planSpecId))
101
+ .output('after')
102
+ createdRecords.push(yield* parseRowOrFail(PlanNodeSpecRecordSchema, created, 'createNodeSpecs'))
103
+ }
104
+
105
+ return createdRecords
106
+ })
107
+ }
108
+
109
+ function createNodeRuns(
110
+ tx: DatabaseTransaction,
111
+ runId: RecordIdInput,
112
+ planSpecId: RecordIdInput,
113
+ nodeSpecs: PlanNodeSpecRecord[],
114
+ ) {
115
+ return Effect.gen(function* () {
116
+ const createdNodeRuns: PlanNodeRunRecord[] = []
117
+
118
+ // Sequential: SurrealDB transactions require ordered operations
119
+ for (const nodeSpec of nodeSpecs) {
120
+ const nodeRunId = new RecordId(TABLES.PLAN_NODE_RUN, Bun.randomUUIDv7())
121
+ const created = yield* tx
122
+ .create(nodeRunId)
123
+ .content(buildNodeRunCreateContent(runId, planSpecId, nodeSpec))
124
+ .output('after')
125
+ createdNodeRuns.push(yield* parseRowOrFail(PlanNodeRunSchema, created, 'createNodeRuns'))
126
+ }
127
+
128
+ return createdNodeRuns
129
+ })
130
+ }
131
+
132
+ export function createInitializedRunGraph(params: {
133
+ tx: DatabaseTransaction
134
+ runId: RecordIdInput
135
+ spec: PlanSpecRecord
136
+ organizationId: RecordIdInput
137
+ threadId: RecordIdInput
138
+ sourceThreadId?: RecordIdInput
139
+ leadAgentId: string
140
+ createdByAgentId?: string
141
+ requireApproval: boolean
142
+ nodes: CompiledPlanNode[]
143
+ emittedEvents: PlanEventRecord[]
144
+ createdEventType: 'plan-created' | 'plan-replaced'
145
+ createdEventMessage: string
146
+ createdEventDetail: Record<string, unknown>
147
+ checkpointReason: 'plan-created' | 'plan-replaced'
148
+ runPatch?: { replacedRunId?: RecordIdInput }
149
+ planExecutor: ExecutionPlanGraphExecutor
150
+ }) {
151
+ return runPromise(
152
+ Effect.gen(function* () {
153
+ const nodeSpecs = yield* createNodeSpecs(params.tx, params.spec.id, params.nodes)
154
+ const runRaw = yield* params.tx
155
+ .create(ensureRecordId(params.runId, TABLES.PLAN_RUN))
156
+ .content({
157
+ planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
158
+ organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
159
+ threadId: ensureRecordId(params.threadId, TABLES.THREAD),
160
+ ...(params.sourceThreadId ? { sourceThreadId: ensureRecordId(params.sourceThreadId, TABLES.THREAD) } : {}),
161
+ leadAgentId: params.leadAgentId,
162
+ ...(params.createdByAgentId ? { createdByAgentId: params.createdByAgentId } : {}),
163
+ status: params.requireApproval ? 'pending-approval' : 'running',
164
+ readyNodeIds: [],
165
+ failureCount: 0,
166
+ ...(params.runPatch?.replacedRunId
167
+ ? { replacedRunId: ensureRecordId(params.runPatch.replacedRunId, TABLES.PLAN_RUN) }
168
+ : {}),
169
+ ...(params.requireApproval ? {} : { startedAt: nowDate() }),
170
+ })
171
+ .output('after')
172
+ const run = yield* parseRowOrFail(PlanRunSchema, runRaw, 'createInitializedRunGraph:run')
173
+
174
+ const nodeRuns = yield* createNodeRuns(params.tx, run.id, params.spec.id, nodeSpecs)
175
+ const synced = params.requireApproval
176
+ ? { run, nodeRuns }
177
+ : yield* Effect.tryPromise(() =>
178
+ params.planExecutor.syncRunGraph({
179
+ tx: params.tx,
180
+ run,
181
+ spec: params.spec,
182
+ nodeSpecs,
183
+ nodeRuns,
184
+ artifacts: [],
185
+ emittedBy: params.leadAgentId,
186
+ capturedEvents: params.emittedEvents,
187
+ }),
188
+ )
189
+
190
+ const event = yield* params.tx
191
+ .create(new RecordId(TABLES.PLAN_EVENT, Bun.randomUUIDv7()))
192
+ .content({
193
+ planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
194
+ runId: ensureRecordId(synced.run.id, TABLES.PLAN_RUN),
195
+ eventType: params.createdEventType,
196
+ message: params.createdEventMessage,
197
+ emittedBy: params.leadAgentId,
198
+ detail: { ...params.createdEventDetail, nodeCount: nodeSpecs.length },
199
+ })
200
+ .output('after')
201
+ params.emittedEvents.push(yield* parseRowOrFail(PlanEventSchema, event, 'createInitializedRunGraph:createdEvent'))
202
+
203
+ if (params.requireApproval) {
204
+ const pendingApprovalEvent = yield* params.tx
205
+ .create(new RecordId(TABLES.PLAN_EVENT, Bun.randomUUIDv7()))
206
+ .content({
207
+ planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
208
+ runId: ensureRecordId(synced.run.id, TABLES.PLAN_RUN),
209
+ eventType: 'plan-pending-approval',
210
+ toStatus: synced.run.status,
211
+ message: `Execution plan "${params.spec.title}" is pending approval.`,
212
+ emittedBy: params.leadAgentId,
213
+ detail: { ...params.createdEventDetail, nodeCount: nodeSpecs.length },
214
+ })
215
+ .output('after')
216
+ params.emittedEvents.push(
217
+ yield* parseRowOrFail(
218
+ PlanEventSchema,
219
+ pendingApprovalEvent,
220
+ 'createInitializedRunGraph:pendingApprovalEvent',
221
+ ),
222
+ )
223
+ }
224
+
225
+ const checkpointRaw = yield* params.tx
226
+ .create(new RecordId(TABLES.PLAN_CHECKPOINT, Bun.randomUUIDv7()))
227
+ .content({
228
+ runId: ensureRecordId(synced.run.id, TABLES.PLAN_RUN),
229
+ sequence: 1,
230
+ runStatus: synced.run.status,
231
+ readyNodeIds: [...synced.run.readyNodeIds],
232
+ activeNodeIds: synced.run.currentNodeId ? [synced.run.currentNodeId] : [],
233
+ artifactIds: [],
234
+ lastCompletedNodeIds: synced.nodeRuns
235
+ .filter((nodeRun) => nodeRun.status === 'completed' || nodeRun.status === 'partial')
236
+ .map((nodeRun) => nodeRun.nodeId),
237
+ snapshot: {
238
+ reason: params.checkpointReason,
239
+ currentNodeId: synced.run.currentNodeId,
240
+ waitingNodeId: synced.run.waitingNodeId,
241
+ readyNodeIds: synced.run.readyNodeIds,
242
+ },
243
+ })
244
+ .output('after')
245
+ const checkpoint = yield* parseRowOrFail(
246
+ PlanCheckpointSchema,
247
+ checkpointRaw,
248
+ 'createInitializedRunGraph:checkpoint',
249
+ )
250
+
251
+ const updatedRunRaw = yield* params.tx
252
+ .update(ensureRecordId(synced.run.id, TABLES.PLAN_RUN))
253
+ .content(toRunData(synced.run, { lastCheckpointId: checkpoint.id }))
254
+ .output('after')
255
+ const updatedRun = yield* parseRowOrFail(PlanRunSchema, updatedRunRaw, 'createInitializedRunGraph:updatedRun')
256
+
257
+ const checkpointEvent = yield* params.tx
258
+ .create(new RecordId(TABLES.PLAN_EVENT, Bun.randomUUIDv7()))
259
+ .content({
260
+ planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
261
+ runId: ensureRecordId(updatedRun.id, TABLES.PLAN_RUN),
262
+ eventType: 'checkpoint-saved',
263
+ message: 'Saved checkpoint 1.',
264
+ emittedBy: 'system',
265
+ detail: {
266
+ checkpointId: recordIdToString(checkpoint.id, TABLES.PLAN_CHECKPOINT),
267
+ reason: params.checkpointReason,
268
+ },
269
+ })
270
+ .output('after')
271
+ params.emittedEvents.push(
272
+ yield* parseRowOrFail(PlanEventSchema, checkpointEvent, 'createInitializedRunGraph:checkpointEvent'),
273
+ )
274
+
275
+ return updatedRun
276
+ }),
277
+ )
278
+ }
@@ -0,0 +1,84 @@
1
+ import type { PlanRunRecord } from '@lota-sdk/shared'
2
+ import { PlanRunSchema } from '@lota-sdk/shared'
3
+ import { Schema, Effect } from 'effect'
4
+
5
+ import type { RecordIdInput } from '../../db/record-id'
6
+ import { ensureRecordId } from '../../db/record-id'
7
+ import type { SurrealDBService } from '../../db/service'
8
+ import { TABLES } from '../../db/tables'
9
+ import { runPromise } from '../../effect/runtime'
10
+ import { toDatabaseDateTime } from '../../utils/date-time'
11
+ import { toRunData } from '../plan/plan-run-data'
12
+ import type { makePlanRunService } from '../plan/plan-run.service'
13
+ import type { makePlanSchedulerService } from '../plan/plan-scheduler.service'
14
+
15
+ class PlanScheduleAttachError extends Schema.TaggedErrorClass<PlanScheduleAttachError>()('PlanScheduleAttachError', {
16
+ cause: Schema.String,
17
+ }) {}
18
+
19
+ function toPlanScheduleAttachError(operation: string, cause: unknown) {
20
+ const detail = cause instanceof Error ? cause.message : String(cause)
21
+ return new PlanScheduleAttachError({ cause: `${operation}: ${detail}` })
22
+ }
23
+
24
+ function attachPlanScheduleIfNeededEffect(params: {
25
+ db: SurrealDBService
26
+ planRunService: ReturnType<typeof makePlanRunService>
27
+ planSchedulerService: ReturnType<typeof makePlanSchedulerService>
28
+ organizationId: RecordIdInput
29
+ threadId: RecordIdInput
30
+ runId: RecordIdInput
31
+ planSpecId: RecordIdInput
32
+ }) {
33
+ return Effect.gen(function* () {
34
+ const [run, spec] = yield* Effect.all([
35
+ params.planRunService
36
+ .getRunById(params.runId)
37
+ .pipe(Effect.mapError((cause) => toPlanScheduleAttachError('get-run-by-id', cause))),
38
+ params.planRunService
39
+ .getPlanSpecById(params.planSpecId)
40
+ .pipe(Effect.mapError((cause) => toPlanScheduleAttachError('get-plan-spec-by-id', cause))),
41
+ ])
42
+
43
+ const scheduleSpec = spec.schedule
44
+ if (!scheduleSpec || run.scheduleId) {
45
+ return run
46
+ }
47
+
48
+ const schedule = yield* params.planSchedulerService
49
+ .createSchedule({
50
+ organizationId: params.organizationId,
51
+ threadId: params.threadId,
52
+ planSpecId: params.planSpecId,
53
+ runId: params.runId,
54
+ scheduleSpec,
55
+ })
56
+ .pipe(Effect.mapError((cause) => toPlanScheduleAttachError('create-schedule', cause)))
57
+
58
+ const updatedRun = yield* params.db
59
+ .update(
60
+ TABLES.PLAN_RUN,
61
+ ensureRecordId(params.runId, TABLES.PLAN_RUN),
62
+ toRunData(run, {
63
+ scheduleId: schedule.id,
64
+ scheduledAt: schedule.nextFireAt ? toDatabaseDateTime(schedule.nextFireAt) : undefined,
65
+ }),
66
+ PlanRunSchema,
67
+ )
68
+ .pipe(Effect.mapError((cause) => toPlanScheduleAttachError('attach-plan-schedule', cause)))
69
+
70
+ return updatedRun ?? run
71
+ })
72
+ }
73
+
74
+ export function attachPlanScheduleIfNeeded(params: {
75
+ db: SurrealDBService
76
+ planRunService: ReturnType<typeof makePlanRunService>
77
+ planSchedulerService: ReturnType<typeof makePlanSchedulerService>
78
+ organizationId: RecordIdInput
79
+ threadId: RecordIdInput
80
+ runId: RecordIdInput
81
+ planSpecId: RecordIdInput
82
+ }): Promise<PlanRunRecord> {
83
+ return runPromise(attachPlanScheduleIfNeededEffect(params))
84
+ }
@@ -0,0 +1,75 @@
1
+ import type { PlanDraft, PlanSpecRecord } from '@lota-sdk/shared'
2
+
3
+ import type { RecordIdInput } from '../../db/record-id'
4
+ import { ensureRecordId } from '../../db/record-id'
5
+ import { TABLES } from '../../db/tables'
6
+ import { nowDate, toDatabaseDateTime } from '../../utils/date-time'
7
+
8
+ export function toSpecData(
9
+ spec: PlanSpecRecord,
10
+ patch: Partial<PlanSpecRecord> & { replacedSpecId?: RecordIdInput | null },
11
+ ) {
12
+ return {
13
+ organizationId: ensureRecordId(spec.organizationId, TABLES.ORGANIZATION),
14
+ threadId: ensureRecordId(spec.threadId, TABLES.THREAD),
15
+ title: patch.title ?? spec.title,
16
+ objective: patch.objective ?? spec.objective,
17
+ version: patch.version ?? spec.version,
18
+ status: patch.status ?? spec.status,
19
+ leadAgentId: patch.leadAgentId ?? spec.leadAgentId,
20
+ schemaRegistry: patch.schemaRegistry ? structuredClone(patch.schemaRegistry) : structuredClone(spec.schemaRegistry),
21
+ edges: patch.edges ? [...patch.edges] : [...spec.edges],
22
+ entryNodeIds: patch.entryNodeIds ? [...patch.entryNodeIds] : [...spec.entryNodeIds],
23
+ defaultExecutionVisibility: patch.defaultExecutionVisibility ?? spec.defaultExecutionVisibility,
24
+ executionMode: patch.executionMode ?? spec.executionMode,
25
+ ...(patch.schedule !== undefined ? { schedule: patch.schedule } : spec.schedule ? { schedule: spec.schedule } : {}),
26
+ ...(patch.dependencies !== undefined
27
+ ? { dependencies: patch.dependencies }
28
+ : spec.dependencies
29
+ ? { dependencies: spec.dependencies }
30
+ : {}),
31
+ ...(spec.contextEnrichments ? { contextEnrichments: spec.contextEnrichments } : {}),
32
+ ...(patch.replacedSpecId
33
+ ? { replacedSpecId: ensureRecordId(patch.replacedSpecId, TABLES.PLAN_SPEC) }
34
+ : spec.replacedSpecId
35
+ ? { replacedSpecId: ensureRecordId(spec.replacedSpecId, TABLES.PLAN_SPEC) }
36
+ : {}),
37
+ ...(patch.compiledAt !== undefined
38
+ ? { compiledAt: toDatabaseDateTime(patch.compiledAt) }
39
+ : spec.compiledAt
40
+ ? { compiledAt: toDatabaseDateTime(spec.compiledAt) }
41
+ : {}),
42
+ }
43
+ }
44
+
45
+ export function buildCompiledSpecCreateData(params: {
46
+ organizationId: RecordIdInput
47
+ threadId: RecordIdInput
48
+ leadAgentId: string
49
+ compiled: { draft: PlanDraft }
50
+ version: number
51
+ replacedSpecId?: RecordIdInput
52
+ contextEnrichments?: PlanSpecRecord['contextEnrichments']
53
+ }) {
54
+ return {
55
+ organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
56
+ threadId: ensureRecordId(params.threadId, TABLES.THREAD),
57
+ title: params.compiled.draft.title,
58
+ objective: params.compiled.draft.objective,
59
+ version: params.version,
60
+ status: 'compiled' as const,
61
+ leadAgentId: params.leadAgentId,
62
+ schemaRegistry: structuredClone(params.compiled.draft.schemas),
63
+ defaultExecutionVisibility: params.compiled.draft.defaultExecutionVisibility,
64
+ ...(params.contextEnrichments?.length
65
+ ? { contextEnrichments: params.contextEnrichments.map((entry) => ({ ...entry })) }
66
+ : {}),
67
+ edges: [...params.compiled.draft.edges],
68
+ entryNodeIds: [...(params.compiled.draft.entryNodeIds ?? [])],
69
+ executionMode: params.compiled.draft.executionMode ?? 'linear',
70
+ ...(params.compiled.draft.schedule ? { schedule: params.compiled.draft.schedule } : {}),
71
+ ...(params.compiled.draft.dependencies ? { dependencies: params.compiled.draft.dependencies } : {}),
72
+ ...(params.replacedSpecId ? { replacedSpecId: ensureRecordId(params.replacedSpecId, TABLES.PLAN_SPEC) } : {}),
73
+ compiledAt: nowDate(),
74
+ }
75
+ }