@memberjunction/server 2.110.0 → 2.111.0
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/dist/agents/skip-sdk.d.ts.map +1 -1
- package/dist/agents/skip-sdk.js +80 -72
- package/dist/agents/skip-sdk.js.map +1 -1
- package/dist/generated/generated.d.ts +160 -11
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +1015 -70
- package/dist/generated/generated.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts +1 -14
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +3 -452
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/scheduler/LearningCycleScheduler.d.ts +0 -40
- package/dist/scheduler/LearningCycleScheduler.d.ts.map +1 -1
- package/dist/scheduler/LearningCycleScheduler.js +0 -192
- package/dist/scheduler/LearningCycleScheduler.js.map +1 -1
- package/package.json +43 -38
- package/src/agents/skip-sdk.ts +102 -89
- package/src/generated/generated.ts +642 -54
- package/src/resolvers/AskSkipResolver.ts +612 -612
- package/src/scheduler/LearningCycleScheduler.ts +261 -261
|
@@ -12,309 +12,309 @@ import { mj_core_schema } from '../config.js';
|
|
|
12
12
|
* Implements BaseSingleton pattern for cross-instance synchronization
|
|
13
13
|
*/
|
|
14
14
|
export class LearningCycleScheduler extends BaseSingleton<LearningCycleScheduler> {
|
|
15
|
-
private intervalId: NodeJS.Timeout | null = null;
|
|
15
|
+
// private intervalId: NodeJS.Timeout | null = null;
|
|
16
16
|
|
|
17
|
-
// Track executions by organization ID instead of a global flag
|
|
18
|
-
private runningOrganizations: Map<string, { startTime: Date, learningCycleId: string }> = new Map();
|
|
17
|
+
// // Track executions by organization ID instead of a global flag
|
|
18
|
+
// private runningOrganizations: Map<string, { startTime: Date, learningCycleId: string }> = new Map();
|
|
19
19
|
|
|
20
|
-
private lastRunTime: Date | null = null;
|
|
21
|
-
private dataSources: DataSourceInfo[] = [];
|
|
20
|
+
// private lastRunTime: Date | null = null;
|
|
21
|
+
// private dataSources: DataSourceInfo[] = [];
|
|
22
22
|
|
|
23
|
-
// Protected constructor to enforce singleton pattern via BaseSingleton
|
|
24
|
-
protected constructor() {
|
|
25
|
-
|
|
26
|
-
}
|
|
23
|
+
// // Protected constructor to enforce singleton pattern via BaseSingleton
|
|
24
|
+
// protected constructor() {
|
|
25
|
+
// super();
|
|
26
|
+
// }
|
|
27
27
|
|
|
28
|
-
public static get Instance(): LearningCycleScheduler {
|
|
29
|
-
|
|
30
|
-
}
|
|
28
|
+
// public static get Instance(): LearningCycleScheduler {
|
|
29
|
+
// return super.getInstance<LearningCycleScheduler>();
|
|
30
|
+
// }
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
public setDataSources(dataSources: DataSourceInfo[]): void {
|
|
37
|
-
|
|
38
|
-
}
|
|
32
|
+
// /**
|
|
33
|
+
// * Set the data sources for the scheduler
|
|
34
|
+
// * @param dataSources Array of data sources
|
|
35
|
+
// */
|
|
36
|
+
// public setDataSources(dataSources: DataSourceInfo[]): void {
|
|
37
|
+
// this.dataSources = dataSources;
|
|
38
|
+
// }
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
public start(intervalMinutes: number = 60): void {
|
|
46
|
-
|
|
40
|
+
// /**
|
|
41
|
+
// * Start the scheduler with the specified interval in minutes
|
|
42
|
+
// * @param intervalMinutes The interval in minutes between runs
|
|
43
|
+
// * @param skipLearningAPIurl The URL for the learning cycle API endpoint
|
|
44
|
+
// */
|
|
45
|
+
// public start(intervalMinutes: number = 60): void {
|
|
46
|
+
// LogStatus(`Starting learning cycle scheduler with interval of ${intervalMinutes} minutes`);
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
// // Set up the interval for recurring calls
|
|
49
|
+
// const intervalMs = intervalMinutes * 60 * 1000;
|
|
50
|
+
// this.intervalId = setInterval(() => {
|
|
51
|
+
// this.runLearningCycle()
|
|
52
|
+
// .catch(error => LogError(`Error in scheduled learning cycle: ${error}`));
|
|
53
|
+
// }, intervalMs);
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
55
|
+
// // Start learning cycle immediately upon the server start
|
|
56
|
+
// this.runLearningCycle()
|
|
57
|
+
// .catch(error => LogError(`Error in initial learning cycle: ${error}`));
|
|
58
|
+
// }
|
|
59
59
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
public stop(): void {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
60
|
+
// /**
|
|
61
|
+
// * Stop the scheduler
|
|
62
|
+
// */
|
|
63
|
+
// public stop(): void {
|
|
64
|
+
// if (this.intervalId) {
|
|
65
|
+
// clearInterval(this.intervalId);
|
|
66
|
+
// this.intervalId = null;
|
|
67
|
+
// LogStatus('Learning cycle scheduler stopped');
|
|
68
|
+
// }
|
|
69
|
+
// }
|
|
70
70
|
|
|
71
|
-
/**
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
public async runLearningCycle(): Promise<boolean> {
|
|
76
|
-
|
|
71
|
+
// /**
|
|
72
|
+
// * Run the learning cycle if it's not already running
|
|
73
|
+
// * @returns A promise that resolves when the learning cycle completes
|
|
74
|
+
// */
|
|
75
|
+
// public async runLearningCycle(): Promise<boolean> {
|
|
76
|
+
// const startTime = new Date();
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
// try {
|
|
79
|
+
// // Make sure we have data sources
|
|
80
|
+
// if (!this.dataSources || this.dataSources.length === 0) {
|
|
81
|
+
// throw new Error('No data sources available for the learning cycle');
|
|
82
|
+
// }
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
// const dataSource = GetReadWriteDataSource(this.dataSources);
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
// // Get system user for operation
|
|
87
|
+
// const systemUser = await getSystemUser(dataSource);
|
|
88
|
+
// if (!systemUser) {
|
|
89
|
+
// throw new Error('System user not found');
|
|
90
|
+
// }
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
// // Create context for the resolver
|
|
93
|
+
// const config = new SQLServerProviderConfigData(dataSource, mj_core_schema, 0, undefined, undefined, false);
|
|
94
|
+
// const p = new SQLServerDataProvider();
|
|
95
|
+
// await p.Config(config);
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
// const context: AppContext = {
|
|
98
|
+
// dataSource: dataSource,
|
|
99
|
+
// dataSources: this.dataSources,
|
|
100
|
+
// userPayload: {
|
|
101
|
+
// email: systemUser.Email,
|
|
102
|
+
// sessionId: `scheduler_${Date.now()}`,
|
|
103
|
+
// userRecord: systemUser,
|
|
104
|
+
// isSystemUser: true
|
|
105
|
+
// },
|
|
106
|
+
// providers: [{provider: p, type: 'Read-Write'}]
|
|
107
|
+
// };
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
// // Execute the learning cycle
|
|
110
|
+
// const skipResolver = new AskSkipResolver();
|
|
111
|
+
// const result = await skipResolver.ExecuteAskSkipLearningCycle(
|
|
112
|
+
// context,
|
|
113
|
+
// false // forceEntityRefresh
|
|
114
|
+
// );
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
// const endTime = new Date();
|
|
117
|
+
// const elapsedMs = endTime.getTime() - startTime.getTime();
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
// this.lastRunTime = startTime;
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
121
|
+
// if (result.learningCycleSkipped) {
|
|
122
|
+
// // skipped the learning cycle - no messages to process, already logged..
|
|
123
|
+
// return true;
|
|
124
|
+
// }
|
|
125
|
+
// else if (result.success) {
|
|
126
|
+
// LogStatus(`Learning cycle completed successfully in ${elapsedMs}ms`);
|
|
127
|
+
// return true;
|
|
128
|
+
// }
|
|
129
|
+
// else {
|
|
130
|
+
// LogError(`Learning cycle failed after ${elapsedMs}ms: ${result.error}`);
|
|
131
|
+
// return false;
|
|
132
|
+
// }
|
|
133
|
+
// } catch (error) {
|
|
134
|
+
// LogError(`Error executing learning cycle: ${error}`);
|
|
135
|
+
// return false;
|
|
136
|
+
// }
|
|
137
|
+
// }
|
|
138
138
|
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
public getStatus() {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
139
|
+
// /**
|
|
140
|
+
// * Get the current status of the scheduler
|
|
141
|
+
// */
|
|
142
|
+
// public getStatus() {
|
|
143
|
+
// return {
|
|
144
|
+
// isSchedulerRunning: this.intervalId !== null,
|
|
145
|
+
// lastRunTime: this.lastRunTime,
|
|
146
|
+
// runningOrganizations: Array.from(this.runningOrganizations.entries()).map(([orgId, info]) => ({
|
|
147
|
+
// organizationId: orgId,
|
|
148
|
+
// learningCycleId: info.learningCycleId,
|
|
149
|
+
// startTime: info.startTime,
|
|
150
|
+
// runningForMinutes: (new Date().getTime() - info.startTime.getTime()) / (1000 * 60)
|
|
151
|
+
// }))
|
|
152
|
+
// };
|
|
153
|
+
// }
|
|
154
154
|
|
|
155
|
-
/**
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
public isOrganizationRunningCycle(
|
|
161
|
-
|
|
162
|
-
): { isRunning: boolean, startTime?: Date, learningCycleId?: string, runningForMinutes?: number } {
|
|
163
|
-
|
|
155
|
+
// /**
|
|
156
|
+
// * Checks if an organization is currently running a learning cycle
|
|
157
|
+
// * @param organizationId The organization ID to check
|
|
158
|
+
// * @returns Whether the organization is running a cycle and details if running
|
|
159
|
+
// */
|
|
160
|
+
// public isOrganizationRunningCycle(
|
|
161
|
+
// organizationId: string
|
|
162
|
+
// ): { isRunning: boolean, startTime?: Date, learningCycleId?: string, runningForMinutes?: number } {
|
|
163
|
+
// const runningInfo = this.runningOrganizations.get(organizationId);
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
// if (runningInfo) {
|
|
166
|
+
// // Check if it's been running too long and should be considered stalled
|
|
167
|
+
// const now = new Date();
|
|
168
|
+
// const elapsedMinutes = (now.getTime() - runningInfo.startTime.getTime()) / (1000 * 60);
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
// return {
|
|
171
|
+
// isRunning: true,
|
|
172
|
+
// startTime: runningInfo.startTime,
|
|
173
|
+
// learningCycleId: runningInfo.learningCycleId,
|
|
174
|
+
// runningForMinutes: elapsedMinutes
|
|
175
|
+
// };
|
|
176
|
+
// }
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
}
|
|
178
|
+
// return { isRunning: false };
|
|
179
|
+
// }
|
|
180
180
|
|
|
181
|
-
/**
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
public registerRunningCycle(organizationId: string, learningCycleId: string): boolean {
|
|
188
|
-
|
|
189
|
-
|
|
181
|
+
// /**
|
|
182
|
+
// * Registers an organization as running a learning cycle
|
|
183
|
+
// * @param organizationId The organization ID to register
|
|
184
|
+
// * @param learningCycleId The ID of the learning cycle
|
|
185
|
+
// * @returns true if successfully registered, false if already running
|
|
186
|
+
// */
|
|
187
|
+
// public registerRunningCycle(organizationId: string, learningCycleId: string): boolean {
|
|
188
|
+
// // First check if already running
|
|
189
|
+
// const { isRunning } = this.isOrganizationRunningCycle(organizationId);
|
|
190
190
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
// if (isRunning) {
|
|
192
|
+
// return false;
|
|
193
|
+
// }
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
195
|
+
// // Register the organization as running a cycle
|
|
196
|
+
// this.runningOrganizations.set(organizationId, {
|
|
197
|
+
// startTime: new Date(),
|
|
198
|
+
// learningCycleId
|
|
199
|
+
// });
|
|
200
200
|
|
|
201
|
-
|
|
202
|
-
}
|
|
201
|
+
// return true;
|
|
202
|
+
// }
|
|
203
203
|
|
|
204
|
-
/**
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
public unregisterRunningCycle(organizationId: string): boolean {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
204
|
+
// /**
|
|
205
|
+
// * Unregisters an organization after its learning cycle completes
|
|
206
|
+
// * @param organizationId The organization ID to unregister
|
|
207
|
+
// * @returns true if successfully unregistered, false if wasn't registered
|
|
208
|
+
// */
|
|
209
|
+
// public unregisterRunningCycle(organizationId: string): boolean {
|
|
210
|
+
// if (this.runningOrganizations.has(organizationId)) {
|
|
211
|
+
// this.runningOrganizations.delete(organizationId);
|
|
212
|
+
// return true;
|
|
213
|
+
// }
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
}
|
|
215
|
+
// return false;
|
|
216
|
+
// }
|
|
217
217
|
|
|
218
|
-
/**
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
public async manuallyExecuteLearningCycle(organizationId?: string): Promise<boolean> {
|
|
226
|
-
|
|
227
|
-
|
|
218
|
+
// /**
|
|
219
|
+
// * Manually execute a learning cycle run for testing purposes
|
|
220
|
+
// * This is intended for debugging/testing only and will force a run
|
|
221
|
+
// * even if the scheduler is not started
|
|
222
|
+
// * @param organizationId Optional organization ID to register for the manual run
|
|
223
|
+
// * @returns A promise that resolves when the learning cycle completes
|
|
224
|
+
// */
|
|
225
|
+
// public async manuallyExecuteLearningCycle(organizationId?: string): Promise<boolean> {
|
|
226
|
+
// try {
|
|
227
|
+
// LogStatus('🧪 Manually executing learning cycle for testing...');
|
|
228
228
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
229
|
+
// // If an organization ID is provided, register it as running
|
|
230
|
+
// const learningCycleId = `manual_${Date.now()}`;
|
|
231
|
+
// let orgRegistered = false;
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
// if (organizationId) {
|
|
234
|
+
// // Check if already running
|
|
235
|
+
// const runningStatus = this.isOrganizationRunningCycle(organizationId);
|
|
236
236
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
// if (runningStatus.isRunning) {
|
|
238
|
+
// LogError(`Organization ${organizationId} is already running a learning cycle. Cannot start a new one.`);
|
|
239
|
+
// return false;
|
|
240
|
+
// }
|
|
241
241
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
242
|
+
// // Register this organization
|
|
243
|
+
// orgRegistered = this.registerRunningCycle(organizationId, learningCycleId);
|
|
244
|
+
// if (!orgRegistered) {
|
|
245
|
+
// LogError(`Failed to register organization ${organizationId} for manual learning cycle execution`);
|
|
246
|
+
// return false;
|
|
247
|
+
// }
|
|
248
|
+
// }
|
|
249
249
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
250
|
+
// // Run the learning cycle
|
|
251
|
+
// const result = await this.runLearningCycle();
|
|
252
|
+
// LogStatus(`🧪 Manual learning cycle execution completed with result: ${result ? 'Success' : 'Failed'}`);
|
|
253
253
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
// // Unregister the organization if it was registered
|
|
255
|
+
// if (organizationId && orgRegistered) {
|
|
256
|
+
// this.unregisterRunningCycle(organizationId);
|
|
257
|
+
// }
|
|
258
258
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
259
|
+
// return result;
|
|
260
|
+
// } catch (error) {
|
|
261
|
+
// // Make sure to unregister on error
|
|
262
|
+
// if (organizationId && this.runningOrganizations.has(organizationId)) {
|
|
263
|
+
// this.unregisterRunningCycle(organizationId);
|
|
264
|
+
// }
|
|
265
265
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
266
|
+
// LogError(`Error in manual learning cycle execution: ${error}`);
|
|
267
|
+
// return false;
|
|
268
|
+
// }
|
|
269
|
+
// }
|
|
270
270
|
|
|
271
|
-
/**
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
public stopLearningCycleForOrganization(organizationId: string): {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
} {
|
|
282
|
-
|
|
283
|
-
|
|
271
|
+
// /**
|
|
272
|
+
// * Force stop a running learning cycle for an organization
|
|
273
|
+
// * @param organizationId The organization ID to stop the cycle for
|
|
274
|
+
// * @returns Information about the stopped cycle
|
|
275
|
+
// */
|
|
276
|
+
// public stopLearningCycleForOrganization(organizationId: string): {
|
|
277
|
+
// success: boolean,
|
|
278
|
+
// message: string,
|
|
279
|
+
// wasRunning: boolean,
|
|
280
|
+
// cycleDetails?: { learningCycleId: string, startTime: Date, runningForMinutes: number }
|
|
281
|
+
// } {
|
|
282
|
+
// // Check if this organization has a running cycle
|
|
283
|
+
// const runningStatus = this.isOrganizationRunningCycle(organizationId);
|
|
284
284
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
285
|
+
// if (!runningStatus.isRunning) {
|
|
286
|
+
// return {
|
|
287
|
+
// success: false,
|
|
288
|
+
// message: `No running learning cycle found for organization ${organizationId}`,
|
|
289
|
+
// wasRunning: false
|
|
290
|
+
// };
|
|
291
|
+
// }
|
|
292
292
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
293
|
+
// // Capture details before unregistering
|
|
294
|
+
// const startTime = runningStatus.startTime!;
|
|
295
|
+
// const learningCycleId = runningStatus.learningCycleId!;
|
|
296
|
+
// const runningForMinutes = runningStatus.runningForMinutes!;
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
|
|
298
|
+
// // Unregister the organization
|
|
299
|
+
// const unregistered = this.unregisterRunningCycle(organizationId);
|
|
300
300
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
301
|
+
// if (unregistered) {
|
|
302
|
+
// return {
|
|
303
|
+
// success: true,
|
|
304
|
+
// message: `Successfully stopped learning cycle for organization ${organizationId}`,
|
|
305
|
+
// wasRunning: true,
|
|
306
|
+
// cycleDetails: {
|
|
307
|
+
// learningCycleId,
|
|
308
|
+
// startTime,
|
|
309
|
+
// runningForMinutes
|
|
310
|
+
// }
|
|
311
|
+
// };
|
|
312
|
+
// } else {
|
|
313
|
+
// return {
|
|
314
|
+
// success: false,
|
|
315
|
+
// message: `Failed to stop learning cycle for organization ${organizationId}`,
|
|
316
|
+
// wasRunning: true
|
|
317
|
+
// };
|
|
318
|
+
// }
|
|
319
|
+
// }
|
|
320
320
|
}
|