@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
@@ -1,240 +0,0 @@
1
- import { PlanCycleRecordSchema, PlanScheduleRecordSchema } from '@lota-sdk/shared'
2
- import type { PlanScheduleRecord, PlanScheduleSpec } from '@lota-sdk/shared'
3
- import { CronExpressionParser } from 'cron-parser'
4
- import { BoundQuery } from 'surrealdb'
5
-
6
- import type { RecordIdInput } from '../db/record-id'
7
- import { ensureRecordId, recordIdToString } from '../db/record-id'
8
- import { databaseService } from '../db/service'
9
- import { TABLES } from '../db/tables'
10
- import { toDatabaseDateTime } from '../utils/date-time'
11
-
12
- class PlanSchedulerService {
13
- computeNextFireAt(spec: PlanScheduleSpec, baseTime: Date = new Date()): Date | null {
14
- switch (spec.type) {
15
- case 'immediate':
16
- return baseTime
17
-
18
- case 'absolute':
19
- return spec.at ? new Date(spec.at) : null
20
-
21
- case 'relative':
22
- return spec.delayMs !== undefined ? new Date(baseTime.getTime() + spec.delayMs) : null
23
-
24
- case 'cron': {
25
- if (!spec.cron) return null
26
- try {
27
- const expr = CronExpressionParser.parse(spec.cron, { currentDate: baseTime })
28
- const next = expr.next()
29
- return next.toDate()
30
- } catch {
31
- return null
32
- }
33
- }
34
-
35
- case 'monitoring':
36
- return spec.intervalMs !== undefined ? new Date(baseTime.getTime() + spec.intervalMs) : null
37
-
38
- default:
39
- return null
40
- }
41
- }
42
-
43
- async createSchedule(params: {
44
- organizationId: RecordIdInput
45
- threadId: RecordIdInput
46
- planSpecId?: RecordIdInput
47
- runId?: RecordIdInput
48
- nodeId?: string
49
- scheduleSpec: PlanScheduleSpec
50
- }): Promise<PlanScheduleRecord> {
51
- const nextFireAt = this.computeNextFireAt(params.scheduleSpec)
52
- const now = new Date()
53
-
54
- const record = await databaseService.create(
55
- TABLES.PLAN_SCHEDULE,
56
- {
57
- organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
58
- threadId: ensureRecordId(params.threadId, TABLES.THREAD),
59
- planSpecId: params.planSpecId ? ensureRecordId(params.planSpecId, TABLES.PLAN_SPEC) : undefined,
60
- runId: params.runId ? ensureRecordId(params.runId, TABLES.PLAN_RUN) : undefined,
61
- nodeId: params.nodeId,
62
- scheduleSpec: params.scheduleSpec,
63
- status: 'active',
64
- fireCount: 0,
65
- ...(nextFireAt ? { nextFireAt: toDatabaseDateTime(nextFireAt) } : {}),
66
- createdAt: now,
67
- },
68
- PlanScheduleRecordSchema,
69
- )
70
-
71
- // Enqueue a delayed BullMQ job to fire at the scheduled time
72
- if (nextFireAt) {
73
- const delay = Math.max(0, nextFireAt.getTime() - Date.now())
74
- const { enqueueScheduleFire } = await import('../queues/plan-scheduler.queue')
75
- await enqueueScheduleFire(recordIdToString(record.id, TABLES.PLAN_SCHEDULE), delay)
76
- }
77
-
78
- return record
79
- }
80
-
81
- /** Called by the BullMQ worker when a fire-schedule job executes. */
82
- async fireScheduleById(scheduleId: string): Promise<void> {
83
- const schedule = await databaseService.findOne(
84
- TABLES.PLAN_SCHEDULE,
85
- { id: ensureRecordId(scheduleId, TABLES.PLAN_SCHEDULE) },
86
- PlanScheduleRecordSchema,
87
- )
88
-
89
- if (!schedule || schedule.status !== 'active') return
90
-
91
- await this.fireSchedule(schedule)
92
- }
93
-
94
- async fireSchedule(schedule: PlanScheduleRecord): Promise<void> {
95
- const now = new Date()
96
- const newFireCount = schedule.fireCount + 1
97
- const isRecurring = schedule.scheduleSpec.type === 'cron' || schedule.scheduleSpec.type === 'monitoring'
98
- const maxReached = schedule.scheduleSpec.maxFires !== undefined && newFireCount >= schedule.scheduleSpec.maxFires
99
-
100
- let nextFireAt: Date | null = null
101
- let newStatus: 'active' | 'completed' = 'completed'
102
-
103
- if (isRecurring && !maxReached) {
104
- nextFireAt = this.computeNextFireAt(schedule.scheduleSpec, now)
105
- newStatus = nextFireAt ? 'active' : 'completed'
106
- }
107
-
108
- await databaseService.update(
109
- TABLES.PLAN_SCHEDULE,
110
- schedule.id,
111
- { fireCount: newFireCount, lastFiredAt: now, nextFireAt: toDatabaseDateTime(nextFireAt), status: newStatus },
112
- PlanScheduleRecordSchema,
113
- )
114
-
115
- // Enqueue next fire for recurring schedules
116
- if (newStatus === 'active' && nextFireAt) {
117
- const delay = Math.max(0, nextFireAt.getTime() - Date.now())
118
- const scheduleIdStr = recordIdToString(schedule.id, TABLES.PLAN_SCHEDULE)
119
- const { enqueueScheduleFire } = await import('../queues/plan-scheduler.queue')
120
- await enqueueScheduleFire(scheduleIdStr, delay)
121
- }
122
-
123
- let shouldRecoverDeadlineChecks = false
124
-
125
- // Dispatch: node-level schedule — promote the delayed node
126
- if (schedule.runId && schedule.nodeId) {
127
- const { planExecutorService } = await import('./plan-executor.service')
128
- await planExecutorService.promoteDelayedNode({
129
- runId: recordIdToString(schedule.runId, TABLES.PLAN_RUN),
130
- nodeId: schedule.nodeId,
131
- emittedBy: 'plan-scheduler',
132
- })
133
- shouldRecoverDeadlineChecks = true
134
- }
135
-
136
- // Dispatch: plan-level schedule — advance a linked cycle or create a new run
137
- if (schedule.planSpecId && !schedule.runId) {
138
- const cycle = await databaseService.findOne(
139
- TABLES.PLAN_CYCLE,
140
- { scheduleId: ensureRecordId(schedule.id, TABLES.PLAN_SCHEDULE) },
141
- PlanCycleRecordSchema,
142
- )
143
-
144
- if (cycle) {
145
- const { planCycleService } = await import('./plan-cycle.service')
146
- await planCycleService.advanceCycle(cycle.id)
147
- shouldRecoverDeadlineChecks = true
148
- }
149
- }
150
-
151
- if (shouldRecoverDeadlineChecks) {
152
- const { planDeadlineService } = await import('./plan-deadline.service')
153
- await planDeadlineService.recoverDeadlineChecks()
154
- }
155
- }
156
-
157
- /** Re-enqueue BullMQ jobs for all active schedules. Called once at worker startup. */
158
- async recoverActiveSchedules(): Promise<void> {
159
- const activeSchedules = await databaseService.queryMany(
160
- new BoundQuery(`SELECT * FROM ${TABLES.PLAN_SCHEDULE} WHERE status = $status ORDER BY nextFireAt ASC`, {
161
- status: 'active',
162
- }),
163
- PlanScheduleRecordSchema,
164
- )
165
-
166
- const { enqueueScheduleFire } = await import('../queues/plan-scheduler.queue')
167
-
168
- for (const schedule of activeSchedules) {
169
- if (!schedule.nextFireAt) continue
170
- const scheduleId = recordIdToString(schedule.id, TABLES.PLAN_SCHEDULE)
171
- const delay = Math.max(0, new Date(schedule.nextFireAt).getTime() - Date.now())
172
- await enqueueScheduleFire(scheduleId, delay)
173
- }
174
- }
175
-
176
- async cancelSchedule(scheduleId: RecordIdInput): Promise<void> {
177
- const idStr = recordIdToString(scheduleId, TABLES.PLAN_SCHEDULE)
178
- const { removeScheduleFireJob } = await import('../queues/plan-scheduler.queue')
179
- await removeScheduleFireJob(idStr)
180
-
181
- await databaseService.update(
182
- TABLES.PLAN_SCHEDULE,
183
- ensureRecordId(scheduleId, TABLES.PLAN_SCHEDULE),
184
- { status: 'cancelled' },
185
- PlanScheduleRecordSchema,
186
- )
187
- }
188
-
189
- async pauseSchedule(scheduleId: RecordIdInput): Promise<void> {
190
- const idStr = recordIdToString(scheduleId, TABLES.PLAN_SCHEDULE)
191
- const { removeScheduleFireJob } = await import('../queues/plan-scheduler.queue')
192
- await removeScheduleFireJob(idStr)
193
-
194
- await databaseService.update(
195
- TABLES.PLAN_SCHEDULE,
196
- ensureRecordId(scheduleId, TABLES.PLAN_SCHEDULE),
197
- { status: 'paused' },
198
- PlanScheduleRecordSchema,
199
- )
200
- }
201
-
202
- async resumeSchedule(scheduleId: RecordIdInput): Promise<void> {
203
- const schedule = await databaseService.findOne(
204
- TABLES.PLAN_SCHEDULE,
205
- { id: ensureRecordId(scheduleId, TABLES.PLAN_SCHEDULE) },
206
- PlanScheduleRecordSchema,
207
- )
208
- if (!schedule) {
209
- throw new Error(`Schedule not found: ${recordIdToString(scheduleId, TABLES.PLAN_SCHEDULE)}`)
210
- }
211
-
212
- const nextFireAt = this.computeNextFireAt(schedule.scheduleSpec)
213
-
214
- await databaseService.update(
215
- TABLES.PLAN_SCHEDULE,
216
- ensureRecordId(scheduleId, TABLES.PLAN_SCHEDULE),
217
- { status: 'active', nextFireAt: toDatabaseDateTime(nextFireAt) },
218
- PlanScheduleRecordSchema,
219
- )
220
-
221
- // Re-enqueue the delayed fire job
222
- if (nextFireAt) {
223
- const delay = Math.max(0, nextFireAt.getTime() - Date.now())
224
- const idStr = recordIdToString(scheduleId, TABLES.PLAN_SCHEDULE)
225
- const { enqueueScheduleFire } = await import('../queues/plan-scheduler.queue')
226
- await enqueueScheduleFire(idStr, delay)
227
- }
228
- }
229
-
230
- async listSchedules(threadId: RecordIdInput): Promise<PlanScheduleRecord[]> {
231
- return databaseService.findMany(
232
- TABLES.PLAN_SCHEDULE,
233
- { threadId: ensureRecordId(threadId, TABLES.THREAD) },
234
- PlanScheduleRecordSchema,
235
- { orderBy: 'createdAt', orderDir: 'ASC' },
236
- )
237
- }
238
- }
239
-
240
- export const planSchedulerService = new PlanSchedulerService()
@@ -1,177 +0,0 @@
1
- import { PlanTemplateRecordSchema } from '@lota-sdk/shared'
2
- import type { ExecutionPlanToolResultData, PlanArtifactRecord, PlanDraft, PlanTemplateRecord } from '@lota-sdk/shared'
3
-
4
- import type { RecordIdInput } from '../db/record-id'
5
- import { ensureRecordId, recordIdToString } from '../db/record-id'
6
- import { databaseService } from '../db/service'
7
- import { TABLES } from '../db/tables'
8
- import { executionPlanService } from './execution-plan.service'
9
-
10
- class PlanTemplateService {
11
- private resolveSourceIdentity(params: { source?: 'user' | 'playbook' | 'system'; sourceRef?: string }) {
12
- const source = params.source ?? 'user'
13
- const sourceRef = params.sourceRef?.trim()
14
-
15
- if (source !== 'user' && !sourceRef) {
16
- throw new Error(`sourceRef is required when source is "${source}".`)
17
- }
18
-
19
- return { source, sourceRef }
20
- }
21
-
22
- async createTemplate(params: {
23
- organizationId: RecordIdInput
24
- name: string
25
- description?: string
26
- draft: PlanDraft
27
- tags?: string[]
28
- source?: 'user' | 'playbook' | 'system'
29
- sourceRef?: string
30
- }): Promise<PlanTemplateRecord> {
31
- const now = new Date()
32
- const identity = this.resolveSourceIdentity({ source: params.source, sourceRef: params.sourceRef })
33
- return databaseService.create(
34
- TABLES.PLAN_TEMPLATE,
35
- {
36
- organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
37
- name: params.name,
38
- ...(params.description ? { description: params.description } : {}),
39
- draft: params.draft,
40
- tags: params.tags ?? [],
41
- source: identity.source,
42
- ...(identity.sourceRef ? { sourceRef: identity.sourceRef } : {}),
43
- createdAt: now,
44
- },
45
- PlanTemplateRecordSchema,
46
- )
47
- }
48
-
49
- async getTemplate(templateId: RecordIdInput): Promise<PlanTemplateRecord | null> {
50
- return databaseService.findOne(
51
- TABLES.PLAN_TEMPLATE,
52
- { id: ensureRecordId(templateId, TABLES.PLAN_TEMPLATE) },
53
- PlanTemplateRecordSchema,
54
- )
55
- }
56
-
57
- async getTemplateBySourceRef(params: {
58
- organizationId: RecordIdInput
59
- source: 'user' | 'playbook' | 'system'
60
- sourceRef: string
61
- }): Promise<PlanTemplateRecord | null> {
62
- return await databaseService.findOne(
63
- TABLES.PLAN_TEMPLATE,
64
- {
65
- organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
66
- source: params.source,
67
- sourceRef: params.sourceRef,
68
- },
69
- PlanTemplateRecordSchema,
70
- )
71
- }
72
-
73
- async listTemplates(
74
- organizationId: RecordIdInput,
75
- params?: { tags?: string[]; source?: string },
76
- ): Promise<PlanTemplateRecord[]> {
77
- const filter: Record<string, unknown> = { organizationId: ensureRecordId(organizationId, TABLES.ORGANIZATION) }
78
- if (params?.source) {
79
- filter.source = params.source
80
- }
81
-
82
- const templates = await databaseService.findMany(TABLES.PLAN_TEMPLATE, filter, PlanTemplateRecordSchema, {
83
- orderBy: 'createdAt',
84
- orderDir: 'ASC',
85
- })
86
-
87
- if (params?.tags && params.tags.length > 0) {
88
- const tagSet = new Set(params.tags)
89
- return templates.filter((t) => t.tags.some((tag) => tagSet.has(tag)))
90
- }
91
-
92
- return templates
93
- }
94
-
95
- async updateTemplate(
96
- templateId: RecordIdInput,
97
- patch: Partial<{ name: string; description: string; draft: PlanDraft; tags: string[] }>,
98
- ): Promise<PlanTemplateRecord> {
99
- const updated = await databaseService.update(
100
- TABLES.PLAN_TEMPLATE,
101
- ensureRecordId(templateId, TABLES.PLAN_TEMPLATE),
102
- patch,
103
- PlanTemplateRecordSchema,
104
- )
105
- if (!updated) {
106
- throw new Error(`Template not found: ${recordIdToString(templateId, TABLES.PLAN_TEMPLATE)}`)
107
- }
108
- return updated
109
- }
110
-
111
- async upsertTemplateBySourceRef(params: {
112
- organizationId: RecordIdInput
113
- name: string
114
- description?: string
115
- draft: PlanDraft
116
- tags?: string[]
117
- source: 'user' | 'playbook' | 'system'
118
- sourceRef: string
119
- }): Promise<PlanTemplateRecord> {
120
- const existing = await this.getTemplateBySourceRef({
121
- organizationId: params.organizationId,
122
- source: params.source,
123
- sourceRef: params.sourceRef,
124
- })
125
-
126
- if (!existing) {
127
- return await this.createTemplate(params)
128
- }
129
-
130
- return await this.updateTemplate(existing.id, {
131
- name: params.name,
132
- description: params.description,
133
- draft: params.draft,
134
- tags: params.tags ?? [],
135
- })
136
- }
137
-
138
- async deleteTemplate(templateId: RecordIdInput): Promise<void> {
139
- await databaseService.deleteById(TABLES.PLAN_TEMPLATE, ensureRecordId(templateId, TABLES.PLAN_TEMPLATE))
140
- }
141
-
142
- async instantiate(params: {
143
- templateId: RecordIdInput
144
- organizationId: RecordIdInput
145
- threadId: RecordIdInput
146
- sourceThreadId?: RecordIdInput
147
- leadAgentId: string
148
- createdByAgentId?: string
149
- requireApproval?: boolean
150
- overrides?: Partial<PlanDraft>
151
- carryForwardArtifacts?: PlanArtifactRecord[]
152
- }): Promise<ExecutionPlanToolResultData> {
153
- const template = await this.getTemplate(params.templateId)
154
- if (!template) {
155
- throw new Error(`Template not found: ${recordIdToString(params.templateId, TABLES.PLAN_TEMPLATE)}`)
156
- }
157
-
158
- const draft: PlanDraft = { ...template.draft, ...params.overrides }
159
-
160
- if (params.carryForwardArtifacts && params.carryForwardArtifacts.length > 0) {
161
- const carryContext = params.carryForwardArtifacts.map((a) => `[carry-forward] ${a.name}: ${a.pointer}`)
162
- draft.objective = `${draft.objective}\n\nCarry-forward context:\n${carryContext.join('\n')}`
163
- }
164
-
165
- return executionPlanService.createPlan({
166
- organizationId: params.organizationId,
167
- threadId: params.threadId,
168
- sourceThreadId: params.sourceThreadId,
169
- leadAgentId: params.leadAgentId,
170
- createdByAgentId: params.createdByAgentId,
171
- requireApproval: params.requireApproval,
172
- input: draft,
173
- })
174
- }
175
- }
176
-
177
- export const planTemplateService = new PlanTemplateService()