@adhdev/daemon-core 0.9.82-rc.121 → 0.9.82-rc.122
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/cli-adapter-types.d.ts +4 -1
- package/dist/cli-adapters/provider-cli-adapter.d.ts +4 -1
- package/dist/index.js +268 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +268 -33
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +28 -0
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/package.json +1 -1
- package/src/cli-adapter-types.ts +2 -1
- package/src/cli-adapters/provider-cli-adapter.ts +20 -1
- package/src/commands/chat-commands.ts +12 -2
- package/src/commands/cli-manager.ts +9 -1
- package/src/mesh/mesh-events.ts +220 -15
- package/src/providers/cli-provider-instance.ts +42 -3
package/dist/index.mjs
CHANGED
|
@@ -2558,7 +2558,7 @@ function hasPendingRefineTerminalEventDuplicate(event) {
|
|
|
2558
2558
|
if (!REFINE_TERMINAL_EVENTS.has(event.event)) return false;
|
|
2559
2559
|
const jobId = readRefineJobId(event);
|
|
2560
2560
|
if (!jobId) return false;
|
|
2561
|
-
return
|
|
2561
|
+
return readPendingMeshCoordinatorEventsFromDisk(event.meshId).some(
|
|
2562
2562
|
(pending) => pending.event === event.event && readRefineJobId(pending) === jobId
|
|
2563
2563
|
);
|
|
2564
2564
|
}
|
|
@@ -2583,12 +2583,91 @@ function buildPendingEventFingerprint(event) {
|
|
|
2583
2583
|
function hasPendingCoordinatorEventDuplicate(event) {
|
|
2584
2584
|
const fingerprint = buildPendingEventFingerprint(event);
|
|
2585
2585
|
if (!fingerprint.trim()) return false;
|
|
2586
|
-
return
|
|
2586
|
+
return readPendingMeshCoordinatorEventsFromDisk(event.meshId).some((pending) => buildPendingEventFingerprint(pending) === fingerprint);
|
|
2587
2587
|
}
|
|
2588
2588
|
function getPendingEventsPath(meshId) {
|
|
2589
2589
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2590
2590
|
return join11(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
2591
2591
|
}
|
|
2592
|
+
function readPendingMeshCoordinatorEventsFromDisk(meshId) {
|
|
2593
|
+
if (!meshId) return [];
|
|
2594
|
+
const path28 = getPendingEventsPath(meshId);
|
|
2595
|
+
if (!existsSync11(path28)) return [];
|
|
2596
|
+
try {
|
|
2597
|
+
const raw = readFileSync7(path28, "utf-8");
|
|
2598
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
2599
|
+
try {
|
|
2600
|
+
return [JSON.parse(line)];
|
|
2601
|
+
} catch {
|
|
2602
|
+
return [];
|
|
2603
|
+
}
|
|
2604
|
+
});
|
|
2605
|
+
} catch {
|
|
2606
|
+
return [];
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
function refineTerminalEventFromLedger(meshId, pending) {
|
|
2610
|
+
const acceptedJobIds = new Set(
|
|
2611
|
+
pending.filter((event) => event.event === "refine:accepted").map((event) => readRefineJobId(event)).filter(Boolean)
|
|
2612
|
+
);
|
|
2613
|
+
if (acceptedJobIds.size === 0) return [];
|
|
2614
|
+
const existingTerminalJobIds = new Set(
|
|
2615
|
+
pending.filter((event) => REFINE_TERMINAL_EVENTS.has(event.event)).map((event) => `${event.event}:${readRefineJobId(event)}`).filter((value) => !value.endsWith(":"))
|
|
2616
|
+
);
|
|
2617
|
+
const backfilled = [];
|
|
2618
|
+
const entries = readLedgerEntries(meshId);
|
|
2619
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
2620
|
+
const entry = entries[i];
|
|
2621
|
+
if (entry.kind !== "task_completed" && entry.kind !== "task_failed") continue;
|
|
2622
|
+
const payload = readRecord2(entry.payload);
|
|
2623
|
+
if (payload?.source !== "refine_mesh_node_async_job") continue;
|
|
2624
|
+
const refineJob = readRecord2(payload.refineJob);
|
|
2625
|
+
const jobId = readNonEmptyString2(refineJob?.jobId);
|
|
2626
|
+
if (!jobId || !acceptedJobIds.has(jobId)) continue;
|
|
2627
|
+
const eventName = entry.kind === "task_completed" ? "refine:completed" : "refine:failed";
|
|
2628
|
+
if (existingTerminalJobIds.has(`${eventName}:${jobId}`)) continue;
|
|
2629
|
+
existingTerminalJobIds.add(`${eventName}:${jobId}`);
|
|
2630
|
+
const result = readRecord2(payload.result);
|
|
2631
|
+
const metadataEvent = {
|
|
2632
|
+
source: "refine_mesh_node_async_job",
|
|
2633
|
+
jobId,
|
|
2634
|
+
interactionId: readNonEmptyString2(refineJob?.interactionId),
|
|
2635
|
+
meshId,
|
|
2636
|
+
nodeId: readNonEmptyString2(refineJob?.nodeId) || entry.nodeId,
|
|
2637
|
+
targetDaemonId: readNonEmptyString2(refineJob?.targetDaemonId),
|
|
2638
|
+
workspace: readNonEmptyString2(refineJob?.workspace),
|
|
2639
|
+
status: eventName === "refine:completed" ? "completed" : "failed",
|
|
2640
|
+
startedAt: readNonEmptyString2(refineJob?.startedAt),
|
|
2641
|
+
completedAt: readNonEmptyString2(refineJob?.completedAt) || entry.timestamp,
|
|
2642
|
+
retryOfJobId: readNonEmptyString2(refineJob?.retryOfJobId) || readNonEmptyString2(payload.retryOfJobId),
|
|
2643
|
+
...result ? { result } : {}
|
|
2644
|
+
};
|
|
2645
|
+
backfilled.push({
|
|
2646
|
+
event: eventName,
|
|
2647
|
+
meshId,
|
|
2648
|
+
nodeLabel: readNonEmptyString2(refineJob?.nodeId) || entry.nodeId || "refine job",
|
|
2649
|
+
nodeId: readNonEmptyString2(refineJob?.nodeId) || entry.nodeId,
|
|
2650
|
+
workspace: readNonEmptyString2(refineJob?.workspace),
|
|
2651
|
+
metadataEvent,
|
|
2652
|
+
coordinatorMessage: buildMeshSystemMessage({
|
|
2653
|
+
event: eventName,
|
|
2654
|
+
nodeLabel: readNonEmptyString2(refineJob?.nodeId) || entry.nodeId || "refine job",
|
|
2655
|
+
metadataEvent
|
|
2656
|
+
}),
|
|
2657
|
+
queuedAt: Date.now()
|
|
2658
|
+
});
|
|
2659
|
+
}
|
|
2660
|
+
return backfilled.reverse();
|
|
2661
|
+
}
|
|
2662
|
+
function reconcilePendingMeshCoordinatorEvents(meshId, events) {
|
|
2663
|
+
const backfilled = refineTerminalEventFromLedger(meshId, events);
|
|
2664
|
+
if (backfilled.length === 0) return events;
|
|
2665
|
+
const terminalJobIds = new Set(backfilled.map((event) => readRefineJobId(event)).filter(Boolean));
|
|
2666
|
+
return [
|
|
2667
|
+
...events.filter((event) => !(event.event === "refine:accepted" && terminalJobIds.has(readRefineJobId(event)))),
|
|
2668
|
+
...backfilled
|
|
2669
|
+
];
|
|
2670
|
+
}
|
|
2592
2671
|
function queuePendingMeshCoordinatorEvent(event) {
|
|
2593
2672
|
try {
|
|
2594
2673
|
if (hasPendingRefineTerminalEventDuplicate(event)) {
|
|
@@ -2611,38 +2690,19 @@ function drainPendingMeshCoordinatorEvents(meshId) {
|
|
|
2611
2690
|
const path28 = getPendingEventsPath(meshId);
|
|
2612
2691
|
if (!existsSync11(path28)) return [];
|
|
2613
2692
|
try {
|
|
2614
|
-
const
|
|
2693
|
+
const parsed = readPendingMeshCoordinatorEventsFromDisk(meshId);
|
|
2615
2694
|
try {
|
|
2616
2695
|
unlinkSync2(path28);
|
|
2617
2696
|
} catch {
|
|
2618
2697
|
}
|
|
2619
|
-
return
|
|
2620
|
-
try {
|
|
2621
|
-
return [JSON.parse(line)];
|
|
2622
|
-
} catch {
|
|
2623
|
-
return [];
|
|
2624
|
-
}
|
|
2625
|
-
});
|
|
2698
|
+
return reconcilePendingMeshCoordinatorEvents(meshId, parsed);
|
|
2626
2699
|
} catch {
|
|
2627
2700
|
return [];
|
|
2628
2701
|
}
|
|
2629
2702
|
}
|
|
2630
2703
|
function getPendingMeshCoordinatorEvents(meshId) {
|
|
2631
2704
|
if (!meshId) return [];
|
|
2632
|
-
|
|
2633
|
-
if (!existsSync11(path28)) return [];
|
|
2634
|
-
try {
|
|
2635
|
-
const raw = readFileSync7(path28, "utf-8");
|
|
2636
|
-
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
2637
|
-
try {
|
|
2638
|
-
return [JSON.parse(line)];
|
|
2639
|
-
} catch {
|
|
2640
|
-
return [];
|
|
2641
|
-
}
|
|
2642
|
-
});
|
|
2643
|
-
} catch {
|
|
2644
|
-
return [];
|
|
2645
|
-
}
|
|
2705
|
+
return reconcilePendingMeshCoordinatorEvents(meshId, readPendingMeshCoordinatorEventsFromDisk(meshId));
|
|
2646
2706
|
}
|
|
2647
2707
|
function clearPendingMeshCoordinatorEvents(meshId) {
|
|
2648
2708
|
if (!meshId) return;
|
|
@@ -2747,6 +2807,62 @@ function isDuplicateRefineTerminalEvent(meshId, eventName, metadataEvent) {
|
|
|
2747
2807
|
recentCompletionFingerprints.set(fingerprint, now);
|
|
2748
2808
|
return false;
|
|
2749
2809
|
}
|
|
2810
|
+
function findRecentTerminalLedgerEvidence(args) {
|
|
2811
|
+
if (!args.sessionId && !args.nodeId) return null;
|
|
2812
|
+
const entries = readLedgerEntries(args.meshId);
|
|
2813
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
2814
|
+
const entry = entries[i];
|
|
2815
|
+
if (entry.kind !== "task_completed" && entry.kind !== "task_failed" && entry.kind !== "task_stalled") continue;
|
|
2816
|
+
if (args.sessionId && entry.sessionId === args.sessionId) {
|
|
2817
|
+
return { kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
2818
|
+
}
|
|
2819
|
+
if (!args.sessionId && args.nodeId && entry.nodeId === args.nodeId) {
|
|
2820
|
+
return { kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
return null;
|
|
2824
|
+
}
|
|
2825
|
+
function buildLongGeneratingCompletionReconciliation(args) {
|
|
2826
|
+
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
2827
|
+
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
2828
|
+
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
2829
|
+
const providerSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
|
|
2830
|
+
const workerResult = readWorkerResultMetadata(args.metadataEvent);
|
|
2831
|
+
const completionDiagnostic = readRecord2(args.metadataEvent.completionDiagnostic);
|
|
2832
|
+
const finalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
2833
|
+
const status = readNonEmptyString2(args.metadataEvent.status).toLowerCase();
|
|
2834
|
+
const explicitCompletionEvidence = Boolean(
|
|
2835
|
+
finalSummary || workerResult || completionDiagnostic?.finalAssistantPresent === true || status === "idle" || status === "ready" || status === "completed"
|
|
2836
|
+
);
|
|
2837
|
+
if (explicitCompletionEvidence) {
|
|
2838
|
+
return {
|
|
2839
|
+
...args.metadataEvent,
|
|
2840
|
+
targetSessionId: sessionId,
|
|
2841
|
+
providerType,
|
|
2842
|
+
providerSessionId,
|
|
2843
|
+
finalSummary,
|
|
2844
|
+
source: "long_generating_reconciliation",
|
|
2845
|
+
reconciledFromEvent: "monitor:long_generating",
|
|
2846
|
+
timestamp: args.metadataEvent.timestamp ?? Date.now(),
|
|
2847
|
+
completionDiagnostic: {
|
|
2848
|
+
...completionDiagnostic || {},
|
|
2849
|
+
reconciliationReason: "provider_completion_evidence"
|
|
2850
|
+
}
|
|
2851
|
+
};
|
|
2852
|
+
}
|
|
2853
|
+
const terminal = findRecentTerminalLedgerEvidence({
|
|
2854
|
+
meshId: args.meshId,
|
|
2855
|
+
sessionId: sessionId || void 0,
|
|
2856
|
+
nodeId: nodeId || void 0
|
|
2857
|
+
});
|
|
2858
|
+
if (!terminal) return null;
|
|
2859
|
+
return {
|
|
2860
|
+
...args.metadataEvent,
|
|
2861
|
+
source: "long_generating_terminal_ledger_suppression",
|
|
2862
|
+
terminalLedgerKind: terminal.kind,
|
|
2863
|
+
terminalLedgerAt: terminal.timestamp
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2750
2866
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
2751
2867
|
const task = claimNextTask(meshId, nodeId, sessionId);
|
|
2752
2868
|
if (!task) {
|
|
@@ -2840,6 +2956,9 @@ function activeAssignedCount(meshId) {
|
|
|
2840
2956
|
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
2841
2957
|
return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedNodeId === nodeId);
|
|
2842
2958
|
}
|
|
2959
|
+
function sessionHasActiveAssignment(meshId, sessionId) {
|
|
2960
|
+
return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedSessionId === sessionId);
|
|
2961
|
+
}
|
|
2843
2962
|
function liveSessionCountForNode(components, meshId, nodeId) {
|
|
2844
2963
|
return components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
2845
2964
|
const state = inst.getState();
|
|
@@ -3050,6 +3169,9 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
3050
3169
|
function buildMeshSystemMessage(args) {
|
|
3051
3170
|
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
3052
3171
|
if (args.event === "agent:generating_completed") {
|
|
3172
|
+
if (args.metadataEvent.source === "long_generating_reconciliation") {
|
|
3173
|
+
return `[System] ${args.nodeLabel} already has completion evidence${metadata}. The long-generating monitor reconciled the terminal handoff and marked the session complete; wait for the queued completion event/status refresh before doing any manual transcript check.`;
|
|
3174
|
+
}
|
|
3053
3175
|
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path; use mesh_read_chat once to review its final progress, but do not poll repeatedly.`;
|
|
3054
3176
|
}
|
|
3055
3177
|
if (args.event === "agent:waiting_approval") {
|
|
@@ -3087,7 +3209,7 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
3087
3209
|
return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
|
|
3088
3210
|
}
|
|
3089
3211
|
if (args.event === "monitor:long_generating") {
|
|
3090
|
-
return `[System] ${args.nodeLabel}
|
|
3212
|
+
return `[System] ${args.nodeLabel} is still reported as generating after a long interval${metadata}. Wait for pendingCoordinatorEvents or a completion/status event; if the user explicitly asks for status, make one bounded status check and then wait again.`;
|
|
3091
3213
|
}
|
|
3092
3214
|
if (args.event === "refine:accepted") {
|
|
3093
3215
|
const jobId = readRefineJobId({ metadataEvent: args.metadataEvent });
|
|
@@ -3165,12 +3287,54 @@ function injectMeshSystemMessage(components, args) {
|
|
|
3165
3287
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
3166
3288
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
3167
3289
|
}
|
|
3290
|
+
if (args.event === "monitor:long_generating") {
|
|
3291
|
+
const reconciledCompletion = buildLongGeneratingCompletionReconciliation({
|
|
3292
|
+
meshId: args.meshId,
|
|
3293
|
+
nodeId: args.nodeId,
|
|
3294
|
+
nodeLabel: args.nodeLabel,
|
|
3295
|
+
metadataEvent: args.metadataEvent,
|
|
3296
|
+
sourceInstanceId: args.sourceInstanceId
|
|
3297
|
+
});
|
|
3298
|
+
if (reconciledCompletion?.source === "long_generating_reconciliation") {
|
|
3299
|
+
LOG.info("MeshEvents", `Reconciled long-generating monitor to completion for session ${eventSessionId || "(unknown session)"}`);
|
|
3300
|
+
return injectMeshSystemMessage(components, {
|
|
3301
|
+
...args,
|
|
3302
|
+
event: "agent:generating_completed",
|
|
3303
|
+
metadataEvent: reconciledCompletion
|
|
3304
|
+
});
|
|
3305
|
+
}
|
|
3306
|
+
if (reconciledCompletion?.source === "long_generating_terminal_ledger_suppression") {
|
|
3307
|
+
LOG.info("MeshEvents", `Suppressed long-generating monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
3308
|
+
return {
|
|
3309
|
+
success: true,
|
|
3310
|
+
forwarded: 0,
|
|
3311
|
+
suppressed: true,
|
|
3312
|
+
terminalLedgerEvidence: true,
|
|
3313
|
+
terminalLedgerKind: reconciledCompletion.terminalLedgerKind
|
|
3314
|
+
};
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3168
3317
|
if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
|
|
3169
3318
|
LOG.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
|
|
3170
3319
|
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
3171
3320
|
}
|
|
3172
3321
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
3173
3322
|
if (args.event === "agent:generating_completed" && eventSessionId) {
|
|
3323
|
+
const terminal = findRecentTerminalLedgerEvidence({
|
|
3324
|
+
meshId: args.meshId,
|
|
3325
|
+
sessionId: eventSessionId,
|
|
3326
|
+
nodeId: eventNodeId || void 0
|
|
3327
|
+
});
|
|
3328
|
+
if (terminal?.kind === "task_completed" && !sessionHasActiveAssignment(args.meshId, eventSessionId)) {
|
|
3329
|
+
const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
|
|
3330
|
+
const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
|
|
3331
|
+
const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
|
|
3332
|
+
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
3333
|
+
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "long_generating_reconciliation") {
|
|
3334
|
+
LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
3335
|
+
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3174
3338
|
const duplicateCompletion = isDuplicateMeshCompletionEvent({
|
|
3175
3339
|
meshId: args.meshId,
|
|
3176
3340
|
event: args.event,
|
|
@@ -3447,6 +3611,10 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
3447
3611
|
completedAt: readNonEmptyString2(payload.completedAt),
|
|
3448
3612
|
retryOfJobId: readNonEmptyString2(payload.retryOfJobId),
|
|
3449
3613
|
...payload.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? { result: payload.result } : {},
|
|
3614
|
+
...payload.completionDiagnostic && typeof payload.completionDiagnostic === "object" && !Array.isArray(payload.completionDiagnostic) ? { completionDiagnostic: payload.completionDiagnostic } : {},
|
|
3615
|
+
...payload.workerResult && typeof payload.workerResult === "object" && !Array.isArray(payload.workerResult) ? { workerResult: payload.workerResult } : {},
|
|
3616
|
+
...payload.meshWorkerResult && typeof payload.meshWorkerResult === "object" && !Array.isArray(payload.meshWorkerResult) ? { meshWorkerResult: payload.meshWorkerResult } : {},
|
|
3617
|
+
...payload.structuredResult && typeof payload.structuredResult === "object" && !Array.isArray(payload.structuredResult) ? { structuredResult: payload.structuredResult } : {},
|
|
3450
3618
|
...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
|
|
3451
3619
|
intentional: payload.intentional === true,
|
|
3452
3620
|
intentionalStop: payload.intentionalStop === true,
|
|
@@ -6346,9 +6514,27 @@ ${lastSnapshot}`;
|
|
|
6346
6514
|
nextScreenChangeAt
|
|
6347
6515
|
), 50);
|
|
6348
6516
|
}
|
|
6349
|
-
async sendMessage(text) {
|
|
6517
|
+
async sendMessage(text, options = {}) {
|
|
6518
|
+
if (options.force === true) {
|
|
6519
|
+
await this.forceSendMessage(text);
|
|
6520
|
+
return;
|
|
6521
|
+
}
|
|
6350
6522
|
await this.sendMessageNow(text, true);
|
|
6351
6523
|
}
|
|
6524
|
+
async forceSendMessage(text) {
|
|
6525
|
+
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
6526
|
+
const content = String(text || "");
|
|
6527
|
+
if (!content.trim()) return;
|
|
6528
|
+
this.recordTrace("force_send_message", {
|
|
6529
|
+
text: summarizeCliTraceText(content, 500),
|
|
6530
|
+
status: this.currentStatus,
|
|
6531
|
+
isWaitingForResponse: this.isWaitingForResponse,
|
|
6532
|
+
queueLength: this.pendingOutboundQueue.length
|
|
6533
|
+
});
|
|
6534
|
+
LOG.info("CLI", `[${this.cliType}] force-sending prompt while status=${this.currentStatus}`);
|
|
6535
|
+
await this.writeToPty(content + this.sendKey);
|
|
6536
|
+
this.onStatusChange?.();
|
|
6537
|
+
}
|
|
6352
6538
|
enqueuePendingOutboundMessage(text, reason) {
|
|
6353
6539
|
const content = String(text || "");
|
|
6354
6540
|
const duplicate = this.pendingOutboundQueue.some((message2) => message2.content === content);
|
|
@@ -17852,8 +18038,18 @@ async function handleSendChat(h, args) {
|
|
|
17852
18038
|
assertTextOnlyInput(provider, input);
|
|
17853
18039
|
if (!text) return { success: false, error: "text required for PTY send" };
|
|
17854
18040
|
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
17855
|
-
|
|
17856
|
-
|
|
18041
|
+
const forceSend = args?.force === true || args?.forceSend === true;
|
|
18042
|
+
if (forceSend && typeof adapter.forceSendMessage === "function") {
|
|
18043
|
+
await adapter.forceSendMessage(text);
|
|
18044
|
+
} else if (forceSend) {
|
|
18045
|
+
await adapter.sendMessage(text, { force: true });
|
|
18046
|
+
} else {
|
|
18047
|
+
await adapter.sendMessage(text);
|
|
18048
|
+
}
|
|
18049
|
+
return {
|
|
18050
|
+
..._logSendSuccess(`${transport}-adapter`, adapter.cliType),
|
|
18051
|
+
...forceSend ? { forceSent: true } : {}
|
|
18052
|
+
};
|
|
17857
18053
|
} catch (e) {
|
|
17858
18054
|
return { success: false, error: `${transport} send failed: ${e.message}` };
|
|
17859
18055
|
}
|
|
@@ -20204,6 +20400,7 @@ var CliProviderInstance = class {
|
|
|
20204
20400
|
lastApprovalEventAt = 0;
|
|
20205
20401
|
autoApproveBusy = false;
|
|
20206
20402
|
autoApproveBusyTimer = null;
|
|
20403
|
+
lastAutoApprovalSignature = "";
|
|
20207
20404
|
controlValues = {};
|
|
20208
20405
|
summaryMetadata = void 0;
|
|
20209
20406
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
@@ -20713,15 +20910,26 @@ var CliProviderInstance = class {
|
|
|
20713
20910
|
}
|
|
20714
20911
|
maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
|
|
20715
20912
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
20716
|
-
if (autoApproveActive
|
|
20913
|
+
if (!autoApproveActive) {
|
|
20914
|
+
this.lastAutoApprovalSignature = "";
|
|
20915
|
+
return autoApproveActive;
|
|
20916
|
+
}
|
|
20917
|
+
const modal = adapterStatus.activeModal;
|
|
20918
|
+
const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(modal?.buttons, this.provider);
|
|
20919
|
+
const signature = [
|
|
20920
|
+
typeof modal?.message === "string" ? modal.message.trim() : "",
|
|
20921
|
+
Array.isArray(modal?.buttons) ? modal.buttons.join("|") : "",
|
|
20922
|
+
buttonIndex
|
|
20923
|
+
].join("::");
|
|
20924
|
+
if (!this.autoApproveBusy || signature !== this.lastAutoApprovalSignature) {
|
|
20717
20925
|
this.autoApproveBusy = true;
|
|
20926
|
+
this.lastAutoApprovalSignature = signature;
|
|
20718
20927
|
if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
|
|
20719
20928
|
this.autoApproveBusyTimer = setTimeout(() => {
|
|
20720
20929
|
this.autoApproveBusy = false;
|
|
20721
20930
|
this.autoApproveBusyTimer = null;
|
|
20931
|
+
this.lastAutoApprovalSignature = "";
|
|
20722
20932
|
}, 2e3);
|
|
20723
|
-
const modal = adapterStatus.activeModal;
|
|
20724
|
-
const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(modal?.buttons, this.provider);
|
|
20725
20933
|
this.recordAutoApproval(modal?.message, buttonLabel, now);
|
|
20726
20934
|
setTimeout(() => {
|
|
20727
20935
|
this.adapter.resolveModal(buttonIndex);
|
|
@@ -20863,7 +21071,26 @@ var CliProviderInstance = class {
|
|
|
20863
21071
|
});
|
|
20864
21072
|
const agentKey = `${this.type}:cli`;
|
|
20865
21073
|
const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint);
|
|
21074
|
+
const monitorParsedStatus = parsedStatus;
|
|
20866
21075
|
for (const me of monitorEvents) {
|
|
21076
|
+
if (me.type === "monitor:long_generating" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
21077
|
+
this.pushEvent({
|
|
21078
|
+
event: "agent:generating_completed",
|
|
21079
|
+
chatTitle,
|
|
21080
|
+
duration: this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : void 0,
|
|
21081
|
+
timestamp: me.timestamp,
|
|
21082
|
+
finalSummary: extractFinalSummaryFromMessages(monitorParsedStatus?.messages),
|
|
21083
|
+
completionDiagnostic: {
|
|
21084
|
+
providerType: this.type,
|
|
21085
|
+
sessionId: this.instanceId,
|
|
21086
|
+
providerSessionId: this.providerSessionId || null,
|
|
21087
|
+
reconciliationReason: "long_generating_monitor_final_summary",
|
|
21088
|
+
finalAssistantPresent: true
|
|
21089
|
+
}
|
|
21090
|
+
});
|
|
21091
|
+
this.generatingStartedAt = 0;
|
|
21092
|
+
continue;
|
|
21093
|
+
}
|
|
20867
21094
|
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
20868
21095
|
}
|
|
20869
21096
|
}
|
|
@@ -23470,11 +23697,19 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
23470
23697
|
}
|
|
23471
23698
|
const message = input.textFallback;
|
|
23472
23699
|
if (!message) throw new Error("message required for send_chat");
|
|
23473
|
-
|
|
23700
|
+
const forceSend = args?.force === true || args?.forceSend === true;
|
|
23701
|
+
if (forceSend && typeof adapter.forceSendMessage === "function") {
|
|
23702
|
+
await adapter.forceSendMessage(message);
|
|
23703
|
+
} else if (forceSend) {
|
|
23704
|
+
await adapter.sendMessage(message, { force: true });
|
|
23705
|
+
} else {
|
|
23706
|
+
await adapter.sendMessage(message);
|
|
23707
|
+
}
|
|
23474
23708
|
return {
|
|
23475
23709
|
success: true,
|
|
23476
23710
|
status: BUSY_AGENT_STATUSES.has(currentStatus) ? currentStatus : "generating",
|
|
23477
|
-
...BUSY_AGENT_STATUSES.has(currentStatus) ? { queued: true, queuedReason: "agent_runtime_busy" } : {}
|
|
23711
|
+
...BUSY_AGENT_STATUSES.has(currentStatus) ? { queued: true, queuedReason: "agent_runtime_busy" } : {},
|
|
23712
|
+
...forceSend ? { forceSent: true, queued: false } : {}
|
|
23478
23713
|
};
|
|
23479
23714
|
} else if (action === "clear_history") {
|
|
23480
23715
|
if (typeof adapter.clearHistory === "function") adapter.clearHistory();
|