@adhdev/daemon-core 0.9.82-rc.24 → 0.9.82-rc.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/dist/index.js +64 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -9
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +9 -0
- package/dist/mesh/mesh-work-queue.d.ts +3 -1
- package/package.json +1 -1
- package/src/mesh/mesh-events.ts +77 -1
- package/src/mesh/mesh-work-queue.ts +7 -4
|
@@ -26,12 +26,21 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
|
|
|
26
26
|
forwarded: number;
|
|
27
27
|
suppressed: boolean;
|
|
28
28
|
intentionalCleanupStop: boolean;
|
|
29
|
+
duplicateCompletion?: undefined;
|
|
30
|
+
error?: undefined;
|
|
31
|
+
} | {
|
|
32
|
+
success: boolean;
|
|
33
|
+
forwarded: number;
|
|
34
|
+
suppressed: boolean;
|
|
35
|
+
duplicateCompletion: boolean;
|
|
36
|
+
intentionalCleanupStop?: undefined;
|
|
29
37
|
error?: undefined;
|
|
30
38
|
} | {
|
|
31
39
|
success: boolean;
|
|
32
40
|
forwarded: number;
|
|
33
41
|
suppressed?: undefined;
|
|
34
42
|
intentionalCleanupStop?: undefined;
|
|
43
|
+
duplicateCompletion?: undefined;
|
|
35
44
|
error?: undefined;
|
|
36
45
|
} | {
|
|
37
46
|
success: boolean;
|
|
@@ -80,7 +80,9 @@ export declare function requeueTask(meshId: string, taskId: string, opts?: {
|
|
|
80
80
|
/**
|
|
81
81
|
* Update the status of the task currently assigned to a specific session.
|
|
82
82
|
*/
|
|
83
|
-
export declare function updateSessionTaskStatus(meshId: string, sessionId: string, status: MeshTaskStatus
|
|
83
|
+
export declare function updateSessionTaskStatus(meshId: string, sessionId: string, status: MeshTaskStatus, opts?: {
|
|
84
|
+
occurredAt?: string;
|
|
85
|
+
}): MeshWorkQueueEntry | null;
|
|
84
86
|
export interface MeshWorkQueueStats {
|
|
85
87
|
total: number;
|
|
86
88
|
active: number;
|
package/package.json
CHANGED
package/src/mesh/mesh-events.ts
CHANGED
|
@@ -189,6 +189,62 @@ function shouldSuppressIntentionalCleanupStop(args: {
|
|
|
189
189
|
return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
const RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1000;
|
|
193
|
+
const recentCompletionFingerprints = new Map<string, number>();
|
|
194
|
+
|
|
195
|
+
function readEventTimestamp(value: unknown): number | null {
|
|
196
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
197
|
+
if (typeof value === 'string' && value.trim()) {
|
|
198
|
+
const numeric = Number(value);
|
|
199
|
+
if (Number.isFinite(numeric)) return numeric;
|
|
200
|
+
const parsed = Date.parse(value);
|
|
201
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function buildMeshCompletionFingerprint(args: {
|
|
207
|
+
meshId: string;
|
|
208
|
+
event: string;
|
|
209
|
+
sessionId: string;
|
|
210
|
+
providerType?: string;
|
|
211
|
+
providerSessionId?: string;
|
|
212
|
+
timestamp?: number | null;
|
|
213
|
+
finalSummary?: string;
|
|
214
|
+
}): string {
|
|
215
|
+
const timestampPart = Number.isFinite(args.timestamp)
|
|
216
|
+
? String(args.timestamp)
|
|
217
|
+
: readNonEmptyString(args.finalSummary).slice(0, 200);
|
|
218
|
+
return [
|
|
219
|
+
args.meshId,
|
|
220
|
+
args.event,
|
|
221
|
+
args.sessionId,
|
|
222
|
+
args.providerType || '',
|
|
223
|
+
args.providerSessionId || '',
|
|
224
|
+
timestampPart,
|
|
225
|
+
].join('::');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function isDuplicateMeshCompletionEvent(args: {
|
|
229
|
+
meshId: string;
|
|
230
|
+
event: string;
|
|
231
|
+
sessionId: string;
|
|
232
|
+
providerType?: string;
|
|
233
|
+
providerSessionId?: string;
|
|
234
|
+
timestamp?: number | null;
|
|
235
|
+
finalSummary?: string;
|
|
236
|
+
}): boolean {
|
|
237
|
+
const fingerprint = buildMeshCompletionFingerprint(args);
|
|
238
|
+
if (!fingerprint) return false;
|
|
239
|
+
const now = Date.now();
|
|
240
|
+
for (const [key, seenAt] of recentCompletionFingerprints.entries()) {
|
|
241
|
+
if (now - seenAt > RECENT_COMPLETION_FINGERPRINT_TTL_MS) recentCompletionFingerprints.delete(key);
|
|
242
|
+
}
|
|
243
|
+
if (recentCompletionFingerprints.has(fingerprint)) return true;
|
|
244
|
+
recentCompletionFingerprints.set(fingerprint, now);
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
192
248
|
|
|
193
249
|
export function tryAssignQueueTask(
|
|
194
250
|
components: DaemonComponents,
|
|
@@ -651,6 +707,23 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
651
707
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
652
708
|
}
|
|
653
709
|
|
|
710
|
+
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
711
|
+
if (args.event === 'agent:generating_completed' && eventSessionId) {
|
|
712
|
+
const duplicateCompletion = isDuplicateMeshCompletionEvent({
|
|
713
|
+
meshId: args.meshId,
|
|
714
|
+
event: args.event,
|
|
715
|
+
sessionId: eventSessionId,
|
|
716
|
+
providerType: readNonEmptyString(args.metadataEvent.providerType) || undefined,
|
|
717
|
+
providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
|
|
718
|
+
timestamp: eventTimestamp,
|
|
719
|
+
finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
|
|
720
|
+
});
|
|
721
|
+
if (duplicateCompletion) {
|
|
722
|
+
LOG.info('MeshEvents', `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
723
|
+
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
654
727
|
// ── Task Queue & Ledger ──
|
|
655
728
|
let completedTaskForLedger: { id?: string } | null = null;
|
|
656
729
|
if (args.event === 'agent:generating_completed') {
|
|
@@ -659,7 +732,9 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
659
732
|
const providerType = readNonEmptyString(args.metadataEvent.providerType);
|
|
660
733
|
|
|
661
734
|
if (sessionId) {
|
|
662
|
-
const completedTask = updateSessionTaskStatus(args.meshId, sessionId, 'completed'
|
|
735
|
+
const completedTask = updateSessionTaskStatus(args.meshId, sessionId, 'completed', {
|
|
736
|
+
occurredAt: eventTimestamp !== null ? new Date(eventTimestamp).toISOString() : undefined,
|
|
737
|
+
});
|
|
663
738
|
completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
|
|
664
739
|
if (nodeId && providerType) {
|
|
665
740
|
// Queue state is already updated above; setImmediate avoids the
|
|
@@ -896,6 +971,7 @@ export function handleMeshForwardEvent(components: DaemonComponents, payload: Re
|
|
|
896
971
|
providerType: readNonEmptyString(payload.providerType),
|
|
897
972
|
providerSessionId: readNonEmptyString(payload.providerSessionId),
|
|
898
973
|
finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
|
|
974
|
+
...(payload.timestamp !== undefined ? { timestamp: payload.timestamp } : {}),
|
|
899
975
|
intentional: payload.intentional === true,
|
|
900
976
|
intentionalStop: payload.intentionalStop === true,
|
|
901
977
|
operatorCleanup: payload.operatorCleanup === true,
|
|
@@ -263,16 +263,19 @@ export function updateSessionTaskStatus(
|
|
|
263
263
|
meshId: string,
|
|
264
264
|
sessionId: string,
|
|
265
265
|
status: MeshTaskStatus,
|
|
266
|
+
opts?: { occurredAt?: string },
|
|
266
267
|
): MeshWorkQueueEntry | null {
|
|
267
268
|
return withQueueLock(meshId, () => {
|
|
268
269
|
const queue = readQueue(meshId);
|
|
270
|
+
const occurredAtTime = opts?.occurredAt ? new Date(opts.occurredAt).getTime() : Number.NaN;
|
|
271
|
+
const hasOccurredAt = Number.isFinite(occurredAtTime);
|
|
269
272
|
let bestIdx = -1;
|
|
270
273
|
let bestTime = 0;
|
|
271
274
|
for (let i = queue.length - 1; i >= 0; i--) {
|
|
272
|
-
if (queue[i].assignedSessionId
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
275
|
+
if (queue[i].assignedSessionId !== sessionId || queue[i].status !== 'assigned') continue;
|
|
276
|
+
const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
|
|
277
|
+
if (hasOccurredAt && Number.isFinite(time) && time > occurredAtTime) continue;
|
|
278
|
+
if (time > bestTime) { bestTime = time; bestIdx = i; }
|
|
276
279
|
}
|
|
277
280
|
if (bestIdx === -1) return null;
|
|
278
281
|
queue[bestIdx].status = status;
|