@symerian/symi 3.1.0 → 3.1.1

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.
Files changed (54) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/bundled/boot-md/handler.js +4 -4
  3. package/dist/bundled/session-memory/handler.js +4 -4
  4. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  5. package/dist/{chrome-O5GtGEaR.js → chrome-CCtr79A5.js} +4 -4
  6. package/dist/{chrome-B7_foWil.js → chrome-CLdjGAF1.js} +4 -4
  7. package/dist/{command-registry-DmjX-MJb.js → command-registry-DtivbkBg.js} +4 -4
  8. package/dist/{completion-cli-CKczmer5.js → completion-cli-DAtKJGz_.js} +1 -1
  9. package/dist/{completion-cli-DezSeZQA.js → completion-cli-M9mpw_DS.js} +2 -2
  10. package/dist/control-ui/js/app.js +34 -2
  11. package/dist/{deliver-BMg6XjUA.js → deliver-D0zCpBS2.js} +4 -4
  12. package/dist/{deliver-Cxzii_el.js → deliver-aqjVfua8.js} +4 -4
  13. package/dist/{doctor-completion-AGw1egU_.js → doctor-completion-BlxU7_DJ.js} +1 -1
  14. package/dist/{doctor-completion-BCVASe0n.js → doctor-completion-DLx2ecZ2.js} +1 -1
  15. package/dist/entry.js +1 -1
  16. package/dist/extensionAPI.js +4 -4
  17. package/dist/{gateway-cli-CvFiUm5D.js → gateway-cli-BDVuQ5k9.js} +6 -354
  18. package/dist/{gateway-cli-BZXfKM1n.js → gateway-cli-CjY_Ct2M.js} +6 -354
  19. package/dist/{glass-ui-ws-CHyGj7GA.js → glass-ui-ws-Bs0VbFCC.js} +1 -1
  20. package/dist/{glass-ui-ws-BSTHY5PU.js → glass-ui-ws-CLyPSA_9.js} +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/llm-slug-generator.js +4 -4
  23. package/dist/{manager-BWi2hK4Y.js → manager-3gF-gaOU.js} +1 -1
  24. package/dist/{manager-BoTf2TBM.js → manager-Do_LVG9R.js} +1 -1
  25. package/dist/{onboard-BzRDv60Y.js → onboard-lFeJdiGp.js} +1 -1
  26. package/dist/{onboard-CHrTg-R0.js → onboard-zwQ2t4TE.js} +1 -1
  27. package/dist/{onboarding-ClbxBHpB.js → onboarding-C0kL3Y5v.js} +1 -1
  28. package/dist/{onboarding-BGwkx8NB.js → onboarding-CaHVfCVn.js} +1 -1
  29. package/dist/{onboarding.finalize-D6zND3C7.js → onboarding.finalize-DwXxdw74.js} +3 -3
  30. package/dist/{onboarding.finalize-BnIBZwze.js → onboarding.finalize-vT6fRWsB.js} +4 -4
  31. package/dist/{pi-embedded-L-sMlPsa.js → pi-embedded-JU-n_Ppj.js} +10 -10
  32. package/dist/plugin-sdk/gateway/server-chat.d.ts +47 -0
  33. package/dist/{program-B8S2KFzC.js → program-C1bTgU2q.js} +2 -2
  34. package/dist/{program-context-DCb3cVEC.js → program-context-BHvgRRy_.js} +6 -6
  35. package/dist/{prompt-select-styled-BJ3NsTmX.js → prompt-select-styled--PI8fuuB.js} +1 -1
  36. package/dist/{prompt-select-styled-ZdXAuRQQ.js → prompt-select-styled-DawD9uin.js} +1 -1
  37. package/dist/{pw-ai-B9riepO_.js → pw-ai-BlFwd1fC.js} +1 -1
  38. package/dist/{pw-ai-CYE0188Y.js → pw-ai-Cq1WlDax.js} +1 -1
  39. package/dist/{register.maintenance-CX4sIokB.js → register.maintenance-D0NfR0wv.js} +5 -5
  40. package/dist/{register.maintenance-BBxWlFhs.js → register.maintenance-fFzETZM-.js} +4 -4
  41. package/dist/{register.onboard-UzFm__iV.js → register.onboard-C0eFmAVL.js} +2 -2
  42. package/dist/{register.onboard-Be8PMN1Z.js → register.onboard-C7aJLoQc.js} +2 -2
  43. package/dist/{register.setup-w0_6rARS.js → register.setup-CRhnePOD.js} +2 -2
  44. package/dist/{register.setup-Dq7WlLOL.js → register.setup-XpvVOl8-.js} +2 -2
  45. package/dist/{register.subclis-Cb1ErrVQ.js → register.subclis-BFq9K0q9.js} +3 -3
  46. package/dist/{run-main-DmC4wWlp.js → run-main-JPtR4nYb.js} +3 -3
  47. package/dist/{server-methods-C97G9dYe.js → server-methods-Dj3PCErz.js} +360 -4
  48. package/dist/{server-methods-DFt60s1H.js → server-methods-RegE5bVx.js} +360 -4
  49. package/dist/{synthesis-DA7kfAUJ.js → synthesis-CNYpM3bL.js} +4 -4
  50. package/dist/{synthesis-CPZoVKlB.js → synthesis-CP97tsyU.js} +4 -4
  51. package/dist/{unified-runner-BdN9pHa8.js → unified-runner-Bjd_KpAr.js} +10 -10
  52. package/dist/{update-cli-Bg3c9ORr.js → update-cli-DPsa1UFx.js} +5 -5
  53. package/dist/{update-cli-DZtbV25O.js → update-cli-bgziGI6r.js} +4 -4
  54. package/package.json +1 -1
