@adhdev/daemon-core 0.9.82-rc.133 → 0.9.82-rc.134
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 +46 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/mesh/mesh-events.ts +35 -14
- package/src/providers/cli-provider-instance.ts +30 -3
package/package.json
CHANGED
package/src/mesh/mesh-events.ts
CHANGED
|
@@ -415,22 +415,38 @@ function findRecentTerminalLedgerEvidence(args: {
|
|
|
415
415
|
meshId: string;
|
|
416
416
|
sessionId?: string;
|
|
417
417
|
nodeId?: string;
|
|
418
|
-
}): { kind: MeshLedgerKind; payload: Record<string, unknown>; timestamp: string } | null {
|
|
418
|
+
}): { id: string; kind: MeshLedgerKind; payload: Record<string, unknown>; timestamp: string } | null {
|
|
419
419
|
if (!args.sessionId && !args.nodeId) return null;
|
|
420
420
|
const entries = readLedgerEntries(args.meshId);
|
|
421
421
|
for (let i = entries.length - 1; i >= 0; i--) {
|
|
422
422
|
const entry = entries[i];
|
|
423
423
|
if (entry.kind !== 'task_completed' && entry.kind !== 'task_failed' && entry.kind !== 'task_stalled') continue;
|
|
424
424
|
if (args.sessionId && entry.sessionId === args.sessionId) {
|
|
425
|
-
return { kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
425
|
+
return { id: entry.id, kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
426
426
|
}
|
|
427
427
|
if (!args.sessionId && args.nodeId && entry.nodeId === args.nodeId) {
|
|
428
|
-
return { kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
428
|
+
return { id: entry.id, kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
431
|
return null;
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
+
// Returns true when a task_dispatched entry for the given session appears AFTER the terminal
|
|
435
|
+
// entry (identified by terminalId) in ledger order. Positional (append) order is used rather
|
|
436
|
+
// than timestamp comparison because both entries may share the same millisecond.
|
|
437
|
+
function hasDispatchAfterTerminal(meshId: string, sessionId: string, terminalId: string): boolean {
|
|
438
|
+
const entries = readLedgerEntries(meshId);
|
|
439
|
+
let pastTerminal = false;
|
|
440
|
+
for (const entry of entries) {
|
|
441
|
+
if (!pastTerminal) {
|
|
442
|
+
if (entry.id === terminalId) pastTerminal = true;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (entry.kind === 'task_dispatched' && entry.sessionId === sessionId) return true;
|
|
446
|
+
}
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
|
|
434
450
|
function buildLongGeneratingCompletionReconciliation(args: {
|
|
435
451
|
meshId: string;
|
|
436
452
|
nodeId?: string;
|
|
@@ -1060,17 +1076,22 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
1060
1076
|
nodeId: eventNodeId || undefined,
|
|
1061
1077
|
});
|
|
1062
1078
|
if (terminal?.kind === 'task_completed' && !sessionHasActiveAssignment(args.meshId, eventSessionId)) {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
const
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1079
|
+
// If a new task_dispatched was recorded for this session after the prior terminal,
|
|
1080
|
+
// this completion belongs to the new task — never suppress it as a duplicate.
|
|
1081
|
+
const newDispatchAfterTerminal = hasDispatchAfterTerminal(args.meshId, eventSessionId, terminal.id);
|
|
1082
|
+
if (!newDispatchAfterTerminal) {
|
|
1083
|
+
const terminalProviderSessionId = readNonEmptyString(terminal.payload.providerSessionId);
|
|
1084
|
+
const terminalFinalSummary = readNonEmptyString(terminal.payload.finalSummary);
|
|
1085
|
+
const eventProviderSessionId = readNonEmptyString(args.metadataEvent.providerSessionId);
|
|
1086
|
+
const eventFinalSummary = readNonEmptyString(args.metadataEvent.finalSummary);
|
|
1087
|
+
if (
|
|
1088
|
+
(terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId)
|
|
1089
|
+
|| (terminalFinalSummary && terminalFinalSummary === eventFinalSummary)
|
|
1090
|
+
|| args.metadataEvent.source === 'long_generating_reconciliation'
|
|
1091
|
+
) {
|
|
1092
|
+
LOG.info('MeshEvents', `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
1093
|
+
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
1094
|
+
}
|
|
1074
1095
|
}
|
|
1075
1096
|
}
|
|
1076
1097
|
const duplicateCompletion = isDuplicateMeshCompletionEvent({
|
|
@@ -899,7 +899,16 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
899
899
|
if (!isCliGeneratingLikeStatus(parsedRawStatus)) return false;
|
|
900
900
|
if (adapterRawStatus !== 'idle') return false;
|
|
901
901
|
if (hasNonEmptyCliModalButtons(parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
|
|
902
|
-
|
|
902
|
+
if (this.hasAdapterPendingResponse()) return false;
|
|
903
|
+
// Do not suppress when the adapter's raw response buffer is still non-empty.
|
|
904
|
+
// This catches the case where isWaitingForResponse has already flipped to false
|
|
905
|
+
// (so getPartialResponse() returns '') but the provider's native parser still
|
|
906
|
+
// reports generating because it's parsing buffered content. Suppressing the
|
|
907
|
+
// finalization block here would emit a false completion event while the provider
|
|
908
|
+
// session is still actively processing its response stream.
|
|
909
|
+
const adapterAny = this.adapter as any;
|
|
910
|
+
if (typeof adapterAny?.responseBuffer === 'string' && adapterAny.responseBuffer.trim()) return false;
|
|
911
|
+
return true;
|
|
903
912
|
}
|
|
904
913
|
|
|
905
914
|
private getCompletedFinalizationBlock(latestVisibleStatus: string): CompletedFinalizationBlock | null {
|
|
@@ -1122,12 +1131,30 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1122
1131
|
}
|
|
1123
1132
|
} else if (newStatus === 'idle' && (this.lastStatus === 'generating' || this.lastStatus === 'waiting_approval')) {
|
|
1124
1133
|
const duration = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1000) : 0;
|
|
1125
|
-
// If debounce still pending (generating lasted < 1s), cancel both events
|
|
1134
|
+
// If debounce still pending (generating lasted < 1s), cancel both UI events.
|
|
1135
|
+
// Still emit agent:generating_completed so mesh orchestration can record
|
|
1136
|
+
// task_completed for direct dispatches that complete faster than the debounce.
|
|
1126
1137
|
if (this.generatingDebouncePending) {
|
|
1127
|
-
|
|
1138
|
+
const shortDurationMs = this.generatingStartedAt ? now - this.generatingStartedAt : 0;
|
|
1139
|
+
LOG.info('CLI', `[${this.type}] suppressed short generating (${shortDurationMs}ms)`);
|
|
1128
1140
|
if (this.generatingDebounceTimer) { clearTimeout(this.generatingDebounceTimer); this.generatingDebounceTimer = null; }
|
|
1129
1141
|
this.generatingDebouncePending = null;
|
|
1130
1142
|
this.generatingStartedAt = 0;
|
|
1143
|
+
// Emit completion for mesh task association even though the UI generating
|
|
1144
|
+
// started/completed pair is suppressed (too short for visible UI update).
|
|
1145
|
+
let shortFinalSummary: string | undefined;
|
|
1146
|
+
try { shortFinalSummary = extractFinalSummaryFromMessages(this.adapter?.getScriptParsedStatus()?.messages); } catch { /* best-effort */ }
|
|
1147
|
+
this.pushEvent({
|
|
1148
|
+
event: 'agent:generating_completed',
|
|
1149
|
+
chatTitle,
|
|
1150
|
+
duration: 0,
|
|
1151
|
+
timestamp: now,
|
|
1152
|
+
finalSummary: shortFinalSummary,
|
|
1153
|
+
completionDiagnostic: {
|
|
1154
|
+
reason: 'short_generating_suppressed',
|
|
1155
|
+
shortDurationMs,
|
|
1156
|
+
},
|
|
1157
|
+
});
|
|
1131
1158
|
} else {
|
|
1132
1159
|
// Debounce completed, then require the rich transcript path that read_chat
|
|
1133
1160
|
// uses to show an idle turn whose last user-facing message is assistant.
|