@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
|
@@ -34,7 +34,10 @@ export interface CliAdapter {
|
|
|
34
34
|
workingDir: string;
|
|
35
35
|
_acpInstance?: AcpAdapterHandle;
|
|
36
36
|
spawn(): Promise<void>;
|
|
37
|
-
sendMessage(text: string
|
|
37
|
+
sendMessage(text: string, options?: {
|
|
38
|
+
force?: boolean;
|
|
39
|
+
}): Promise<void>;
|
|
40
|
+
forceSendMessage?(text: string): Promise<void>;
|
|
38
41
|
getStatus(): CliAdapterStatus;
|
|
39
42
|
getScriptParsedStatus?(): unknown;
|
|
40
43
|
getDebugSnapshot?(): unknown;
|
|
@@ -214,7 +214,10 @@ export declare class ProviderCliAdapter implements CliAdapter {
|
|
|
214
214
|
private submitSendKey;
|
|
215
215
|
private submitImmediatePrompt;
|
|
216
216
|
private waitForEchoAndSubmit;
|
|
217
|
-
sendMessage(text: string
|
|
217
|
+
sendMessage(text: string, options?: {
|
|
218
|
+
force?: boolean;
|
|
219
|
+
}): Promise<void>;
|
|
220
|
+
forceSendMessage(text: string): Promise<void>;
|
|
218
221
|
private enqueuePendingOutboundMessage;
|
|
219
222
|
private shouldQueuePendingOutboundMessage;
|
|
220
223
|
private schedulePendingOutboundFlush;
|
package/dist/index.js
CHANGED
|
@@ -2563,7 +2563,7 @@ function hasPendingRefineTerminalEventDuplicate(event) {
|
|
|
2563
2563
|
if (!REFINE_TERMINAL_EVENTS.has(event.event)) return false;
|
|
2564
2564
|
const jobId = readRefineJobId(event);
|
|
2565
2565
|
if (!jobId) return false;
|
|
2566
|
-
return
|
|
2566
|
+
return readPendingMeshCoordinatorEventsFromDisk(event.meshId).some(
|
|
2567
2567
|
(pending) => pending.event === event.event && readRefineJobId(pending) === jobId
|
|
2568
2568
|
);
|
|
2569
2569
|
}
|
|
@@ -2588,12 +2588,91 @@ function buildPendingEventFingerprint(event) {
|
|
|
2588
2588
|
function hasPendingCoordinatorEventDuplicate(event) {
|
|
2589
2589
|
const fingerprint = buildPendingEventFingerprint(event);
|
|
2590
2590
|
if (!fingerprint.trim()) return false;
|
|
2591
|
-
return
|
|
2591
|
+
return readPendingMeshCoordinatorEventsFromDisk(event.meshId).some((pending) => buildPendingEventFingerprint(pending) === fingerprint);
|
|
2592
2592
|
}
|
|
2593
2593
|
function getPendingEventsPath(meshId) {
|
|
2594
2594
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2595
2595
|
return (0, import_path7.join)(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
2596
2596
|
}
|
|
2597
|
+
function readPendingMeshCoordinatorEventsFromDisk(meshId) {
|
|
2598
|
+
if (!meshId) return [];
|
|
2599
|
+
const path28 = getPendingEventsPath(meshId);
|
|
2600
|
+
if (!(0, import_fs8.existsSync)(path28)) return [];
|
|
2601
|
+
try {
|
|
2602
|
+
const raw = (0, import_fs8.readFileSync)(path28, "utf-8");
|
|
2603
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
2604
|
+
try {
|
|
2605
|
+
return [JSON.parse(line)];
|
|
2606
|
+
} catch {
|
|
2607
|
+
return [];
|
|
2608
|
+
}
|
|
2609
|
+
});
|
|
2610
|
+
} catch {
|
|
2611
|
+
return [];
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
function refineTerminalEventFromLedger(meshId, pending) {
|
|
2615
|
+
const acceptedJobIds = new Set(
|
|
2616
|
+
pending.filter((event) => event.event === "refine:accepted").map((event) => readRefineJobId(event)).filter(Boolean)
|
|
2617
|
+
);
|
|
2618
|
+
if (acceptedJobIds.size === 0) return [];
|
|
2619
|
+
const existingTerminalJobIds = new Set(
|
|
2620
|
+
pending.filter((event) => REFINE_TERMINAL_EVENTS.has(event.event)).map((event) => `${event.event}:${readRefineJobId(event)}`).filter((value) => !value.endsWith(":"))
|
|
2621
|
+
);
|
|
2622
|
+
const backfilled = [];
|
|
2623
|
+
const entries = readLedgerEntries(meshId);
|
|
2624
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
2625
|
+
const entry = entries[i];
|
|
2626
|
+
if (entry.kind !== "task_completed" && entry.kind !== "task_failed") continue;
|
|
2627
|
+
const payload = readRecord2(entry.payload);
|
|
2628
|
+
if (payload?.source !== "refine_mesh_node_async_job") continue;
|
|
2629
|
+
const refineJob = readRecord2(payload.refineJob);
|
|
2630
|
+
const jobId = readNonEmptyString2(refineJob?.jobId);
|
|
2631
|
+
if (!jobId || !acceptedJobIds.has(jobId)) continue;
|
|
2632
|
+
const eventName = entry.kind === "task_completed" ? "refine:completed" : "refine:failed";
|
|
2633
|
+
if (existingTerminalJobIds.has(`${eventName}:${jobId}`)) continue;
|
|
2634
|
+
existingTerminalJobIds.add(`${eventName}:${jobId}`);
|
|
2635
|
+
const result = readRecord2(payload.result);
|
|
2636
|
+
const metadataEvent = {
|
|
2637
|
+
source: "refine_mesh_node_async_job",
|
|
2638
|
+
jobId,
|
|
2639
|
+
interactionId: readNonEmptyString2(refineJob?.interactionId),
|
|
2640
|
+
meshId,
|
|
2641
|
+
nodeId: readNonEmptyString2(refineJob?.nodeId) || entry.nodeId,
|
|
2642
|
+
targetDaemonId: readNonEmptyString2(refineJob?.targetDaemonId),
|
|
2643
|
+
workspace: readNonEmptyString2(refineJob?.workspace),
|
|
2644
|
+
status: eventName === "refine:completed" ? "completed" : "failed",
|
|
2645
|
+
startedAt: readNonEmptyString2(refineJob?.startedAt),
|
|
2646
|
+
completedAt: readNonEmptyString2(refineJob?.completedAt) || entry.timestamp,
|
|
2647
|
+
retryOfJobId: readNonEmptyString2(refineJob?.retryOfJobId) || readNonEmptyString2(payload.retryOfJobId),
|
|
2648
|
+
...result ? { result } : {}
|
|
2649
|
+
};
|
|
2650
|
+
backfilled.push({
|
|
2651
|
+
event: eventName,
|
|
2652
|
+
meshId,
|
|
2653
|
+
nodeLabel: readNonEmptyString2(refineJob?.nodeId) || entry.nodeId || "refine job",
|
|
2654
|
+
nodeId: readNonEmptyString2(refineJob?.nodeId) || entry.nodeId,
|
|
2655
|
+
workspace: readNonEmptyString2(refineJob?.workspace),
|
|
2656
|
+
metadataEvent,
|
|
2657
|
+
coordinatorMessage: buildMeshSystemMessage({
|
|
2658
|
+
event: eventName,
|
|
2659
|
+
nodeLabel: readNonEmptyString2(refineJob?.nodeId) || entry.nodeId || "refine job",
|
|
2660
|
+
metadataEvent
|
|
2661
|
+
}),
|
|
2662
|
+
queuedAt: Date.now()
|
|
2663
|
+
});
|
|
2664
|
+
}
|
|
2665
|
+
return backfilled.reverse();
|
|
2666
|
+
}
|
|
2667
|
+
function reconcilePendingMeshCoordinatorEvents(meshId, events) {
|
|
2668
|
+
const backfilled = refineTerminalEventFromLedger(meshId, events);
|
|
2669
|
+
if (backfilled.length === 0) return events;
|
|
2670
|
+
const terminalJobIds = new Set(backfilled.map((event) => readRefineJobId(event)).filter(Boolean));
|
|
2671
|
+
return [
|
|
2672
|
+
...events.filter((event) => !(event.event === "refine:accepted" && terminalJobIds.has(readRefineJobId(event)))),
|
|
2673
|
+
...backfilled
|
|
2674
|
+
];
|
|
2675
|
+
}
|
|
2597
2676
|
function queuePendingMeshCoordinatorEvent(event) {
|
|
2598
2677
|
try {
|
|
2599
2678
|
if (hasPendingRefineTerminalEventDuplicate(event)) {
|
|
@@ -2616,38 +2695,19 @@ function drainPendingMeshCoordinatorEvents(meshId) {
|
|
|
2616
2695
|
const path28 = getPendingEventsPath(meshId);
|
|
2617
2696
|
if (!(0, import_fs8.existsSync)(path28)) return [];
|
|
2618
2697
|
try {
|
|
2619
|
-
const
|
|
2698
|
+
const parsed = readPendingMeshCoordinatorEventsFromDisk(meshId);
|
|
2620
2699
|
try {
|
|
2621
2700
|
(0, import_fs8.unlinkSync)(path28);
|
|
2622
2701
|
} catch {
|
|
2623
2702
|
}
|
|
2624
|
-
return
|
|
2625
|
-
try {
|
|
2626
|
-
return [JSON.parse(line)];
|
|
2627
|
-
} catch {
|
|
2628
|
-
return [];
|
|
2629
|
-
}
|
|
2630
|
-
});
|
|
2703
|
+
return reconcilePendingMeshCoordinatorEvents(meshId, parsed);
|
|
2631
2704
|
} catch {
|
|
2632
2705
|
return [];
|
|
2633
2706
|
}
|
|
2634
2707
|
}
|
|
2635
2708
|
function getPendingMeshCoordinatorEvents(meshId) {
|
|
2636
2709
|
if (!meshId) return [];
|
|
2637
|
-
|
|
2638
|
-
if (!(0, import_fs8.existsSync)(path28)) return [];
|
|
2639
|
-
try {
|
|
2640
|
-
const raw = (0, import_fs8.readFileSync)(path28, "utf-8");
|
|
2641
|
-
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
2642
|
-
try {
|
|
2643
|
-
return [JSON.parse(line)];
|
|
2644
|
-
} catch {
|
|
2645
|
-
return [];
|
|
2646
|
-
}
|
|
2647
|
-
});
|
|
2648
|
-
} catch {
|
|
2649
|
-
return [];
|
|
2650
|
-
}
|
|
2710
|
+
return reconcilePendingMeshCoordinatorEvents(meshId, readPendingMeshCoordinatorEventsFromDisk(meshId));
|
|
2651
2711
|
}
|
|
2652
2712
|
function clearPendingMeshCoordinatorEvents(meshId) {
|
|
2653
2713
|
if (!meshId) return;
|
|
@@ -2752,6 +2812,62 @@ function isDuplicateRefineTerminalEvent(meshId, eventName, metadataEvent) {
|
|
|
2752
2812
|
recentCompletionFingerprints.set(fingerprint, now);
|
|
2753
2813
|
return false;
|
|
2754
2814
|
}
|
|
2815
|
+
function findRecentTerminalLedgerEvidence(args) {
|
|
2816
|
+
if (!args.sessionId && !args.nodeId) return null;
|
|
2817
|
+
const entries = readLedgerEntries(args.meshId);
|
|
2818
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
2819
|
+
const entry = entries[i];
|
|
2820
|
+
if (entry.kind !== "task_completed" && entry.kind !== "task_failed" && entry.kind !== "task_stalled") continue;
|
|
2821
|
+
if (args.sessionId && entry.sessionId === args.sessionId) {
|
|
2822
|
+
return { kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
2823
|
+
}
|
|
2824
|
+
if (!args.sessionId && args.nodeId && entry.nodeId === args.nodeId) {
|
|
2825
|
+
return { kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
return null;
|
|
2829
|
+
}
|
|
2830
|
+
function buildLongGeneratingCompletionReconciliation(args) {
|
|
2831
|
+
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
2832
|
+
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
2833
|
+
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
2834
|
+
const providerSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
|
|
2835
|
+
const workerResult = readWorkerResultMetadata(args.metadataEvent);
|
|
2836
|
+
const completionDiagnostic = readRecord2(args.metadataEvent.completionDiagnostic);
|
|
2837
|
+
const finalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
2838
|
+
const status = readNonEmptyString2(args.metadataEvent.status).toLowerCase();
|
|
2839
|
+
const explicitCompletionEvidence = Boolean(
|
|
2840
|
+
finalSummary || workerResult || completionDiagnostic?.finalAssistantPresent === true || status === "idle" || status === "ready" || status === "completed"
|
|
2841
|
+
);
|
|
2842
|
+
if (explicitCompletionEvidence) {
|
|
2843
|
+
return {
|
|
2844
|
+
...args.metadataEvent,
|
|
2845
|
+
targetSessionId: sessionId,
|
|
2846
|
+
providerType,
|
|
2847
|
+
providerSessionId,
|
|
2848
|
+
finalSummary,
|
|
2849
|
+
source: "long_generating_reconciliation",
|
|
2850
|
+
reconciledFromEvent: "monitor:long_generating",
|
|
2851
|
+
timestamp: args.metadataEvent.timestamp ?? Date.now(),
|
|
2852
|
+
completionDiagnostic: {
|
|
2853
|
+
...completionDiagnostic || {},
|
|
2854
|
+
reconciliationReason: "provider_completion_evidence"
|
|
2855
|
+
}
|
|
2856
|
+
};
|
|
2857
|
+
}
|
|
2858
|
+
const terminal = findRecentTerminalLedgerEvidence({
|
|
2859
|
+
meshId: args.meshId,
|
|
2860
|
+
sessionId: sessionId || void 0,
|
|
2861
|
+
nodeId: nodeId || void 0
|
|
2862
|
+
});
|
|
2863
|
+
if (!terminal) return null;
|
|
2864
|
+
return {
|
|
2865
|
+
...args.metadataEvent,
|
|
2866
|
+
source: "long_generating_terminal_ledger_suppression",
|
|
2867
|
+
terminalLedgerKind: terminal.kind,
|
|
2868
|
+
terminalLedgerAt: terminal.timestamp
|
|
2869
|
+
};
|
|
2870
|
+
}
|
|
2755
2871
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
2756
2872
|
const task = claimNextTask(meshId, nodeId, sessionId);
|
|
2757
2873
|
if (!task) {
|
|
@@ -2845,6 +2961,9 @@ function activeAssignedCount(meshId) {
|
|
|
2845
2961
|
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
2846
2962
|
return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedNodeId === nodeId);
|
|
2847
2963
|
}
|
|
2964
|
+
function sessionHasActiveAssignment(meshId, sessionId) {
|
|
2965
|
+
return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedSessionId === sessionId);
|
|
2966
|
+
}
|
|
2848
2967
|
function liveSessionCountForNode(components, meshId, nodeId) {
|
|
2849
2968
|
return components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
2850
2969
|
const state = inst.getState();
|
|
@@ -3055,6 +3174,9 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
3055
3174
|
function buildMeshSystemMessage(args) {
|
|
3056
3175
|
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
3057
3176
|
if (args.event === "agent:generating_completed") {
|
|
3177
|
+
if (args.metadataEvent.source === "long_generating_reconciliation") {
|
|
3178
|
+
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.`;
|
|
3179
|
+
}
|
|
3058
3180
|
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.`;
|
|
3059
3181
|
}
|
|
3060
3182
|
if (args.event === "agent:waiting_approval") {
|
|
@@ -3092,7 +3214,7 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
3092
3214
|
return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
|
|
3093
3215
|
}
|
|
3094
3216
|
if (args.event === "monitor:long_generating") {
|
|
3095
|
-
return `[System] ${args.nodeLabel}
|
|
3217
|
+
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.`;
|
|
3096
3218
|
}
|
|
3097
3219
|
if (args.event === "refine:accepted") {
|
|
3098
3220
|
const jobId = readRefineJobId({ metadataEvent: args.metadataEvent });
|
|
@@ -3170,12 +3292,54 @@ function injectMeshSystemMessage(components, args) {
|
|
|
3170
3292
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
3171
3293
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
3172
3294
|
}
|
|
3295
|
+
if (args.event === "monitor:long_generating") {
|
|
3296
|
+
const reconciledCompletion = buildLongGeneratingCompletionReconciliation({
|
|
3297
|
+
meshId: args.meshId,
|
|
3298
|
+
nodeId: args.nodeId,
|
|
3299
|
+
nodeLabel: args.nodeLabel,
|
|
3300
|
+
metadataEvent: args.metadataEvent,
|
|
3301
|
+
sourceInstanceId: args.sourceInstanceId
|
|
3302
|
+
});
|
|
3303
|
+
if (reconciledCompletion?.source === "long_generating_reconciliation") {
|
|
3304
|
+
LOG.info("MeshEvents", `Reconciled long-generating monitor to completion for session ${eventSessionId || "(unknown session)"}`);
|
|
3305
|
+
return injectMeshSystemMessage(components, {
|
|
3306
|
+
...args,
|
|
3307
|
+
event: "agent:generating_completed",
|
|
3308
|
+
metadataEvent: reconciledCompletion
|
|
3309
|
+
});
|
|
3310
|
+
}
|
|
3311
|
+
if (reconciledCompletion?.source === "long_generating_terminal_ledger_suppression") {
|
|
3312
|
+
LOG.info("MeshEvents", `Suppressed long-generating monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
3313
|
+
return {
|
|
3314
|
+
success: true,
|
|
3315
|
+
forwarded: 0,
|
|
3316
|
+
suppressed: true,
|
|
3317
|
+
terminalLedgerEvidence: true,
|
|
3318
|
+
terminalLedgerKind: reconciledCompletion.terminalLedgerKind
|
|
3319
|
+
};
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3173
3322
|
if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
|
|
3174
3323
|
LOG.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
|
|
3175
3324
|
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
3176
3325
|
}
|
|
3177
3326
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
3178
3327
|
if (args.event === "agent:generating_completed" && eventSessionId) {
|
|
3328
|
+
const terminal = findRecentTerminalLedgerEvidence({
|
|
3329
|
+
meshId: args.meshId,
|
|
3330
|
+
sessionId: eventSessionId,
|
|
3331
|
+
nodeId: eventNodeId || void 0
|
|
3332
|
+
});
|
|
3333
|
+
if (terminal?.kind === "task_completed" && !sessionHasActiveAssignment(args.meshId, eventSessionId)) {
|
|
3334
|
+
const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
|
|
3335
|
+
const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
|
|
3336
|
+
const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
|
|
3337
|
+
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
3338
|
+
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "long_generating_reconciliation") {
|
|
3339
|
+
LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
3340
|
+
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3179
3343
|
const duplicateCompletion = isDuplicateMeshCompletionEvent({
|
|
3180
3344
|
meshId: args.meshId,
|
|
3181
3345
|
event: args.event,
|
|
@@ -3452,6 +3616,10 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
3452
3616
|
completedAt: readNonEmptyString2(payload.completedAt),
|
|
3453
3617
|
retryOfJobId: readNonEmptyString2(payload.retryOfJobId),
|
|
3454
3618
|
...payload.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? { result: payload.result } : {},
|
|
3619
|
+
...payload.completionDiagnostic && typeof payload.completionDiagnostic === "object" && !Array.isArray(payload.completionDiagnostic) ? { completionDiagnostic: payload.completionDiagnostic } : {},
|
|
3620
|
+
...payload.workerResult && typeof payload.workerResult === "object" && !Array.isArray(payload.workerResult) ? { workerResult: payload.workerResult } : {},
|
|
3621
|
+
...payload.meshWorkerResult && typeof payload.meshWorkerResult === "object" && !Array.isArray(payload.meshWorkerResult) ? { meshWorkerResult: payload.meshWorkerResult } : {},
|
|
3622
|
+
...payload.structuredResult && typeof payload.structuredResult === "object" && !Array.isArray(payload.structuredResult) ? { structuredResult: payload.structuredResult } : {},
|
|
3455
3623
|
...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
|
|
3456
3624
|
intentional: payload.intentional === true,
|
|
3457
3625
|
intentionalStop: payload.intentionalStop === true,
|
|
@@ -6351,9 +6519,27 @@ ${lastSnapshot}`;
|
|
|
6351
6519
|
nextScreenChangeAt
|
|
6352
6520
|
), 50);
|
|
6353
6521
|
}
|
|
6354
|
-
async sendMessage(text) {
|
|
6522
|
+
async sendMessage(text, options = {}) {
|
|
6523
|
+
if (options.force === true) {
|
|
6524
|
+
await this.forceSendMessage(text);
|
|
6525
|
+
return;
|
|
6526
|
+
}
|
|
6355
6527
|
await this.sendMessageNow(text, true);
|
|
6356
6528
|
}
|
|
6529
|
+
async forceSendMessage(text) {
|
|
6530
|
+
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
6531
|
+
const content = String(text || "");
|
|
6532
|
+
if (!content.trim()) return;
|
|
6533
|
+
this.recordTrace("force_send_message", {
|
|
6534
|
+
text: summarizeCliTraceText(content, 500),
|
|
6535
|
+
status: this.currentStatus,
|
|
6536
|
+
isWaitingForResponse: this.isWaitingForResponse,
|
|
6537
|
+
queueLength: this.pendingOutboundQueue.length
|
|
6538
|
+
});
|
|
6539
|
+
LOG.info("CLI", `[${this.cliType}] force-sending prompt while status=${this.currentStatus}`);
|
|
6540
|
+
await this.writeToPty(content + this.sendKey);
|
|
6541
|
+
this.onStatusChange?.();
|
|
6542
|
+
}
|
|
6357
6543
|
enqueuePendingOutboundMessage(text, reason) {
|
|
6358
6544
|
const content = String(text || "");
|
|
6359
6545
|
const duplicate = this.pendingOutboundQueue.some((message2) => message2.content === content);
|
|
@@ -18118,8 +18304,18 @@ async function handleSendChat(h, args) {
|
|
|
18118
18304
|
assertTextOnlyInput(provider, input);
|
|
18119
18305
|
if (!text) return { success: false, error: "text required for PTY send" };
|
|
18120
18306
|
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
18121
|
-
|
|
18122
|
-
|
|
18307
|
+
const forceSend = args?.force === true || args?.forceSend === true;
|
|
18308
|
+
if (forceSend && typeof adapter.forceSendMessage === "function") {
|
|
18309
|
+
await adapter.forceSendMessage(text);
|
|
18310
|
+
} else if (forceSend) {
|
|
18311
|
+
await adapter.sendMessage(text, { force: true });
|
|
18312
|
+
} else {
|
|
18313
|
+
await adapter.sendMessage(text);
|
|
18314
|
+
}
|
|
18315
|
+
return {
|
|
18316
|
+
..._logSendSuccess(`${transport}-adapter`, adapter.cliType),
|
|
18317
|
+
...forceSend ? { forceSent: true } : {}
|
|
18318
|
+
};
|
|
18123
18319
|
} catch (e) {
|
|
18124
18320
|
return { success: false, error: `${transport} send failed: ${e.message}` };
|
|
18125
18321
|
}
|
|
@@ -20470,6 +20666,7 @@ var CliProviderInstance = class {
|
|
|
20470
20666
|
lastApprovalEventAt = 0;
|
|
20471
20667
|
autoApproveBusy = false;
|
|
20472
20668
|
autoApproveBusyTimer = null;
|
|
20669
|
+
lastAutoApprovalSignature = "";
|
|
20473
20670
|
controlValues = {};
|
|
20474
20671
|
summaryMetadata = void 0;
|
|
20475
20672
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
@@ -20979,15 +21176,26 @@ var CliProviderInstance = class {
|
|
|
20979
21176
|
}
|
|
20980
21177
|
maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
|
|
20981
21178
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
20982
|
-
if (autoApproveActive
|
|
21179
|
+
if (!autoApproveActive) {
|
|
21180
|
+
this.lastAutoApprovalSignature = "";
|
|
21181
|
+
return autoApproveActive;
|
|
21182
|
+
}
|
|
21183
|
+
const modal = adapterStatus.activeModal;
|
|
21184
|
+
const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(modal?.buttons, this.provider);
|
|
21185
|
+
const signature = [
|
|
21186
|
+
typeof modal?.message === "string" ? modal.message.trim() : "",
|
|
21187
|
+
Array.isArray(modal?.buttons) ? modal.buttons.join("|") : "",
|
|
21188
|
+
buttonIndex
|
|
21189
|
+
].join("::");
|
|
21190
|
+
if (!this.autoApproveBusy || signature !== this.lastAutoApprovalSignature) {
|
|
20983
21191
|
this.autoApproveBusy = true;
|
|
21192
|
+
this.lastAutoApprovalSignature = signature;
|
|
20984
21193
|
if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
|
|
20985
21194
|
this.autoApproveBusyTimer = setTimeout(() => {
|
|
20986
21195
|
this.autoApproveBusy = false;
|
|
20987
21196
|
this.autoApproveBusyTimer = null;
|
|
21197
|
+
this.lastAutoApprovalSignature = "";
|
|
20988
21198
|
}, 2e3);
|
|
20989
|
-
const modal = adapterStatus.activeModal;
|
|
20990
|
-
const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(modal?.buttons, this.provider);
|
|
20991
21199
|
this.recordAutoApproval(modal?.message, buttonLabel, now);
|
|
20992
21200
|
setTimeout(() => {
|
|
20993
21201
|
this.adapter.resolveModal(buttonIndex);
|
|
@@ -21129,7 +21337,26 @@ var CliProviderInstance = class {
|
|
|
21129
21337
|
});
|
|
21130
21338
|
const agentKey = `${this.type}:cli`;
|
|
21131
21339
|
const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint);
|
|
21340
|
+
const monitorParsedStatus = parsedStatus;
|
|
21132
21341
|
for (const me of monitorEvents) {
|
|
21342
|
+
if (me.type === "monitor:long_generating" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
21343
|
+
this.pushEvent({
|
|
21344
|
+
event: "agent:generating_completed",
|
|
21345
|
+
chatTitle,
|
|
21346
|
+
duration: this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : void 0,
|
|
21347
|
+
timestamp: me.timestamp,
|
|
21348
|
+
finalSummary: extractFinalSummaryFromMessages(monitorParsedStatus?.messages),
|
|
21349
|
+
completionDiagnostic: {
|
|
21350
|
+
providerType: this.type,
|
|
21351
|
+
sessionId: this.instanceId,
|
|
21352
|
+
providerSessionId: this.providerSessionId || null,
|
|
21353
|
+
reconciliationReason: "long_generating_monitor_final_summary",
|
|
21354
|
+
finalAssistantPresent: true
|
|
21355
|
+
}
|
|
21356
|
+
});
|
|
21357
|
+
this.generatingStartedAt = 0;
|
|
21358
|
+
continue;
|
|
21359
|
+
}
|
|
21133
21360
|
this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
|
|
21134
21361
|
}
|
|
21135
21362
|
}
|
|
@@ -23731,11 +23958,19 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
23731
23958
|
}
|
|
23732
23959
|
const message = input.textFallback;
|
|
23733
23960
|
if (!message) throw new Error("message required for send_chat");
|
|
23734
|
-
|
|
23961
|
+
const forceSend = args?.force === true || args?.forceSend === true;
|
|
23962
|
+
if (forceSend && typeof adapter.forceSendMessage === "function") {
|
|
23963
|
+
await adapter.forceSendMessage(message);
|
|
23964
|
+
} else if (forceSend) {
|
|
23965
|
+
await adapter.sendMessage(message, { force: true });
|
|
23966
|
+
} else {
|
|
23967
|
+
await adapter.sendMessage(message);
|
|
23968
|
+
}
|
|
23735
23969
|
return {
|
|
23736
23970
|
success: true,
|
|
23737
23971
|
status: BUSY_AGENT_STATUSES.has(currentStatus) ? currentStatus : "generating",
|
|
23738
|
-
...BUSY_AGENT_STATUSES.has(currentStatus) ? { queued: true, queuedReason: "agent_runtime_busy" } : {}
|
|
23972
|
+
...BUSY_AGENT_STATUSES.has(currentStatus) ? { queued: true, queuedReason: "agent_runtime_busy" } : {},
|
|
23973
|
+
...forceSend ? { forceSent: true, queued: false } : {}
|
|
23739
23974
|
};
|
|
23740
23975
|
} else if (action === "clear_history") {
|
|
23741
23976
|
if (typeof adapter.clearHistory === "function") adapter.clearHistory();
|