@@ -12,14 +12,15 @@ import { f as GATEWAY_CLIENT_CAPS, g as hasGatewayClientCap, i as isGatewayMessa
12
12
  import { c as writeJsonAtomic, o as createAsyncLock, s as readJsonFile } from "./pairing-token-DZAnUH5B.js";
13
13
  import { s as pickPrimaryLanIPv4 } from "./net-DZ5Ayk-W.js";
14
14
  import { i as normalizeInputProvenance } from "./input-provenance-D0lNkCf6.js";
15
- import { $n as setTtsEnabled, A as waitForEmbeddedPiRunEnd, Bt as scheduleGatewaySigusr1Restart, C as buildGlassUiProfile, Cn as prepareAgentRun, E as runUnifiedTurn, Fn as isAbortTrigger, G as ensureOutboundSessionEntry, Gn as getTtsProvider, In as stopSubagentsForRequester, Jn as resolveTtsApiKey, K as resolveOutboundSessionRoute, Kn as isTtsEnabled, Mn as normalizeGroupActivation, Mt as persistBrowserProxyFiles, O as abortEmbeddedPiRun, Pn as formatZonedTimestamp, Qn as resolveTtsProviderOrder, R as buildAgentTurnParams, Sn as resolveAgentTimeoutMs, Tn as isSystemEventContextChanged, Ut as loadProviderUsageSummary, V as listTasksInWorkdir, Vn as resolveUserTimezone, Xn as resolveTtsConfig, Y as resolveOutboundTarget, Yn as resolveTtsAutoMode, Z as normalizePollInput, Zn as resolveTtsPrefsPath, a as listSubagentRunsForRequester, br as registerAgentRunContext, c as clearSessionQueues, cn as applyModelOverrideToSessionEntry, dt as writeRestartSentinel, er as setTtsProvider, i as listDescendantRunsForRequester, jn as BARE_SESSION_RESET_PROMPT, jt as applyBrowserProxyPaths, ln as applyVerboseOverride, m as loadSymiPlugins, mt as normalizeCronJobPatch, nn as normalizeSendPolicy, nr as OPENAI_TTS_MODELS, ot as formatDoctorNonInteractiveHint, pt as normalizeCronJobCreate, qn as isTtsProviderConfigured, rn as resolveSendPolicy, rr as OPENAI_TTS_VOICES, tr as textToSpeech, un as parseVerboseOverride, wn as enqueueSystemEvent, x as createReplyDispatcher, y as getChannelActivity, yr as onAgentEvent, z as prepareReplyTurn } from "./subagent-registry-DNcSxvl3.js";
15
+ import { $n as setTtsEnabled, A as waitForEmbeddedPiRunEnd, Bt as scheduleGatewaySigusr1Restart, C as buildGlassUiProfile, Cn as prepareAgentRun, E as runUnifiedTurn, F as classifyOutboundMessage, Fn as isAbortTrigger, G as ensureOutboundSessionEntry, Gn as getTtsProvider, In as stopSubagentsForRequester, Jn as resolveTtsApiKey, K as resolveOutboundSessionRoute, Kn as isTtsEnabled, Mn as normalizeGroupActivation, Mt as persistBrowserProxyFiles, O as abortEmbeddedPiRun, Pn as formatZonedTimestamp, Qn as resolveTtsProviderOrder, R as buildAgentTurnParams, Sn as resolveAgentTimeoutMs, Tn as isSystemEventContextChanged, Ut as loadProviderUsageSummary, V as listTasksInWorkdir, Vn as resolveUserTimezone, Xn as resolveTtsConfig, Y as resolveOutboundTarget, Yn as resolveTtsAutoMode, Z as normalizePollInput, Zn as resolveTtsPrefsPath, a as listSubagentRunsForRequester, br as registerAgentRunContext, c as clearSessionQueues, cn as applyModelOverrideToSessionEntry, dr as DEFAULT_HEARTBEAT_ACK_MAX_CHARS, dt as writeRestartSentinel, er as setTtsProvider, i as listDescendantRunsForRequester, jn as BARE_SESSION_RESET_PROMPT, jt as applyBrowserProxyPaths, ln as applyVerboseOverride, m as loadSymiPlugins, mt as normalizeCronJobPatch, n as countActiveRunsForSession, nn as normalizeSendPolicy, nr as OPENAI_TTS_MODELS, ot as formatDoctorNonInteractiveHint, pt as normalizeCronJobCreate, qn as isTtsProviderConfigured, rn as resolveSendPolicy, rr as OPENAI_TTS_VOICES, tr as textToSpeech, un as parseVerboseOverride, vr as getAgentRunContext, wn as enqueueSystemEvent, x as createReplyDispatcher, y as getChannelActivity, yr as onAgentEvent, z as prepareReplyTurn } from "./subagent-registry-DNcSxvl3.js";
16
16
  import { F as resolveMainSessionKey, I as resolveMainSessionKeyFromConfig, J as normalizeSessionDeliveryFields, N as resolveAgentMainSessionKey, P as resolveExplicitAgentSessionKey, R as snapshotSessionOrigin, S as stripEnvelopeFromMessages, _ as capArrayByJsonBytes, d as updateSessionStore, g as archiveSessionTranscripts, h as archiveFileOnDisk, o as loadSessionStore, t as extractDeliveryInfo, v as readSessionMessages, x as resolveSessionTranscriptCandidates, y as readSessionPreviewItemsFromTranscript } from "./sessions-CrQE7gq3.js";
17
+ import { i as isSilentReplyText, n as SILENT_REPLY_TOKEN } from "./tokens-DN4W-XdV.js";
17
18
  import { n as listChannelPlugins, r as normalizeChannelId, t as getChannelPlugin } from "./plugins-CYQsm6Gy.js";
18
19
  import { n as createBrowserRouteDispatcher } from "./with-timeout-DNvX8V3I.js";
19
20
  import { h as getGlobalHookRunner, o as normalizeReplyPayloadsForDelivery, t as deliverOutboundPayloads } from "./deliver-SxI9drJl.js";
20
21
  import { t as movePathToTrash } from "./trash-BEXyYJdG.js";
21
22
  import { c as resolveStorePath, n as resolveSessionFilePath, r as resolveSessionFilePathOptions, s as resolveSessionTranscriptsDirForAgent } from "./paths-BDcioH8W.js";
22
- import { a as normalizeElevatedLevel, c as normalizeUsageDisplay, d as supportsXHighThinking, n as formatXHighModelHint, o as normalizeReasoningLevel, s as normalizeThinkLevel, t as formatThinkingLevels } from "./thinking-C72VJ9y9.js";
23
+ import { a as normalizeElevatedLevel, c as normalizeUsageDisplay, d as supportsXHighThinking, l as normalizeVerboseLevel, n as formatXHighModelHint, o as normalizeReasoningLevel, s as normalizeThinkLevel, t as formatThinkingLevels } from "./thinking-C72VJ9y9.js";
23
24
  import { a as resolveAgentIdentity, t as createReplyPrefixOptions } from "./reply-prefix-B9wo4eUI.js";
24
25
  import { r as getMemorySearchManager } from "./memory-cli-B7Ls3Iv1.js";
25
26
  import { _ as requestNodePairing, g as renamePairedNode, h as rejectNodePairing, m as listNodePairing, o as getRemoteSkillEligibility, p as approveNodePairing, y as verifyNodeToken } from "./skill-commands-BFRS0Miy.js";
@@ -36,7 +37,7 @@ import { t as buildChannelAccountSnapshot } from "./status-CBkcR9vW.js";
36
37
  import { w as resolveAssistantAvatarUrl } from "./onboard-helpers-CilvN36L.js";
37
38
  import { o as isNodeCommandAllowed, s as resolveNodeCommandAllowlist } from "./audit-CHQE7ltJ.js";
38
39
  import { r as getStatusSummary } from "./status-er3ceIYD.js";
39
- import { c as setHeartbeatsEnabled, d as getLastHeartbeatEvent, p as abortHeartbeatRunForSession } from "./health-vDQ4nRJB.js";
40
+ import { c as setHeartbeatsEnabled, d as getLastHeartbeatEvent, p as abortHeartbeatRunForSession, u as resolveHeartbeatVisibility } from "./health-vDQ4nRJB.js";
40
41
  import { r as createOutboundSendDeps } from "./outbound-send-deps-KBVliaIJ.js";
41
42
  import { m as normalizeUpdateChannel } from "./update-check-CZiE16y_.js";
42
43
  import { a as sendApnsAlert, c as parseMessageWithAttachments, i as resolveApnsAuthConfigFromEnv, l as formatForLog, n as normalizeApnsEnvironment, o as sendApnsBackgroundWake, s as normalizeRpcAttachmentsToChatAttachments, t as loadApnsRegistration } from "./push-apns-CZG-Sec1.js";
@@ -403,6 +404,355 @@ function startGatewayConfigReloader(opts) {
403
404
  } };
