@lota-sdk/core 0.1.23 → 0.1.25
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.
- package/package.json +2 -2
- package/src/ai/definitions.ts +5 -59
- package/src/ai-gateway/ai-gateway.ts +36 -28
- package/src/ai-gateway/cache-headers.ts +9 -0
- package/src/config/model-constants.ts +6 -2
- package/src/create-runtime.ts +5 -17
- package/src/db/memory-types.ts +13 -8
- package/src/db/memory.ts +74 -53
- package/src/queues/autonomous-job.queue.ts +1 -8
- package/src/queues/context-compaction.queue.ts +2 -2
- package/src/queues/index.ts +2 -6
- package/src/queues/organization-learning.queue.ts +78 -0
- package/src/queues/plan-agent-heartbeat.queue.ts +10 -16
- package/src/queues/title-generation.queue.ts +62 -0
- package/src/runtime/agent-prompt-context.ts +0 -18
- package/src/runtime/agent-runtime-policy.ts +9 -2
- package/src/runtime/context-compaction-constants.ts +4 -2
- package/src/runtime/context-compaction.ts +135 -118
- package/src/runtime/execution-plan.ts +2 -1
- package/src/runtime/memory-pipeline.ts +70 -1
- package/src/runtime/memory-prompts-fact.ts +16 -0
- package/src/runtime/plugin-resolution.ts +3 -2
- package/src/runtime/plugin-types.ts +1 -42
- package/src/runtime/post-turn-side-effects.ts +212 -0
- package/src/runtime/runtime-config.ts +0 -13
- package/src/runtime/runtime-extensions.ts +10 -16
- package/src/runtime/runtime-worker-registry.ts +8 -19
- package/src/runtime/social-chat-agent-runner.ts +119 -0
- package/src/runtime/social-chat-history.ts +110 -0
- package/src/runtime/social-chat-prompts.ts +58 -0
- package/src/runtime/social-chat.ts +104 -340
- package/src/runtime/specialist-runner.ts +18 -0
- package/src/runtime/workstream-chat-helpers.ts +19 -0
- package/src/runtime/workstream-plan-turn.ts +195 -0
- package/src/runtime/workstream-state.ts +11 -8
- package/src/runtime/workstream-turn-context.ts +183 -0
- package/src/services/agent-activity.service.ts +350 -0
- package/src/services/autonomous-job.service.ts +1 -8
- package/src/services/execution-plan.service.ts +205 -334
- package/src/services/index.ts +2 -4
- package/src/services/memory.service.ts +54 -44
- package/src/services/ownership-dispatcher.service.ts +2 -19
- package/src/services/plan-completion-side-effects.ts +80 -0
- package/src/services/plan-event-delivery.service.ts +1 -1
- package/src/services/plan-executor.service.ts +42 -190
- package/src/services/plan-node-spec.ts +60 -0
- package/src/services/plan-run-data.ts +88 -0
- package/src/services/plan-validator.service.ts +10 -8
- package/src/services/workstream-constants.ts +2 -0
- package/src/services/workstream-title.service.ts +1 -1
- package/src/services/workstream-turn-preparation.service.ts +208 -715
- package/src/services/workstream.service.ts +162 -192
- package/src/services/workstream.types.ts +12 -44
- package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -0
- package/src/tools/execution-plan.tool.ts +11 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/project-with-plan.tool.ts +87 -0
- package/src/tools/remember-memory.tool.ts +7 -10
- package/src/tools/research-topic.tool.ts +1 -1
- package/src/tools/team-think.tool.ts +1 -1
- package/src/tools/user-questions.tool.ts +1 -1
- package/src/utils/autonomous-job-ids.ts +7 -0
- package/src/workers/organization-learning.worker.ts +31 -0
- package/src/workers/regular-chat-memory-digest.runner.ts +9 -3
- package/src/workers/skill-extraction.runner.ts +2 -2
- package/src/queues/recent-activity-title-refinement.queue.ts +0 -30
- package/src/queues/regular-chat-memory-digest.config.ts +0 -12
- package/src/queues/regular-chat-memory-digest.queue.ts +0 -34
- package/src/queues/skill-extraction.config.ts +0 -9
- package/src/queues/skill-extraction.queue.ts +0 -27
- package/src/queues/workstream-title-generation.queue.ts +0 -33
- package/src/services/context-enrichment.service.ts +0 -33
- package/src/services/coordination-registry.service.ts +0 -117
- package/src/services/domain-agent-executor.service.ts +0 -71
- package/src/services/memory-assessment.service.ts +0 -44
- package/src/services/playbook-registry.service.ts +0 -67
- package/src/workers/regular-chat-memory-digest.worker.ts +0 -22
- package/src/workers/skill-extraction.worker.ts +0 -22
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AgentActivityCounts,
|
|
3
|
+
AgentActivityEntry,
|
|
4
|
+
AgentActivityResponse,
|
|
5
|
+
AgentProjectEntry,
|
|
6
|
+
MyTasksResponse,
|
|
7
|
+
PlanBoardColumn,
|
|
8
|
+
PlanBoardResponse,
|
|
9
|
+
PlanNodeCard,
|
|
10
|
+
PlanViewNode,
|
|
11
|
+
PlanViewResponse,
|
|
12
|
+
SerializableExecutionPlan,
|
|
13
|
+
SerializablePlanNode,
|
|
14
|
+
} from '@lota-sdk/shared'
|
|
15
|
+
|
|
16
|
+
import { agentRoster } from '../config/agent-defaults'
|
|
17
|
+
import { serverLogger } from '../config/logger'
|
|
18
|
+
import { executionPlanService } from './execution-plan.service'
|
|
19
|
+
import { workstreamService } from './workstream.service'
|
|
20
|
+
import type { NormalizedWorkstream } from './workstream.types'
|
|
21
|
+
|
|
22
|
+
const BOARD_COLUMN_ORDER = ['ready', 'running', 'awaiting-human', 'completed', 'blocked', 'failed'] as const
|
|
23
|
+
type BoardColumnStatus = (typeof BOARD_COLUMN_ORDER)[number]
|
|
24
|
+
|
|
25
|
+
const COLUMN_LABELS: Record<BoardColumnStatus, string> = {
|
|
26
|
+
ready: 'Ready',
|
|
27
|
+
running: 'Running',
|
|
28
|
+
'awaiting-human': 'Awaiting Human',
|
|
29
|
+
completed: 'Completed',
|
|
30
|
+
blocked: 'Blocked',
|
|
31
|
+
failed: 'Failed',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type ActivePlanEntry = {
|
|
35
|
+
plan: SerializableExecutionPlan
|
|
36
|
+
workstream: Pick<NormalizedWorkstream, 'id' | 'title' | 'isRunning' | 'updatedAt'>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type AgentActivityDeps = {
|
|
40
|
+
executionPlanService: Pick<typeof executionPlanService, 'getActivePlansForWorkstream'>
|
|
41
|
+
workstreamService: Pick<typeof workstreamService, 'listWorkstreams'>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function normalizeCardStatus(status: string): BoardColumnStatus {
|
|
45
|
+
if (status === 'pending' || status === 'scheduled') return 'ready'
|
|
46
|
+
if (status === 'partial') return 'completed'
|
|
47
|
+
if (status === 'running' || status === 'awaiting-human' || status === 'completed' || status === 'blocked') {
|
|
48
|
+
return status
|
|
49
|
+
}
|
|
50
|
+
if (status === 'failed') return 'failed'
|
|
51
|
+
return 'blocked'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isCompletedStatus(status: string): boolean {
|
|
55
|
+
return status === 'completed' || status === 'partial' || status === 'skipped'
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createEmptyCounts(): AgentActivityCounts {
|
|
59
|
+
return { running: 0, ready: 0, pending: 0, awaitingHuman: 0, blocked: 0, completed: 0, failed: 0 }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function maxIsoDate(current: string | null, candidate: string): string {
|
|
63
|
+
if (!current) return candidate
|
|
64
|
+
return new Date(candidate).getTime() > new Date(current).getTime() ? candidate : current
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function incrementCounts(counts: AgentActivityCounts, rawStatus: string): void {
|
|
68
|
+
if (rawStatus === 'running') {
|
|
69
|
+
counts.running += 1
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
if (rawStatus === 'ready') {
|
|
73
|
+
counts.ready += 1
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
if (rawStatus === 'pending' || rawStatus === 'scheduled') {
|
|
77
|
+
counts.pending += 1
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
if (rawStatus === 'awaiting-human') {
|
|
81
|
+
counts.awaitingHuman += 1
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
if (rawStatus === 'blocked') {
|
|
85
|
+
counts.blocked += 1
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
if (rawStatus === 'failed') {
|
|
89
|
+
counts.failed += 1
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
if (rawStatus === 'completed' || rawStatus === 'partial') {
|
|
93
|
+
counts.completed += 1
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function planNodeToCard(
|
|
98
|
+
node: SerializablePlanNode,
|
|
99
|
+
plan: SerializableExecutionPlan,
|
|
100
|
+
workstreamId: string,
|
|
101
|
+
workstreamTitle: string,
|
|
102
|
+
): PlanNodeCard {
|
|
103
|
+
const approval = plan.approvals.find((candidate) => candidate.nodeId === node.id && candidate.status === 'pending')
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
nodeId: node.id,
|
|
107
|
+
label: node.label,
|
|
108
|
+
objective: node.objective,
|
|
109
|
+
status: normalizeCardStatus(node.status),
|
|
110
|
+
ownerType: node.owner.executorType,
|
|
111
|
+
ownerRef: node.owner.ref,
|
|
112
|
+
planRunId: plan.runId,
|
|
113
|
+
planTitle: plan.title,
|
|
114
|
+
workstreamId,
|
|
115
|
+
workstreamTitle,
|
|
116
|
+
nodeType: node.type,
|
|
117
|
+
artifactCount: plan.artifacts.filter((artifact) => artifact.nodeId === node.id).length,
|
|
118
|
+
hasApproval: Boolean(approval),
|
|
119
|
+
approvalId: approval?.id ?? null,
|
|
120
|
+
approvalStatus: approval?.status ?? null,
|
|
121
|
+
blockedReason: node.blockedReason ?? null,
|
|
122
|
+
latestNotes: node.latestNotes ?? null,
|
|
123
|
+
startedAt: node.startedAt ?? null,
|
|
124
|
+
completedAt: node.completedAt ?? null,
|
|
125
|
+
readyAt: node.readyAt ?? null,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildPlanViewNode(
|
|
130
|
+
node: SerializablePlanNode,
|
|
131
|
+
plan: SerializableExecutionPlan,
|
|
132
|
+
workstreamId: string,
|
|
133
|
+
workstreamTitle: string,
|
|
134
|
+
): PlanViewNode {
|
|
135
|
+
return {
|
|
136
|
+
...planNodeToCard(node, plan, workstreamId, workstreamTitle),
|
|
137
|
+
deliverableNames: node.deliverables.map((deliverable) => deliverable.name),
|
|
138
|
+
upstreamNodeIds: node.upstreamNodeIds,
|
|
139
|
+
downstreamNodeIds: node.downstreamNodeIds,
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export class AgentActivityService {
|
|
144
|
+
constructor(private readonly deps: AgentActivityDeps = { executionPlanService, workstreamService }) {}
|
|
145
|
+
|
|
146
|
+
async getBoard(userRef: string, orgRef: string): Promise<PlanBoardResponse> {
|
|
147
|
+
const activePlans = await this.getAllActivePlans(userRef, orgRef)
|
|
148
|
+
const cards = activePlans.flatMap(({ plan, workstream }) =>
|
|
149
|
+
plan.nodes.map((node) => planNodeToCard(node, plan, workstream.id, workstream.title)),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
const columns: PlanBoardColumn[] = BOARD_COLUMN_ORDER.map((status) => ({
|
|
153
|
+
status,
|
|
154
|
+
label: COLUMN_LABELS[status],
|
|
155
|
+
nodes: cards.filter((card) => card.status === status),
|
|
156
|
+
}))
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
columns,
|
|
160
|
+
summary: {
|
|
161
|
+
totalNodes: cards.length,
|
|
162
|
+
completedNodes: cards.filter((card) => card.status === 'completed').length,
|
|
163
|
+
activePlanCount: activePlans.length,
|
|
164
|
+
pendingApprovalCount: cards.filter((card) => card.hasApproval).length,
|
|
165
|
+
},
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async getPlanView(orgRef: string, planRunId: string, userRef: string): Promise<PlanViewResponse | null> {
|
|
170
|
+
const activePlans = await this.getAllActivePlans(userRef, orgRef)
|
|
171
|
+
const match = activePlans.find(({ plan }) => plan.runId === planRunId)
|
|
172
|
+
if (!match) return null
|
|
173
|
+
|
|
174
|
+
const { plan, workstream } = match
|
|
175
|
+
return {
|
|
176
|
+
planRunId: plan.runId,
|
|
177
|
+
title: plan.title,
|
|
178
|
+
objective: plan.objective,
|
|
179
|
+
status: plan.status,
|
|
180
|
+
leadAgentId: plan.leadAgentId,
|
|
181
|
+
progress: { completed: plan.progress.completed + plan.progress.partial, total: plan.progress.total },
|
|
182
|
+
nodes: plan.nodes.map((node) => buildPlanViewNode(node, plan, workstream.id, workstream.title)),
|
|
183
|
+
edges: plan.edges.map((edge) => ({ from: edge.source, to: edge.target })),
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async getMyTasks(userRef: string, orgRef: string): Promise<MyTasksResponse> {
|
|
188
|
+
const activePlans = await this.getAllActivePlans(userRef, orgRef)
|
|
189
|
+
const tasks: PlanNodeCard[] = []
|
|
190
|
+
|
|
191
|
+
for (const { plan, workstream } of activePlans) {
|
|
192
|
+
for (const node of plan.nodes) {
|
|
193
|
+
const humanOwned = node.owner.executorType === 'user'
|
|
194
|
+
const awaitingHuman = node.status === 'awaiting-human'
|
|
195
|
+
if (!humanOwned && !awaitingHuman) continue
|
|
196
|
+
|
|
197
|
+
tasks.push(planNodeToCard(node, plan, workstream.id, workstream.title))
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return { tasks, pendingApprovalCount: tasks.filter((task) => task.hasApproval).length }
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async getAgentActivity(userRef: string, orgRef: string): Promise<AgentActivityResponse> {
|
|
205
|
+
const activePlans = await this.getAllActivePlans(userRef, orgRef)
|
|
206
|
+
const activityByAgent = new Map<string, AgentActivityEntry>()
|
|
207
|
+
|
|
208
|
+
for (const agentId of agentRoster) {
|
|
209
|
+
activityByAgent.set(agentId, this.createEmptyEntry(agentId))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
for (const { plan, workstream } of activePlans) {
|
|
213
|
+
const involvedAgents = new Set<string>()
|
|
214
|
+
|
|
215
|
+
for (const node of plan.nodes) {
|
|
216
|
+
if (node.owner.executorType !== 'agent') continue
|
|
217
|
+
|
|
218
|
+
const agentId = node.owner.ref
|
|
219
|
+
const entry = this.ensureEntry(activityByAgent, agentId)
|
|
220
|
+
involvedAgents.add(agentId)
|
|
221
|
+
incrementCounts(entry.counts, node.status)
|
|
222
|
+
|
|
223
|
+
if (!isCompletedStatus(node.status)) {
|
|
224
|
+
entry.tasks.push(planNodeToCard(node, plan, workstream.id, workstream.title))
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (plan.leadAgentId.trim()) {
|
|
229
|
+
const leadEntry = this.ensureEntry(activityByAgent, plan.leadAgentId)
|
|
230
|
+
leadEntry.isLeadingActivePlan = true
|
|
231
|
+
involvedAgents.add(plan.leadAgentId)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
for (const agentId of involvedAgents) {
|
|
235
|
+
const entry = this.ensureEntry(activityByAgent, agentId)
|
|
236
|
+
this.ensureProjectEntry(entry.projects, {
|
|
237
|
+
workstreamId: workstream.id,
|
|
238
|
+
workstreamTitle: workstream.title,
|
|
239
|
+
planRunId: plan.runId,
|
|
240
|
+
planTitle: plan.title,
|
|
241
|
+
status: plan.status,
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
entry.isRunning = entry.isRunning || workstream.isRunning
|
|
245
|
+
entry.lastActiveAt = maxIsoDate(entry.lastActiveAt, workstream.updatedAt)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const userTasks = await this.getMyTasks(userRef, orgRef)
|
|
250
|
+
const agents = [...activityByAgent.values()].sort((left, right) => {
|
|
251
|
+
const leftIndex = agentRoster.indexOf(left.agentId)
|
|
252
|
+
const rightIndex = agentRoster.indexOf(right.agentId)
|
|
253
|
+
if (leftIndex !== -1 || rightIndex !== -1) {
|
|
254
|
+
if (leftIndex === -1) return 1
|
|
255
|
+
if (rightIndex === -1) return -1
|
|
256
|
+
return leftIndex - rightIndex
|
|
257
|
+
}
|
|
258
|
+
return left.agentId.localeCompare(right.agentId)
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
agents,
|
|
263
|
+
userActivity: {
|
|
264
|
+
taskCount: userTasks.tasks.length,
|
|
265
|
+
pendingApprovalCount: userTasks.pendingApprovalCount,
|
|
266
|
+
awaitingHumanCount: userTasks.tasks.filter((task) => task.status === 'awaiting-human').length,
|
|
267
|
+
lastActiveAt: activePlans.reduce<string | null>(
|
|
268
|
+
(latest, entry) => maxIsoDate(latest, entry.workstream.updatedAt),
|
|
269
|
+
null,
|
|
270
|
+
),
|
|
271
|
+
},
|
|
272
|
+
totalActivePlans: activePlans.length,
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async getAllActivePlans(userRef: string, orgRef: string): Promise<ActivePlanEntry[]> {
|
|
277
|
+
const workstreams = await this.listRelevantWorkstreams(userRef, orgRef)
|
|
278
|
+
const planResults = await Promise.all(
|
|
279
|
+
workstreams.map(async (workstream) => {
|
|
280
|
+
try {
|
|
281
|
+
const plans = await this.deps.executionPlanService.getActivePlansForWorkstream(workstream.id)
|
|
282
|
+
return plans.map((plan) => ({ plan, workstream }))
|
|
283
|
+
} catch (error) {
|
|
284
|
+
serverLogger.error`Failed to load active plans for workstream ${workstream.id}: ${error}`
|
|
285
|
+
return []
|
|
286
|
+
}
|
|
287
|
+
}),
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
return planResults.flat()
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
private async listRelevantWorkstreams(userRef: string, orgRef: string): Promise<NormalizedWorkstream[]> {
|
|
294
|
+
const [direct, core, group] = await Promise.all([
|
|
295
|
+
this.deps.workstreamService.listWorkstreams(userRef, orgRef, { mode: 'direct', includeArchived: false }),
|
|
296
|
+
this.deps.workstreamService.listWorkstreams(userRef, orgRef, {
|
|
297
|
+
mode: 'group',
|
|
298
|
+
core: true,
|
|
299
|
+
includeArchived: false,
|
|
300
|
+
}),
|
|
301
|
+
this.deps.workstreamService.listWorkstreams(userRef, orgRef, {
|
|
302
|
+
mode: 'group',
|
|
303
|
+
core: false,
|
|
304
|
+
includeArchived: false,
|
|
305
|
+
take: 500,
|
|
306
|
+
page: 1,
|
|
307
|
+
}),
|
|
308
|
+
])
|
|
309
|
+
|
|
310
|
+
const deduped = new Map<string, NormalizedWorkstream>()
|
|
311
|
+
for (const workstream of [...direct.workstreams, ...core.workstreams, ...group.workstreams]) {
|
|
312
|
+
deduped.set(workstream.id, workstream)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return [...deduped.values()]
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private createEmptyEntry(agentId: string): AgentActivityEntry {
|
|
319
|
+
return {
|
|
320
|
+
agentId,
|
|
321
|
+
counts: createEmptyCounts(),
|
|
322
|
+
tasks: [],
|
|
323
|
+
projects: [],
|
|
324
|
+
isLeadingActivePlan: false,
|
|
325
|
+
isRunning: false,
|
|
326
|
+
lastActiveAt: null,
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private ensureEntry(entries: Map<string, AgentActivityEntry>, agentId: string): AgentActivityEntry {
|
|
331
|
+
const existing = entries.get(agentId)
|
|
332
|
+
if (existing) {
|
|
333
|
+
return existing
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const created = this.createEmptyEntry(agentId)
|
|
337
|
+
entries.set(agentId, created)
|
|
338
|
+
return created
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private ensureProjectEntry(projects: AgentProjectEntry[], next: AgentProjectEntry): void {
|
|
342
|
+
if (projects.some((project) => project.planRunId === next.planRunId)) {
|
|
343
|
+
return
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
projects.push(next)
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export const agentActivityService = new AgentActivityService()
|
|
@@ -31,6 +31,7 @@ import { databaseService } from '../db/service'
|
|
|
31
31
|
import { TABLES } from '../db/tables'
|
|
32
32
|
import type { AutonomousJobQueuePayload } from '../queues/autonomous-job.queue'
|
|
33
33
|
import { extractMessageText } from '../runtime/workstream-chat-helpers'
|
|
34
|
+
import { buildAutonomousAtJobId, encodeBullmqId } from '../utils/autonomous-job-ids'
|
|
34
35
|
import { toIsoDateTimeString, toOptionalIsoDateTimeString } from '../utils/date-time'
|
|
35
36
|
import { compactRecord, compactWhitespace, stringifyUnknown, truncateText } from '../utils/string'
|
|
36
37
|
import { executionPlanService } from './execution-plan.service'
|
|
@@ -41,14 +42,6 @@ import { workstreamService } from './workstream.service'
|
|
|
41
42
|
|
|
42
43
|
const AUTONOMOUS_JOB_QUEUE_NAME = 'autonomous-job'
|
|
43
44
|
|
|
44
|
-
function encodeBullmqId(raw: string): string {
|
|
45
|
-
return Buffer.from(raw).toString('base64url')
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function buildAutonomousAtJobId(autonomousJobId: string): string {
|
|
49
|
-
return `autonomous-at-${encodeBullmqId(autonomousJobId)}`
|
|
50
|
-
}
|
|
51
|
-
|
|
52
45
|
function buildAutonomousManualJobId(autonomousJobId: string): string {
|
|
53
46
|
return `autonomous-manual-${encodeBullmqId(autonomousJobId)}-${Date.now()}`
|
|
54
47
|
}
|