@pikku/mongodb 0.12.1
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/CHANGELOG.md +15 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.js +9 -0
- package/dist/src/mongodb-agent-run-service.d.ts +21 -0
- package/dist/src/mongodb-agent-run-service.js +127 -0
- package/dist/src/mongodb-ai-storage-service.d.ts +41 -0
- package/dist/src/mongodb-ai-storage-service.js +408 -0
- package/dist/src/mongodb-channel-store.d.ts +19 -0
- package/dist/src/mongodb-channel-store.js +52 -0
- package/dist/src/mongodb-deployment-service.d.ts +17 -0
- package/dist/src/mongodb-deployment-service.js +75 -0
- package/dist/src/mongodb-eventhub-store.d.ts +13 -0
- package/dist/src/mongodb-eventhub-store.js +37 -0
- package/dist/src/mongodb-secret-service.d.ts +30 -0
- package/dist/src/mongodb-secret-service.js +110 -0
- package/dist/src/mongodb-workflow-run-service.d.ts +36 -0
- package/dist/src/mongodb-workflow-run-service.js +146 -0
- package/dist/src/mongodb-workflow-service.d.ts +55 -0
- package/dist/src/mongodb-workflow-service.js +351 -0
- package/dist/src/pikku-mongodb.d.ts +12 -0
- package/dist/src/pikku-mongodb.js +37 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +29 -0
- package/run-tests.sh +53 -0
- package/src/index.ts +14 -0
- package/src/mongodb-agent-run-service.ts +206 -0
- package/src/mongodb-ai-storage-service.ts +576 -0
- package/src/mongodb-channel-store.ts +96 -0
- package/src/mongodb-deployment-service.ts +114 -0
- package/src/mongodb-eventhub-store.ts +52 -0
- package/src/mongodb-secret-service.ts +178 -0
- package/src/mongodb-services.test.ts +149 -0
- package/src/mongodb-workflow-run-service.ts +246 -0
- package/src/mongodb-workflow-service.ts +583 -0
- package/src/pikku-mongodb.ts +41 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
WorkflowRun,
|
|
3
|
+
StepState,
|
|
4
|
+
WorkflowStatus,
|
|
5
|
+
WorkflowRunService,
|
|
6
|
+
} from '@pikku/core/workflow'
|
|
7
|
+
import type { Db, Collection } from 'mongodb'
|
|
8
|
+
|
|
9
|
+
interface WorkflowRunDoc {
|
|
10
|
+
_id: string
|
|
11
|
+
workflow: string
|
|
12
|
+
status: string
|
|
13
|
+
input: any
|
|
14
|
+
output: any | null
|
|
15
|
+
error: any | null
|
|
16
|
+
state: Record<string, unknown>
|
|
17
|
+
inline: boolean
|
|
18
|
+
graphHash: string | null
|
|
19
|
+
wire: any | null
|
|
20
|
+
createdAt: Date
|
|
21
|
+
updatedAt: Date
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface WorkflowStepDoc {
|
|
25
|
+
_id: string
|
|
26
|
+
workflowRunId: string
|
|
27
|
+
stepName: string
|
|
28
|
+
rpcName: string | null
|
|
29
|
+
data: any | null
|
|
30
|
+
status: string
|
|
31
|
+
result: any | null
|
|
32
|
+
error: any | null
|
|
33
|
+
branchTaken: string | null
|
|
34
|
+
retries: number | null
|
|
35
|
+
retryDelay: string | null
|
|
36
|
+
createdAt: Date
|
|
37
|
+
updatedAt: Date
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface WorkflowStepHistoryDoc {
|
|
41
|
+
_id: string
|
|
42
|
+
workflowStepId: string
|
|
43
|
+
status: string
|
|
44
|
+
result: any | null
|
|
45
|
+
error: any | null
|
|
46
|
+
createdAt: Date
|
|
47
|
+
runningAt: Date | null
|
|
48
|
+
scheduledAt: Date | null
|
|
49
|
+
succeededAt: Date | null
|
|
50
|
+
failedAt: Date | null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface WorkflowVersionDoc {
|
|
54
|
+
workflowName: string
|
|
55
|
+
graphHash: string
|
|
56
|
+
graph: any
|
|
57
|
+
source: string
|
|
58
|
+
createdAt: Date
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class MongoDBWorkflowRunService implements WorkflowRunService {
|
|
62
|
+
private runs: Collection<WorkflowRunDoc>
|
|
63
|
+
private steps: Collection<WorkflowStepDoc>
|
|
64
|
+
private stepHistory: Collection<WorkflowStepHistoryDoc>
|
|
65
|
+
private versions: Collection<WorkflowVersionDoc>
|
|
66
|
+
|
|
67
|
+
constructor(db: Db) {
|
|
68
|
+
this.runs = db.collection<WorkflowRunDoc>('workflow_runs')
|
|
69
|
+
this.steps = db.collection<WorkflowStepDoc>('workflow_step')
|
|
70
|
+
this.stepHistory = db.collection<WorkflowStepHistoryDoc>(
|
|
71
|
+
'workflow_step_history'
|
|
72
|
+
)
|
|
73
|
+
this.versions = db.collection<WorkflowVersionDoc>('workflow_versions')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async listRuns(options?: {
|
|
77
|
+
workflowName?: string
|
|
78
|
+
status?: string
|
|
79
|
+
limit?: number
|
|
80
|
+
offset?: number
|
|
81
|
+
}): Promise<WorkflowRun[]> {
|
|
82
|
+
const { workflowName, status, limit = 50, offset = 0 } = options ?? {}
|
|
83
|
+
|
|
84
|
+
const filter: Record<string, any> = {}
|
|
85
|
+
if (workflowName) filter.workflow = workflowName
|
|
86
|
+
if (status) filter.status = status
|
|
87
|
+
|
|
88
|
+
const result = await this.runs
|
|
89
|
+
.find(filter)
|
|
90
|
+
.sort({ createdAt: -1 })
|
|
91
|
+
.skip(offset)
|
|
92
|
+
.limit(limit)
|
|
93
|
+
.toArray()
|
|
94
|
+
|
|
95
|
+
return result.map((row) => this.mapRunRow(row))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async getRun(id: string): Promise<WorkflowRun | null> {
|
|
99
|
+
const row = await this.runs.findOne({ _id: id })
|
|
100
|
+
if (!row) return null
|
|
101
|
+
return this.mapRunRow(row)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async getRunSteps(
|
|
105
|
+
runId: string
|
|
106
|
+
): Promise<
|
|
107
|
+
Array<StepState & { stepName: string; rpcName?: string; data?: any }>
|
|
108
|
+
> {
|
|
109
|
+
const result = await this.steps
|
|
110
|
+
.find({ workflowRunId: runId })
|
|
111
|
+
.sort({ createdAt: 1 })
|
|
112
|
+
.toArray()
|
|
113
|
+
|
|
114
|
+
const stepIds = result.map((r) => r._id)
|
|
115
|
+
const historyCounts = await this.stepHistory
|
|
116
|
+
.aggregate<{
|
|
117
|
+
_id: string
|
|
118
|
+
count: number
|
|
119
|
+
}>([
|
|
120
|
+
{ $match: { workflowStepId: { $in: stepIds } } },
|
|
121
|
+
{ $group: { _id: '$workflowStepId', count: { $sum: 1 } } },
|
|
122
|
+
])
|
|
123
|
+
.toArray()
|
|
124
|
+
|
|
125
|
+
const countMap = new Map(historyCounts.map((h) => [h._id, h.count]))
|
|
126
|
+
|
|
127
|
+
return result.map((row) => ({
|
|
128
|
+
stepId: row._id,
|
|
129
|
+
stepName: row.stepName,
|
|
130
|
+
rpcName: row.rpcName ?? undefined,
|
|
131
|
+
data: row.data ?? undefined,
|
|
132
|
+
status: row.status as StepState['status'],
|
|
133
|
+
result: row.result ?? undefined,
|
|
134
|
+
error: row.error ?? undefined,
|
|
135
|
+
attemptCount: countMap.get(row._id) ?? 1,
|
|
136
|
+
retries: row.retries != null ? Number(row.retries) : undefined,
|
|
137
|
+
retryDelay: row.retryDelay ?? undefined,
|
|
138
|
+
createdAt: new Date(row.createdAt),
|
|
139
|
+
updatedAt: new Date(row.updatedAt),
|
|
140
|
+
}))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async getRunHistory(
|
|
144
|
+
runId: string
|
|
145
|
+
): Promise<Array<StepState & { stepName: string }>> {
|
|
146
|
+
const steps = await this.steps.find({ workflowRunId: runId }).toArray()
|
|
147
|
+
|
|
148
|
+
const stepMap = new Map(steps.map((s) => [s._id, s]))
|
|
149
|
+
const stepIds = steps.map((s) => s._id)
|
|
150
|
+
|
|
151
|
+
const history = await this.stepHistory
|
|
152
|
+
.find({ workflowStepId: { $in: stepIds } })
|
|
153
|
+
.sort({ createdAt: 1 })
|
|
154
|
+
.toArray()
|
|
155
|
+
|
|
156
|
+
let attemptCounters: Record<string, number> = {}
|
|
157
|
+
return history.map((row) => {
|
|
158
|
+
const stepId = row.workflowStepId
|
|
159
|
+
const step = stepMap.get(stepId)!
|
|
160
|
+
attemptCounters[stepId] = (attemptCounters[stepId] ?? 0) + 1
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
stepId,
|
|
164
|
+
stepName: step.stepName,
|
|
165
|
+
status: row.status as StepState['status'],
|
|
166
|
+
result: row.result ?? undefined,
|
|
167
|
+
error: row.error ?? undefined,
|
|
168
|
+
attemptCount: attemptCounters[stepId]!,
|
|
169
|
+
retries: step.retries != null ? Number(step.retries) : undefined,
|
|
170
|
+
retryDelay: step.retryDelay ?? undefined,
|
|
171
|
+
createdAt: new Date(row.createdAt),
|
|
172
|
+
updatedAt: new Date(row.createdAt),
|
|
173
|
+
runningAt: row.runningAt ? new Date(row.runningAt) : undefined,
|
|
174
|
+
scheduledAt: row.scheduledAt ? new Date(row.scheduledAt) : undefined,
|
|
175
|
+
succeededAt: row.succeededAt ? new Date(row.succeededAt) : undefined,
|
|
176
|
+
failedAt: row.failedAt ? new Date(row.failedAt) : undefined,
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async getDistinctWorkflowNames(): Promise<string[]> {
|
|
182
|
+
const result = await this.runs.distinct('workflow')
|
|
183
|
+
return result.sort()
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async getWorkflowVersion(
|
|
187
|
+
name: string,
|
|
188
|
+
graphHash: string
|
|
189
|
+
): Promise<{ graph: any; source: string } | null> {
|
|
190
|
+
const row = await this.versions.findOne({
|
|
191
|
+
workflowName: name,
|
|
192
|
+
graphHash,
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
if (!row) return null
|
|
196
|
+
return {
|
|
197
|
+
graph: row.graph,
|
|
198
|
+
source: row.source,
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async getAIGeneratedWorkflows(
|
|
203
|
+
agentName?: string
|
|
204
|
+
): Promise<Array<{ workflowName: string; graphHash: string; graph: any }>> {
|
|
205
|
+
const filter: Record<string, any> = { source: 'ai-agent', status: 'active' }
|
|
206
|
+
if (agentName) {
|
|
207
|
+
const escaped = agentName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
208
|
+
filter.workflowName = { $regex: `^ai:${escaped}:` }
|
|
209
|
+
}
|
|
210
|
+
const rows = await this.versions.find(filter).toArray()
|
|
211
|
+
return rows.map((row) => ({
|
|
212
|
+
workflowName: row.workflowName,
|
|
213
|
+
graphHash: row.graphHash,
|
|
214
|
+
graph: row.graph,
|
|
215
|
+
}))
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async deleteRun(id: string): Promise<boolean> {
|
|
219
|
+
const steps = await this.steps.find({ workflowRunId: id }).toArray()
|
|
220
|
+
const stepIds = steps.map((s) => s._id)
|
|
221
|
+
|
|
222
|
+
if (stepIds.length > 0) {
|
|
223
|
+
await this.stepHistory.deleteMany({ workflowStepId: { $in: stepIds } })
|
|
224
|
+
await this.steps.deleteMany({ workflowRunId: id })
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const result = await this.runs.deleteOne({ _id: id })
|
|
228
|
+
return result.deletedCount > 0
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private mapRunRow(row: WorkflowRunDoc): WorkflowRun {
|
|
232
|
+
return {
|
|
233
|
+
id: row._id,
|
|
234
|
+
workflow: row.workflow,
|
|
235
|
+
status: row.status as WorkflowStatus,
|
|
236
|
+
input: row.input,
|
|
237
|
+
output: row.output ?? undefined,
|
|
238
|
+
error: row.error ?? undefined,
|
|
239
|
+
inline: row.inline,
|
|
240
|
+
graphHash: row.graphHash ?? undefined,
|
|
241
|
+
wire: row.wire ?? { type: 'unknown' },
|
|
242
|
+
createdAt: new Date(row.createdAt),
|
|
243
|
+
updatedAt: new Date(row.updatedAt),
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|