404
405
  }
405
406
 
407
+ //#endregion
408
+ //#region src/gateway/server-chat.ts
409
+ function resolveHeartbeatAckMaxChars() {
410
+ try {
411
+ const cfg = loadConfig();
412
+ return Math.max(0, cfg.agents?.defaults?.heartbeat?.ackMaxChars ?? DEFAULT_HEARTBEAT_ACK_MAX_CHARS);
413
+ } catch {
414
+ return DEFAULT_HEARTBEAT_ACK_MAX_CHARS;
415
+ }
416
+ }
417
+ function resolveHeartbeatContext(runId, sourceRunId) {
418
+ const primary = getAgentRunContext(runId);
419
+ if (primary?.isHeartbeat) return primary;
420
+ if (sourceRunId && sourceRunId !== runId) {
421
+ const source = getAgentRunContext(sourceRunId);
422
+ if (source?.isHeartbeat) return source;
423
+ }
424
+ return primary;
425
+ }
426
+ /**
427
+ * Check if heartbeat ACK/noise should be hidden from interactive chat surfaces.
428
+ */
429
+ function shouldHideHeartbeatChatOutput(runId, sourceRunId) {
430
+ if (!resolveHeartbeatContext(runId, sourceRunId)?.isHeartbeat) return false;
431
+ try {
432
+ return !resolveHeartbeatVisibility({
433
+ cfg: loadConfig(),
434
+ channel: "webchat"
435
+ }).showOk;
436
+ } catch {
437
+ return true;
438
+ }
439
+ }
440
+ function createChatRunRegistry() {
441
+ const chatRunSessions = /* @__PURE__ */ new Map();
442
+ const add = (sessionId, entry) => {
443
+ const queue = chatRunSessions.get(sessionId);
444
+ if (queue) queue.push(entry);
445
+ else chatRunSessions.set(sessionId, [entry]);
446
+ };
447
+ const peek = (sessionId) => chatRunSessions.get(sessionId)?.[0];
448
+ const shift = (sessionId) => {
449
+ const queue = chatRunSessions.get(sessionId);
450
+ if (!queue || queue.length === 0) return;
451
+ const entry = queue.shift();
452
+ if (!queue.length) chatRunSessions.delete(sessionId);
453
+ return entry;
454
+ };
455
+ const remove = (sessionId, clientRunId, sessionKey) => {
456
+ const queue = chatRunSessions.get(sessionId);
457
+ if (!queue || queue.length === 0) return;
458
+ const idx = queue.findIndex((entry) => entry.clientRunId === clientRunId && (sessionKey ? entry.sessionKey === sessionKey : true));
459
+ if (idx < 0) return;
460
+ const [entry] = queue.splice(idx, 1);
461
+ if (!queue.length) chatRunSessions.delete(sessionId);
462
+ return entry;
463
+ };
464
+ const clear = () => {
465
+ chatRunSessions.clear();
466
+ };
467
+ return {
468
+ add,
469
+ peek,
470
+ shift,
471
+ remove,
472
+ clear
473
+ };
474
+ }
475
+ function createChatRunState() {
476
+ const registry = createChatRunRegistry();
477
+ const buffers = /* @__PURE__ */ new Map();
478
+ const deltaSentAt = /* @__PURE__ */ new Map();
479
+ const pendingDeltaText = /* @__PURE__ */ new Map();
480
+ const abortedRuns = /* @__PURE__ */ new Map();
481
+ const clear = () => {
482
+ registry.clear();
483
+ buffers.clear();
484
+ deltaSentAt.clear();
485
+ pendingDeltaText.clear();
486
+ abortedRuns.clear();
487
+ };
488
+ return {
489
+ registry,
490
+ buffers,
491
+ deltaSentAt,
492
+ pendingDeltaText,
493
+ abortedRuns,
494
+ clear
495
+ };
496
+ }
497
+ const TOOL_EVENT_RECIPIENT_TTL_MS = 600 * 1e3;
498
+ const TOOL_EVENT_RECIPIENT_FINAL_GRACE_MS = 30 * 1e3;
499
+ function createToolEventRecipientRegistry() {
500
+ const recipients = /* @__PURE__ */ new Map();
501
+ const prune = () => {
502
+ if (recipients.size === 0) return;
503
+ const now = Date.now();
504
+ for (const [runId, entry] of recipients) if (now >= (entry.finalizedAt ? entry.finalizedAt + TOOL_EVENT_RECIPIENT_FINAL_GRACE_MS : entry.updatedAt + TOOL_EVENT_RECIPIENT_TTL_MS)) recipients.delete(runId);
505
+ };
506
+ const add = (runId, connId) => {
507
+ if (!runId || !connId) return;
508
+ const now = Date.now();
509
+ const existing = recipients.get(runId);
510
+ if (existing) {
511
+ existing.connIds.add(connId);
512
+ existing.updatedAt = now;
513
+ } else recipients.set(runId, {
514
+ connIds: new Set([connId]),
515
+ updatedAt: now
516
+ });
517
+ prune();
518
+ };
519
+ const get = (runId) => {
520
+ const entry = recipients.get(runId);
521
+ if (!entry) return;
522
+ entry.updatedAt = Date.now();
523
+ prune();
524
+ return entry.connIds;
525
+ };
526
+ const markFinal = (runId) => {
527
+ const entry = recipients.get(runId);
528
+ if (!entry) return;
529
+ entry.finalizedAt = Date.now();
530
+ prune();
531
+ };
532
+ return {
533
+ add,
534
+ get,
535
+ markFinal
536
+ };
537
+ }
538
+ function createAgentEventHandler({ broadcast, broadcastToConnIds, nodeSendToSession, agentRunSeq, chatRunState, resolveSessionKeyForRun, clearAgentRunContext, toolEventRecipients }) {
539
+ const emitChatDelta = (sessionKey, clientRunId, sourceRunId, seq, text) => {
540
+ if (isSilentReplyText(text, SILENT_REPLY_TOKEN)) return;
541
+ const prev = chatRunState.buffers.get(clientRunId) ?? "";
542
+ chatRunState.buffers.set(clientRunId, prev + text);
543
+ if (shouldHideHeartbeatChatOutput(clientRunId, sourceRunId)) return;
544
+ const now = Date.now();
545
+ if (now - (chatRunState.deltaSentAt.get(clientRunId) ?? 0) < 150) {
546
+ chatRunState.pendingDeltaText.set(clientRunId, (chatRunState.pendingDeltaText.get(clientRunId) ?? "") + text);
547
+ return;
548
+ }
549
+ const buffered = chatRunState.pendingDeltaText.get(clientRunId) ?? "";
550
+ chatRunState.pendingDeltaText.delete(clientRunId);
551
+ const fullText = buffered + text;
552
+ chatRunState.deltaSentAt.set(clientRunId, now);
553
+ const payload = {
554
+ runId: clientRunId,
555
+ sessionKey,
556
+ seq,
557
+ state: "delta",
558
+ ...resolveHeartbeatContext(clientRunId, sourceRunId)?.isHeartbeat ? { isHeartbeat: true } : {},
559
+ message: {
560
+ role: "assistant",
561
+ content: [{
562
+ type: "text",
563
+ text: fullText
564
+ }],
565
+ timestamp: now
566
+ }
567
+ };
568
+ broadcast("chat", payload, { dropIfSlow: true });
569
+ nodeSendToSession(sessionKey, "chat", payload);
570
+ };
571
+ const emitChatFinal = (sessionKey, clientRunId, sourceRunId, seq, jobState, error) => {
572
+ const remainingDelta = chatRunState.pendingDeltaText.get(clientRunId);
573
+ if (remainingDelta && !shouldHideHeartbeatChatOutput(clientRunId, sourceRunId)) {
574
+ const flushPayload = {
575
+ runId: clientRunId,
576
+ sessionKey,
577
+ seq,
578
+ state: "delta",
579
+ ...resolveHeartbeatContext(clientRunId, sourceRunId)?.isHeartbeat ? { isHeartbeat: true } : {},
580
+ message: {
581
+ role: "assistant",
582
+ content: [{
583
+ type: "text",
584
+ text: remainingDelta
585
+ }],
586
+ timestamp: Date.now()
587
+ }
588
+ };
589
+ broadcast("chat", flushPayload);
590
+ nodeSendToSession(sessionKey, "chat", flushPayload);
591
+ }
592
+ chatRunState.pendingDeltaText.delete(clientRunId);
593
+ const bufferedText = chatRunState.buffers.get(clientRunId)?.trim() ?? "";
594
+ const heartbeatCtx = resolveHeartbeatContext(clientRunId, sourceRunId);
595
+ const isHeartbeatRun = !!heartbeatCtx?.isHeartbeat;
596
+ const heartbeatHidden = isHeartbeatRun && shouldHideHeartbeatChatOutput(clientRunId, sourceRunId);
597
+ const filterResult = isHeartbeatRun && !heartbeatHidden ? {
598
+ action: "deliver",
599
+ output: bufferedText,
600
+ reason: "deliver"
601
+ } : classifyOutboundMessage(bufferedText, {
602
+ isHeartbeat: heartbeatHidden,
603
+ heartbeatAckMaxChars: resolveHeartbeatAckMaxChars()
604
+ });
605
+ const text = filterResult.output.trim();
606
+ const shouldSuppressSilent = filterResult.action === "drop";
607
+ chatRunState.buffers.delete(clientRunId);
608
+ chatRunState.deltaSentAt.delete(clientRunId);
609
+ if (jobState === "done") {
610
+ const payload = {
611
+ runId: clientRunId,
612
+ sessionKey,
613
+ seq,
614
+ state: "final",
615
+ activeSubagentCount: countActiveRunsForSession(sessionKey),
616
+ ...heartbeatCtx?.isHeartbeat ? { isHeartbeat: true } : {},
617
+ message: text && !shouldSuppressSilent ? {
618
+ role: "assistant",
619
+ content: [{
620
+ type: "text",
621
+ text
622
+ }],
623
+ timestamp: Date.now()
624
+ } : void 0
625
+ };
626
+ broadcast("chat", payload);
627
+ nodeSendToSession(sessionKey, "chat", payload);
628
+ return;
629
+ }
630
+ const payload = {
631
+ runId: clientRunId,
632
+ sessionKey,
633
+ seq,
634
+ state: "error",
635
+ errorMessage: error ? formatForLog(error) : void 0,
636
+ ...heartbeatCtx?.isHeartbeat ? { isHeartbeat: true } : {}
637
+ };
638
+ broadcast("chat", payload);
639
+ nodeSendToSession(sessionKey, "chat", payload);
640
+ };
641
+ const resolveToolVerboseLevel = (runId, sessionKey) => {
642
+ const runVerbose = normalizeVerboseLevel(getAgentRunContext(runId)?.verboseLevel);
643
+ if (runVerbose) return runVerbose;
644
+ if (!sessionKey) return "off";
645
+ try {
646
+ const { cfg, entry } = loadSessionEntry(sessionKey);
647
+ const sessionVerbose = normalizeVerboseLevel(entry?.verboseLevel);
648
+ if (sessionVerbose) return sessionVerbose;
649
+ return normalizeVerboseLevel(cfg.agents?.defaults?.verboseDefault) ?? "off";
650
+ } catch {
651
+ return "off";
652
+ }
653
+ };
654
+ return (evt) => {
655
+ const chatLink = chatRunState.registry.peek(evt.runId);
656
+ const eventSessionKey = typeof evt.sessionKey === "string" && evt.sessionKey.trim() ? evt.sessionKey : void 0;
657
+ const sessionKey = chatLink?.sessionKey ?? eventSessionKey ?? resolveSessionKeyForRun(evt.runId);
658
+ if (sessionKey?.startsWith("temp:")) return;
659
+ const clientRunId = chatLink?.clientRunId ?? evt.runId;
660
+ const eventRunId = chatLink?.clientRunId ?? evt.runId;
661
+ const eventForClients = chatLink ? {
662
+ ...evt,
663
+ runId: eventRunId
664
+ } : evt;
665
+ const isAborted = chatRunState.abortedRuns.has(clientRunId) || chatRunState.abortedRuns.has(evt.runId);
666
+ const heartbeatAgentCtx = resolveHeartbeatContext(clientRunId, evt.runId);
667
+ const agentPayload = {
668
+ ...eventForClients,
669
+ ...sessionKey ? { sessionKey } : {},
670
+ ...heartbeatAgentCtx?.isHeartbeat ? { isHeartbeat: true } : {}
671
+ };
672
+ const last = agentRunSeq.get(evt.runId) ?? 0;
673
+ const isToolEvent = evt.stream === "tool";
674
+ const toolVerbose = isToolEvent ? resolveToolVerboseLevel(evt.runId, sessionKey) : "off";
675
+ const toolPayload = isToolEvent && toolVerbose !== "full" ? (() => {
676
+ const data = evt.data ? { ...evt.data } : {};
677
+ delete data.result;
678
+ delete data.partialResult;
679
+ return sessionKey ? {
680
+ ...eventForClients,
681
+ sessionKey,
682
+ data
683
+ } : {
684
+ ...eventForClients,
685
+ data
686
+ };
687
+ })() : agentPayload;
688
+ if (evt.seq !== last + 1) broadcast("agent", {
689
+ runId: eventRunId,
690
+ stream: "error",
691
+ ts: Date.now(),
692
+ sessionKey,
693
+ ...heartbeatAgentCtx?.isHeartbeat ? { isHeartbeat: true } : {},
694
+ data: {
695
+ reason: "seq gap",
696
+ expected: last + 1,
697
+ received: evt.seq
698
+ }
699
+ });
700
+ agentRunSeq.set(evt.runId, evt.seq);
701
+ if (isToolEvent) {
702
+ const recipients = toolEventRecipients.get(evt.runId);
703
+ if (recipients && recipients.size > 0) broadcastToConnIds("agent", toolPayload, recipients);
704
+ } else broadcast("agent", agentPayload);
705
+ const lifecyclePhase = evt.stream === "lifecycle" && typeof evt.data?.phase === "string" ? evt.data.phase : null;
706
+ if (lifecyclePhase === "start" && sessionKey && !isAborted) {
707
+ if (!resolveHeartbeatContext(clientRunId, evt.runId)?.isHeartbeat) broadcast("chat", {
708
+ runId: clientRunId,
709
+ sessionKey,
710
+ seq: evt.seq,
711
+ state: "thinking"
712
+ });
713
+ }
714
+ if (lifecyclePhase && sessionKey && sessionKey.includes(":subagent:")) {
715
+ if (lifecyclePhase === "start") broadcast("subagent", {
716
+ phase: "started",
717
+ sessionKey,
718
+ runId: clientRunId
719
+ });
720
+ else if (lifecyclePhase === "end" || lifecyclePhase === "error") broadcast("subagent", {
721
+ phase: "completed",
722
+ sessionKey,
723
+ runId: clientRunId
724
+ });
725
+ }
726
+ if (sessionKey) {
727
+ if (!isToolEvent || toolVerbose !== "off") nodeSendToSession(sessionKey, "agent", isToolEvent ? toolPayload : agentPayload);
728
+ if (!isAborted && evt.stream === "assistant" && typeof evt.data?.text === "string") {
729
+ const deltaText = typeof evt.data?.delta === "string" && evt.data.delta ? evt.data.delta : evt.data.text;
730
+ emitChatDelta(sessionKey, clientRunId, evt.runId, evt.seq, deltaText);
731
+ } else if (!isAborted && (lifecyclePhase === "end" || lifecyclePhase === "error")) if (chatLink) {
732
+ const finished = chatRunState.registry.shift(evt.runId);
733
+ if (!finished) {
734
+ clearAgentRunContext(evt.runId);
735
+ return;
736
+ }
737
+ emitChatFinal(finished.sessionKey, finished.clientRunId, evt.runId, evt.seq, lifecyclePhase === "error" ? "error" : "done", evt.data?.error);
738
+ } else emitChatFinal(sessionKey, eventRunId, evt.runId, evt.seq, lifecyclePhase === "error" ? "error" : "done", evt.data?.error);
739
+ else if (isAborted && (lifecyclePhase === "end" || lifecyclePhase === "error")) {
740
+ chatRunState.abortedRuns.delete(clientRunId);
741
+ chatRunState.abortedRuns.delete(evt.runId);
742
+ chatRunState.buffers.delete(clientRunId);
743
+ chatRunState.deltaSentAt.delete(clientRunId);
744
+ if (chatLink) chatRunState.registry.remove(evt.runId, clientRunId, sessionKey);
745
+ }
746
+ }
747
+ if (lifecyclePhase === "end" || lifecyclePhase === "error") {
748
+ toolEventRecipients.markFinal(evt.runId);
749
+ clearAgentRunContext(evt.runId);
750
+ agentRunSeq.delete(evt.runId);
751
+ agentRunSeq.delete(clientRunId);
752
+ }
753
+ };
754
+ }
755
+
406
756
  //#endregion
