@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/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 getPendingMeshCoordinatorEvents(event.meshId).some(
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 getPendingMeshCoordinatorEvents(event.meshId).some((pending) => buildPendingEventFingerprint(pending) === fingerprint);
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 raw = readFileSync7(path28, "utf-8");
2693
+ const parsed = readPendingMeshCoordinatorEventsFromDisk(meshId);
2615
2694
  try {
2616
2695
  unlinkSync2(path28);
2617
2696
  } catch {
2618
2697
  }
2619
- return raw.split("\n").filter(Boolean).flatMap((line) => {
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
- const path28 = getPendingEventsPath(meshId);
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} has been generating for a long time${metadata}. Use mesh_read_chat once for a status check, but do not poll repeatedly.`;
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
- await adapter.sendMessage(text);
17856
- return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
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 && !this.autoApproveBusy) {
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
- await adapter.sendMessage(message);
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();