407
757
  //#region src/cron/run-log.ts
408
758
  function resolveCronRunLogPath(params) {
@@ -496,12 +846,14 @@ function resolveChatRunExpiresAtMs(params) {
496
846
  }
497
847
  function broadcastChatAborted(ops, params) {
498
848
  const { runId, sessionKey, stopReason, partialText } = params;
849
+ const heartbeatCtx = resolveHeartbeatContext(runId);
499
850
  const payload = {
500
851
  runId,
501
852
  sessionKey,
502
853
  seq: (ops.agentRunSeq.get(runId) ?? 0) + 1,
503
854
  state: "aborted",
504
855
  stopReason,
856
+ ...heartbeatCtx?.isHeartbeat ? { isHeartbeat: true } : {},
505
857
  message: partialText ? {
506
858
  role: "assistant",
507
859
  content: [{
@@ -4110,11 +4462,13 @@ function nextChatSeq(context, runId) {
4110
4462
  }
4111
4463
  function broadcastChatFinal(params) {
4112
4464
  const seq = nextChatSeq({ agentRunSeq: params.context.agentRunSeq }, params.runId);
4465
+ const heartbeatCtx = resolveHeartbeatContext(params.runId);
4113
4466
  const payload = {
4114
4467
  runId: params.runId,
4115
4468
  sessionKey: params.sessionKey,
4116
4469
  seq,
4117
4470
  state: "final",
4471
+ ...heartbeatCtx?.isHeartbeat ? { isHeartbeat: true } : {},
4118
4472
  message: params.message
4119
4473
  };
4120
4474
  params.context.broadcast("chat", payload);
@@ -4123,11 +4477,13 @@ function broadcastChatFinal(params) {
4123
4477
  }
4124
4478
  function broadcastChatError(params) {
4125
4479
  const seq = nextChatSeq({ agentRunSeq: params.context.agentRunSeq }, params.runId);
4480
+ const heartbeatCtx = resolveHeartbeatContext(params.runId);
4126
4481
  const payload = {
4127
4482
  runId: params.runId,
4128
4483
  sessionKey: params.sessionKey,
4129
4484
  seq,
4130
4485
  state: "error",
4486
+ ...heartbeatCtx?.isHeartbeat ? { isHeartbeat: true } : {},
4131
4487
  errorMessage: params.errorMessage
4132
4488
  };
4133
4489
  params.context.broadcast("chat", payload);
@@ -9601,4 +9957,4 @@ async function handleGatewayRequest(opts) {
9601
9957
  }
9602
9958
 
9603
9959
  //#endregion
9604
- export { startGatewayConfigReloader as C, resolveCronRunLogPath as S, MAX_PAYLOAD_BYTES as _, loadFavoritesSet as a, abortChatRunById as b, resolveAssistantIdentity as c, formatError as d, loadVoiceWakeConfig as f, MAX_BUFFERED_BYTES as g, HEALTH_REFRESH_INTERVAL_MS as h, safeParseJson as i, listSystemPresence as l, DEDUPE_TTL_MS as m, handleGatewayRequest as n, reconcileFavorites as o, DEDUPE_MAX as p, broadcastPresenceSnapshot as r, DEFAULT_ASSISTANT_IDENTITY as s, coreGatewayHandlers as t, upsertPresence as u, TICK_INTERVAL_MS as v, appendCronRunLog as x, getHandshakeTimeoutMs as y };
9960
+ export { createAgentEventHandler as C, startGatewayConfigReloader as E, resolveCronRunLogPath as S, createToolEventRecipientRegistry as T, MAX_PAYLOAD_BYTES as _, loadFavoritesSet as a, abortChatRunById as b, resolveAssistantIdentity as c, formatError as d, loadVoiceWakeConfig as f, MAX_BUFFERED_BYTES as g, HEALTH_REFRESH_INTERVAL_MS as h, safeParseJson as i, listSystemPresence as l, DEDUPE_TTL_MS as m, handleGatewayRequest as n, reconcileFavorites as o, DEDUPE_MAX as p, broadcastPresenceSnapshot as r, DEFAULT_ASSISTANT_IDENTITY as s, coreGatewayHandlers as t, upsertPresence as u, TICK_INTERVAL_MS as v, createChatRunState as w, appendCronRunLog as x, getHandshakeTimeoutMs as y };