@seanhogg/builderforce-agents 2026.10.3 → 2026.10.4

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 (143) hide show
  1. package/dist/{agent-CxhUn-aN.js → agent-Cu57zjv6.js} +1 -1
  2. package/dist/{agent-CiEaiH-p.js → agent-LoZ_09Jv.js} +1 -1
  3. package/dist/{agents-DkKFDcYq.js → agents-Dgrr6E7S.js} +1 -1
  4. package/dist/{agents-IZrPoZIi.js → agents-DiRof4zA.js} +1 -1
  5. package/dist/{audio-preflight-COZAlqnx.js → audio-preflight-Cg4vjX8I.js} +1 -1
  6. package/dist/{auth-choice-CrYQF7zX.js → auth-choice-BJmosINc.js} +1 -1
  7. package/dist/{auth-choice-DhUBmu6y.js → auth-choice-CDoW8QDy.js} +1 -1
  8. package/dist/{auth-choice.apply-Botyf6Sg.js → auth-choice.apply-25j_lhua.js} +1 -1
  9. package/dist/{auth-choice.apply-k9tk1hGj.js → auth-choice.apply-CE1TC_Ts.js} +1 -1
  10. package/dist/{auth-choice.apply-Cch5UXis.js → auth-choice.apply-DSHzvYNu.js} +1 -1
  11. package/dist/{auth-choice.apply-CXRcLO-h.js → auth-choice.apply-ND2C2oSe.js} +1 -1
  12. package/dist/{auth-choice.apply.transformers-BkN8HlZJ.js → auth-choice.apply.transformers-BF-qyu2L.js} +1 -1
  13. package/dist/{auth-choice.apply.transformers-B9SieNNk.js → auth-choice.apply.transformers-CBQbUAwr.js} +1 -1
  14. package/dist/{auth-choice.apply.transformers-D02W3zy7.js → auth-choice.apply.transformers-DE9QrzbX.js} +1 -1
  15. package/dist/{auth-choice.apply.transformers-Dnr7Izx1.js → auth-choice.apply.transformers-vr05ATPq.js} +1 -1
  16. package/dist/{banner-Bd45EXyp.js → banner-Bx4c92N8.js} +1 -1
  17. package/dist/build-info.json +3 -3
  18. package/dist/{builderforce-BxVfTQsc.js → builderforce-DHU87PJG.js} +1 -1
  19. package/dist/{builderforce-C86noipf.js → builderforce-DgYCZ3Up.js} +1 -1
  20. package/dist/bundled/boot-md/handler.js +1 -1
  21. package/dist/bundled/session-memory/handler.js +1 -1
  22. package/dist/{channel-options-BHetVK54.js → channel-options-BZoCW2EZ.js} +1 -1
  23. package/dist/{channel-options-D5PmuxT-.js → channel-options-DAkHvC-x.js} +1 -1
  24. package/dist/{channel-web-B5QgCj6B.js → channel-web-BWEX1FnI.js} +1 -1
  25. package/dist/{channels-cli-sHtDH37K.js → channels-cli-DHFIXbTT.js} +1 -1
  26. package/dist/{channels-cli-CgZqXqUm.js → channels-cli-DvkQEBwz.js} +1 -1
  27. package/dist/chrome-CbBg1ngA.js +4 -0
  28. package/dist/{cli-DKoe6Ywl.js → cli-C9bsC2UP.js} +1 -1
  29. package/dist/{cli-DlaHihmr.js → cli-DnMFuBeA.js} +1 -1
  30. package/dist/{command-registry-FQIQbQAx.js → command-registry-DUOpdtcT.js} +1 -1
  31. package/dist/{command-registry-BhyY4aXy.js → command-registry-DrRz6Wgg.js} +1 -1
  32. package/dist/{completion-cli-D86ydD3X.js → completion-cli-BtLeKqh_.js} +1 -1
  33. package/dist/{completion-cli-H4iKy2_f.js → completion-cli-Cq33pQdJ.js} +1 -1
  34. package/dist/{completion-cli-CoFRiwNp.js → completion-cli-EbyCUnCP.js} +1 -1
  35. package/dist/{completion-cli-DF6vmGRs.js → completion-cli-mzQa8oTd.js} +1 -1
  36. package/dist/{config-cli-D6KAk3vw.js → config-cli-BIQl_nrn.js} +1 -1
  37. package/dist/{config-cli-9HoPtGDR.js → config-cli-Dw1pr9MW.js} +1 -1
  38. package/dist/{configure-B_FvthXy.js → configure-B1HJIRSM.js} +1 -1
  39. package/dist/{configure-CYwCU0Hw.js → configure-BPX5i4at.js} +1 -1
  40. package/dist/{configure-BgZGeNXf.js → configure-CKm9_xkS.js} +1 -1
  41. package/dist/{configure-6QCgecON.js → configure-CQPFd8N9.js} +1 -1
  42. package/dist/{deps-jUQM2eq1.js → deps-DN7fhGiB.js} +1 -1
  43. package/dist/{doctor-completion-CZrfkBfj.js → doctor-completion-B7JXY8EJ.js} +1 -1
  44. package/dist/{doctor-completion-BSbAN5p1.js → doctor-completion-BEVC1EV7.js} +1 -1
  45. package/dist/{embedded-CA0n2tyG.js → embedded-BBM-usEa.js} +7 -7
  46. package/dist/{embedded-SSuKQ6Yc.js → embedded-CIuP-6Ex.js} +2 -2
  47. package/dist/entry.js +1 -1
  48. package/dist/extensionAPI.js +1 -1
  49. package/dist/{gateway-cli-8SuDvuCq.js → gateway-cli-CvdguqNO.js} +2 -2
  50. package/dist/{gateway-cli-D5pW1jLs.js → gateway-cli-DvMzpFIF.js} +2 -2
  51. package/dist/{health-BLW40WUJ.js → health-Bd0YvHPq.js} +1 -1
  52. package/dist/{health-DqZB_jd8.js → health-CcUquV5P.js} +1 -1
  53. package/dist/{health-Cggr6c-2.js → health-CoTbsx1p.js} +1 -1
  54. package/dist/{hooks-cli-BQZjt-Fk.js → hooks-cli-D1mx0_F_.js} +1 -1
  55. package/dist/{hooks-cli-D5Zt0sN4.js → hooks-cli-Dr0hMOiz.js} +1 -1
  56. package/dist/index.js +2 -2
  57. package/dist/llm-slug-generator.js +1 -1
  58. package/dist/{models-DH9Vrv7O.js → models-D3MukbTO.js} +1 -1
  59. package/dist/{models-cli-DLZZwy_m.js → models-cli-CBUEjJ_T.js} +1 -1
  60. package/dist/{models-cli-CAaWi4TX.js → models-cli-nD2MyRO3.js} +1 -1
  61. package/dist/{models-bp562zNz.js → models-px2EtCBB.js} +1 -1
  62. package/dist/{onboard-pzmSj6MG.js → onboard-CelRLEbD.js} +1 -1
  63. package/dist/{onboard-CpFQ-bpz.js → onboard-D_Ja6cJL.js} +1 -1
  64. package/dist/{onboard-channels-BsMS0Ehd.js → onboard-channels-C5v3gxTE.js} +1 -1
  65. package/dist/{onboard-channels-D1FMu5M8.js → onboard-channels-CEMtoVzX.js} +1 -1
  66. package/dist/{onboard-channels-CKWKLbTn.js → onboard-channels-DIvxrZLb.js} +1 -1
  67. package/dist/{onboard-channels-CqXCWPaQ.js → onboard-channels-pPjt4AF5.js} +1 -1
  68. package/dist/{onboard-interactive-BAcb1Yd8.js → onboard-interactive-BIVMtUaZ.js} +1 -1
  69. package/dist/{onboard-interactive-COTt-hGf.js → onboard-interactive-CeQp6fAt.js} +1 -1
  70. package/dist/{onboard-interactive-B_YG0JwA.js → onboard-interactive-D3YgFz9n.js} +1 -1
  71. package/dist/{onboard-interactive-BdwTeKJ2.js → onboard-interactive-tVpsWM3V.js} +1 -1
  72. package/dist/{onboarding-C8IDtM8O.js → onboarding-B9P9Rocf.js} +2 -2
  73. package/dist/{onboarding-BhMZqtBx.js → onboarding-DXxufSuN.js} +2 -2
  74. package/dist/{onboarding.finalize-DpyMh92r.js → onboarding.finalize-BJbv33Sa.js} +1 -1
  75. package/dist/{onboarding.finalize-DEhEHZPV.js → onboarding.finalize-CiIdxWgH.js} +1 -1
  76. package/dist/{outbound-send-deps-CKOfRpqk.js → outbound-send-deps-DL5n0r7v.js} +1 -1
  77. package/dist/{plugin-registry-Bi-9AQMd.js → plugin-registry-B5gTbK3m.js} +1 -1
  78. package/dist/{plugin-registry-nxUQWv6l.js → plugin-registry-CBXZbshG.js} +1 -1
  79. package/dist/{plugin-registry-BlKyKAq2.js → plugin-registry-DEWbh_9i.js} +1 -1
  80. package/dist/{plugin-registry-CqGq9jzk.js → plugin-registry-Glc-xriO.js} +1 -1
  81. package/dist/plugin-sdk/{channel-web-C3UtHX6b.js → channel-web-CW5s6vEZ.js} +1 -1
  82. package/dist/plugin-sdk/index.js +1 -1
  83. package/dist/plugin-sdk/{reply-BTKDKB2t.js → reply-pngAtrhW.js} +2 -2
  84. package/dist/plugin-sdk/{web-CsPSK9U2.js → web-DfrDkFj_.js} +1 -1
  85. package/dist/{plugins-CUhWH9-E.js → plugins-BJNBD6Si.js} +1 -1
  86. package/dist/{plugins-B8Lge-oB.js → plugins-BZnMash4.js} +1 -1
  87. package/dist/{plugins-cli-c36MSKiX.js → plugins-cli-Cv_bwpr4.js} +1 -1
  88. package/dist/{plugins-cli-CgjC_YvF.js → plugins-cli-DkFN_JgK.js} +1 -1
  89. package/dist/{program-QMtnfrM_.js → program-DYU1raxm.js} +2 -2
  90. package/dist/{program-context-BgCNjcCh.js → program-context-D4S-3zNt.js} +1 -1
  91. package/dist/{prompt-select-styled-CWG9o2CX.js → prompt-select-styled-BhKY5Oj4.js} +1 -1
  92. package/dist/{prompt-select-styled-m1_NXutn.js → prompt-select-styled-D1StbM6j.js} +1 -1
  93. package/dist/{provider-auth-helpers-BFCTgzr_.js → provider-auth-helpers-5ZQb3SEz.js} +1 -1
  94. package/dist/{provider-auth-helpers-D0eiRpeb.js → provider-auth-helpers-Cibq8oDi.js} +1 -1
  95. package/dist/{provider-dispatcher-Djomkp5i.js → provider-dispatcher-Bwaplzm8.js} +1 -1
  96. package/dist/{provider-dispatcher-B6kumPDM.js → provider-dispatcher-kL8Yl9XU.js} +1 -1
  97. package/dist/{push-apns-DalSFp-6.js → push-apns-BXmSvfvx.js} +1 -1
  98. package/dist/{push-apns-DwSjHMuA.js → push-apns-C9hsLIBU.js} +1 -1
  99. package/dist/{pw-ai-1DyAPekE.js → pw-ai-BLyUwyRC.js} +1 -1
  100. package/dist/{register.agent-BZn434eF.js → register.agent-C4x77WJe.js} +1 -1
  101. package/dist/{register.agent-DNaHcARI.js → register.agent-CbP_v3k5.js} +1 -1
  102. package/dist/{register.configure-GTH7BPIx.js → register.configure-B-j2lVkz.js} +1 -1
  103. package/dist/{register.configure-Bflad790.js → register.configure-BsBerk8U.js} +1 -1
  104. package/dist/{register.maintenance-Dl7P66Jm.js → register.maintenance-B83yzc-P.js} +1 -1
  105. package/dist/{register.maintenance-B1XK1zeY.js → register.maintenance-WLPWJ7vr.js} +1 -1
  106. package/dist/{register.message-CJS3PPCy.js → register.message-BVo8xLbS.js} +1 -1
  107. package/dist/{register.message-CA5LiG16.js → register.message-DZ9zcORn.js} +1 -1
  108. package/dist/{register.onboard-Bj6wFSzC.js → register.onboard-CWCqKyU7.js} +1 -1
  109. package/dist/{register.onboard-4y1mzgCn.js → register.onboard-D9mB9MLj.js} +1 -1
  110. package/dist/{register.setup-Cvk8SB1q.js → register.setup-BMFb9IC4.js} +1 -1
  111. package/dist/{register.setup-zLIWO_nF.js → register.setup-C22fWTFR.js} +1 -1
  112. package/dist/{register.status-health-sessions-CjxA4ATI.js → register.status-health-sessions-BqMqFeMA.js} +1 -1
  113. package/dist/{register.status-health-sessions-CIYKmgKO.js → register.status-health-sessions-C-jqKRZ5.js} +1 -1
  114. package/dist/{register.subclis-Ua7PkPpv.js → register.subclis-Ceyv8kgc.js} +1 -1
  115. package/dist/{register.subclis-Ct4QBaKi.js → register.subclis-DxcQwaQg.js} +1 -1
  116. package/dist/{reply-gZ_yr2mJ.js → reply-BeKidf2F.js} +4 -4
  117. package/dist/{run-main-Cyc_C0B-.js → run-main-EhlBxGJB.js} +1 -1
  118. package/dist/{runner-C1sy_uJN.js → runner-P3IfAnSL.js} +3 -3
  119. package/dist/{server-node-events-CSsH-eIF.js → server-node-events-BZuSkcbo.js} +1 -1
  120. package/dist/{server-node-events-Bz_Qo5BV.js → server-node-events-CIsEZSfR.js} +1 -1
  121. package/dist/{session-dirs-fh5kvbyH.js → session-dirs-DH7k5ehu.js} +1 -1
  122. package/dist/{session-dirs-DVL9vHmq.js → session-dirs-DgwMogyJ.js} +1 -1
  123. package/dist/{status-sAc6yoa3.js → status-BY0kS_wo.js} +1 -1
  124. package/dist/{status-SPonEO1J.js → status-B_SXw9W4.js} +1 -1
  125. package/dist/{status-DZYF4S6_.js → status-BqEzSHhZ.js} +1 -1
  126. package/dist/{status-ChEjU5un.js → status-Ca-hgLW_.js} +1 -1
  127. package/dist/{status-CpxCM8BO.js → status-_KIJcQH-.js} +1 -1
  128. package/dist/{subagent-registry-BHP3_ka8.js → subagent-registry-98yia-RN.js} +4 -4
  129. package/dist/{subagent-registry-BYK0Wq_w.js → subagent-registry-Ch9dN-TR.js} +1 -1
  130. package/dist/{subagent-registry-DR5M5QUP.js → subagent-registry-CiYeuaym.js} +1 -1
  131. package/dist/{tui-Ujq2bTco.js → tui-BIpdEy5i.js} +2 -2
  132. package/dist/{tui-BsMw6I4Y.js → tui-DeG1am8h.js} +2 -2
  133. package/dist/{tui-cli-CLYxMYyC.js → tui-cli-3mxSu-O0.js} +1 -1
  134. package/dist/{tui-cli-BBKMdwDt.js → tui-cli-CXRFHYWv.js} +1 -1
  135. package/dist/{update-cli-uQLI7RCN.js → update-cli-BYhJHTZ0.js} +1 -1
  136. package/dist/{update-cli-BKcCNOzz.js → update-cli-DkgHl95y.js} +1 -1
  137. package/dist/{web-Bkk568P6.js → web--D7qJmx6.js} +1 -1
  138. package/dist/{web-wR7gzEVJ.js → web-CgypI7gs.js} +1 -1
  139. package/dist/{web-CGo9DnE4.js → web-DKmwaw7q.js} +1 -1
  140. package/dist/{web-DktK5vCb.js → web-Dvcfg5Kd.js} +1 -1
  141. package/extensions/memory-lancedb/package.json +2 -2
  142. package/package.json +1 -1
  143. package/dist/chrome-CAuboFG7.js +0 -4
@@ -41,7 +41,7 @@ Assigned content references: ${content.join(`, `)}. Treat these as authoritative
41
41
 
42
42
  `)}function hasCrossChannelItems(items,resolveKey){let keys=new Set,hasUnkeyed=!1;for(let item of items){let resolved=resolveKey(item);if(resolved.cross)return!0;if(!resolved.key){hasUnkeyed=!0;continue}keys.add(resolved.key)}return keys.size===0?!1:hasUnkeyed?!0:keys.size>1}const ANNOUNCE_QUEUES=new Map;function getAnnounceQueue(key,settings,send){let existing=ANNOUNCE_QUEUES.get(key);if(existing)return applyQueueRuntimeSettings({target:existing,settings}),existing.send=send,existing;let created={items:[],draining:!1,lastEnqueuedAt:0,mode:settings.mode,debounceMs:typeof settings.debounceMs==`number`?Math.max(0,settings.debounceMs):1e3,cap:typeof settings.cap==`number`&&settings.cap>0?Math.floor(settings.cap):20,dropPolicy:settings.dropPolicy??`summarize`,droppedCount:0,summaryLines:[],send};return applyQueueRuntimeSettings({target:created,settings}),ANNOUNCE_QUEUES.set(key,created),created}function scheduleAnnounceDrain(key){let queue=ANNOUNCE_QUEUES.get(key);!queue||queue.draining||(queue.draining=!0,(async()=>{try{let forceIndividualCollect=!1;for(;queue.items.length>0||queue.droppedCount>0;){if(await waitForQueueDebounce(queue),queue.mode===`collect`){if(forceIndividualCollect){let next=queue.items[0];if(!next)break;await queue.send(next),queue.items.shift();continue}if(hasCrossChannelItems(queue.items,item=>item.origin?item.originKey?{key:item.originKey}:{cross:!0}:{})){forceIndividualCollect=!0;let next=queue.items[0];if(!next)break;await queue.send(next),queue.items.shift();continue}let items=queue.items.slice(),summary=previewQueueSummaryPrompt({state:queue,noun:`announce`}),prompt=buildCollectPrompt({title:`[Queued announce messages while agent was busy]`,items,summary,renderItem:(item,idx)=>`---\nQueued #${idx+1}\n${item.prompt}`.trim()}),last=items.at(-1);if(!last)break;await queue.send({...last,prompt}),queue.items.splice(0,items.length),summary&&clearQueueSummaryState(queue);continue}let summaryPrompt=previewQueueSummaryPrompt({state:queue,noun:`announce`});if(summaryPrompt){let next=queue.items[0];if(!next)break;await queue.send({...next,prompt:summaryPrompt}),queue.items.shift(),clearQueueSummaryState(queue);continue}let next=queue.items[0];if(!next)break;await queue.send(next),queue.items.shift()}}catch(err){queue.lastEnqueuedAt=Date.now(),defaultRuntime.error?.(`announce queue drain failed for ${key}: ${String(err)}`)}finally{queue.draining=!1,queue.items.length===0&&queue.droppedCount===0?ANNOUNCE_QUEUES.delete(key):scheduleAnnounceDrain(key)}})())}function enqueueAnnounce(params){let queue=getAnnounceQueue(params.key,params.settings,params.send);if(queue.lastEnqueuedAt=Date.now(),!applyQueueDropPolicy({queue,summarize:item=>item.summaryLine?.trim()||item.prompt.trim()}))return queue.dropPolicy===`new`&&scheduleAnnounceDrain(params.key),!1;let origin=normalizeDeliveryContext(params.item.origin),originKey=deliveryContextKey(origin);return queue.items.push({...params.item,origin,originKey}),scheduleAnnounceDrain(params.key),!0}function buildAnnounceIdFromChildRun(params){return`v1:${params.childSessionKey}:${params.childRunId}`}function buildAnnounceIdempotencyKey(announceId){return`announce:${announceId}`}function resolveQueueAnnounceId(params){return params.announceId?.trim()||`legacy:${params.sessionKey}:${params.enqueuedAt}`}function normalizeSpawnDepth(value){if(typeof value==`number`)return Number.isInteger(value)&&value>=0?value:void 0;if(typeof value==`string`){let trimmed=value.trim();if(!trimmed)return;let numeric=Number(trimmed);return Number.isInteger(numeric)&&numeric>=0?numeric:void 0}}function normalizeSessionKey(value){if(typeof value==`string`)return value.trim()||void 0}function readSessionStore(storePath){try{let raw=fs.readFileSync(storePath,`utf-8`),parsed=JSON5.parse(raw);if(parsed&&typeof parsed==`object`&&!Array.isArray(parsed))return parsed}catch{}return{}}function buildKeyCandidates(rawKey,cfg){if(!cfg||rawKey===`global`||rawKey===`unknown`||parseAgentSessionKey(rawKey))return[rawKey];let prefixed=`agent:${resolveDefaultAgentId(cfg)}:${rawKey}`;return prefixed===rawKey?[rawKey]:[rawKey,prefixed]}function findEntryBySessionId(store,sessionId){let normalizedSessionId=normalizeSessionKey(sessionId);if(normalizedSessionId)for(let entry of Object.values(store)){let candidateSessionId=normalizeSessionKey(entry?.sessionId);if(candidateSessionId&&candidateSessionId===normalizedSessionId)return entry}}function resolveEntryForSessionKey(params){let candidates=buildKeyCandidates(params.sessionKey,params.cfg);if(params.store){for(let key of candidates){let entry=params.store[key];if(entry)return entry}return findEntryBySessionId(params.store,params.sessionKey)}if(params.cfg)for(let key of candidates){let parsed=parseAgentSessionKey(key);if(!parsed?.agentId)continue;let storePath=resolveStorePath(params.cfg.session?.store,{agentId:parsed.agentId}),store=params.cache.get(storePath);store||(store=readSessionStore(storePath),params.cache.set(storePath,store));let entry=store[key]??findEntryBySessionId(store,params.sessionKey);if(entry)return entry}}function getSubagentDepthFromSessionStore(sessionKey,opts){let raw=(sessionKey??``).trim(),fallbackDepth=getSubagentDepth(raw);if(!raw)return fallbackDepth;let cache=new Map,visited=new Set,depthFromStore=key=>{let normalizedKey=normalizeSessionKey(key);if(!normalizedKey||visited.has(normalizedKey))return;visited.add(normalizedKey);let entry=resolveEntryForSessionKey({sessionKey:normalizedKey,cfg:opts?.cfg,store:opts?.store,cache}),storedDepth=normalizeSpawnDepth(entry?.spawnDepth);if(storedDepth!==void 0)return storedDepth;let spawnedBy=normalizeSessionKey(entry?.spawnedBy);if(!spawnedBy)return;let parentDepth=depthFromStore(spawnedBy);return parentDepth===void 0?getSubagentDepth(spawnedBy)+1:parentDepth+1};return depthFromStore(raw)??fallbackDepth}function buildCompletionDeliveryMessage(params){let findingsText=params.findings.trim(),hasFindings=findingsText.length>0&&findingsText!==`(no output)`,header=`✅ Subagent ${params.subagentName} finished`;return hasFindings?`${header}\n\n${findingsText}`:header}function summarizeDeliveryError(error){if(error instanceof Error)return error.message||`error`;if(typeof error==`string`)return error;if(error==null)return`unknown error`;try{return JSON.stringify(error)}catch{return`error`}}function extractToolResultText$1(content){if(typeof content==`string`)return sanitizeTextContent(content);if(content&&typeof content==`object`&&!Array.isArray(content)){let obj=content;if(typeof obj.text==`string`)return sanitizeTextContent(obj.text);if(typeof obj.output==`string`)return sanitizeTextContent(obj.output);if(typeof obj.content==`string`)return sanitizeTextContent(obj.content);if(typeof obj.result==`string`)return sanitizeTextContent(obj.result);if(typeof obj.error==`string`)return sanitizeTextContent(obj.error);if(typeof obj.summary==`string`)return sanitizeTextContent(obj.summary)}return Array.isArray(content)?extractTextFromChatContent(content,{sanitizeText:sanitizeTextContent,normalizeText:text=>text,joinWith:`
43
43
  `})?.trim()??``:``}function extractInlineTextContent(content){return Array.isArray(content)?extractTextFromChatContent(content,{sanitizeText:sanitizeTextContent,normalizeText:text=>text.trim(),joinWith:``})??``:``}function extractSubagentOutputText(message){if(!message||typeof message!=`object`)return``;let role=message.role,content=message.content;return role===`assistant`?extractAssistantText(message)||(typeof content==`string`?sanitizeTextContent(content):Array.isArray(content)?extractInlineTextContent(content):``):role===`toolResult`||role===`tool`?extractToolResultText$1(message.content):typeof content==`string`?sanitizeTextContent(content):Array.isArray(content)?extractInlineTextContent(content):``}async function readLatestSubagentOutput(sessionKey){let history=await callGateway({method:`chat.history`,params:{sessionKey,limit:50}}),messages=Array.isArray(history?.messages)?history.messages:[];for(let i=messages.length-1;i>=0;--i){let msg=messages[i],text=extractSubagentOutputText(msg);if(text)return text}}async function readLatestSubagentOutputWithRetry(params){let deadline=Date.now()+Math.max(0,Math.min(params.maxWaitMs,15e3)),result;for(;Date.now()<deadline;){if(result=await readLatestSubagentOutput(params.sessionKey),result?.trim())return result;await new Promise(resolve=>setTimeout(resolve,100))}return result}function formatDurationShort(valueMs){if(!valueMs||!Number.isFinite(valueMs)||valueMs<=0)return`n/a`;let totalSeconds=Math.round(valueMs/1e3),hours=Math.floor(totalSeconds/3600),minutes=Math.floor(totalSeconds%3600/60),seconds=totalSeconds%60;return hours>0?`${hours}h${minutes}m`:minutes>0?`${minutes}m${seconds}s`:`${seconds}s`}function formatTokenCount$1(value){return typeof value!=`number`||!Number.isFinite(value)||value<=0?`0`:value>=1e6?`${(value/1e6).toFixed(1)}m`:value>=1e3?`${(value/1e3).toFixed(1)}k`:String(Math.round(value))}async function buildCompactAnnounceStatsLine(params){let cfg=loadConfig(),agentId=resolveAgentIdFromSessionKey(params.sessionKey),storePath=resolveStorePath(cfg.session?.store,{agentId}),entry=loadSessionStore(storePath)[params.sessionKey];for(let attempt=0;attempt<3&&!(typeof entry?.inputTokens==`number`||typeof entry?.outputTokens==`number`||typeof entry?.totalTokens==`number`);attempt+=1)await new Promise(resolve=>setTimeout(resolve,150)),entry=loadSessionStore(storePath)[params.sessionKey];let input=typeof entry?.inputTokens==`number`?entry.inputTokens:0,output=typeof entry?.outputTokens==`number`?entry.outputTokens:0,ioTotal=input+output,promptCache=typeof entry?.totalTokens==`number`?entry.totalTokens:void 0,parts=[`runtime ${formatDurationShort(typeof params.startedAt==`number`&&typeof params.endedAt==`number`?Math.max(0,params.endedAt-params.startedAt):void 0)}`,`tokens ${formatTokenCount$1(ioTotal)} (in ${formatTokenCount$1(input)} / out ${formatTokenCount$1(output)})`];return typeof promptCache==`number`&&promptCache>ioTotal&&parts.push(`prompt/cache ${formatTokenCount$1(promptCache)}`),`Stats: ${parts.join(` • `)}`}function resolveAnnounceOrigin(entry,requesterOrigin){let normalizedRequester=normalizeDeliveryContext(requesterOrigin),normalizedEntry=deliveryContextFromSession(entry);return normalizedRequester?.channel&&!isDeliverableMessageChannel(normalizedRequester.channel)?mergeDeliveryContext({accountId:normalizedRequester.accountId,threadId:normalizedRequester.threadId},normalizedEntry):mergeDeliveryContext(normalizedRequester,normalizedEntry)}async function sendAnnounce(item){let requesterIsSubagent=getSubagentDepthFromSessionStore(item.sessionKey)>=1,origin=item.origin,threadId=origin?.threadId!=null&&origin.threadId!==``?String(origin.threadId):void 0,idempotencyKey=buildAnnounceIdempotencyKey(resolveQueueAnnounceId({announceId:item.announceId,sessionKey:item.sessionKey,enqueuedAt:item.enqueuedAt}));await callGateway({method:`agent`,params:{sessionKey:item.sessionKey,message:item.prompt,channel:requesterIsSubagent?void 0:origin?.channel,accountId:requesterIsSubagent?void 0:origin?.accountId,to:requesterIsSubagent?void 0:origin?.to,threadId:requesterIsSubagent?void 0:threadId,deliver:!requesterIsSubagent,idempotencyKey},timeoutMs:15e3})}function resolveRequesterStoreKey(cfg,requesterSessionKey){let raw=requesterSessionKey.trim();if(!raw||raw===`global`||raw===`unknown`||raw.startsWith(`agent:`))return raw;let mainKey=normalizeMainKey(cfg.session?.mainKey);return raw===`main`||raw===mainKey?resolveMainSessionKey(cfg):`agent:${resolveAgentIdFromSessionKey(raw)}:${raw}`}function loadRequesterSessionEntry(requesterSessionKey){let cfg=loadConfig(),canonicalKey=resolveRequesterStoreKey(cfg,requesterSessionKey),agentId=resolveAgentIdFromSessionKey(canonicalKey);return{cfg,entry:loadSessionStore(resolveStorePath(cfg.session?.store,{agentId}))[canonicalKey],canonicalKey}}async function maybeQueueSubagentAnnounce(params){let{cfg,entry}=loadRequesterSessionEntry(params.requesterSessionKey),canonicalKey=resolveRequesterStoreKey(cfg,params.requesterSessionKey),sessionId=entry?.sessionId;if(!sessionId)return`none`;let queueSettings=resolveQueueSettings({cfg,channel:entry?.channel??entry?.lastChannel,sessionEntry:entry}),isActive=isEmbeddedRunActive(sessionId);if((queueSettings.mode===`steer`||queueSettings.mode===`steer-backlog`)&&queueEmbeddedMessage(sessionId,params.triggerMessage))return`steered`;let shouldFollowup=queueSettings.mode===`followup`||queueSettings.mode===`collect`||queueSettings.mode===`steer-backlog`||queueSettings.mode===`interrupt`;if(isActive&&(shouldFollowup||queueSettings.mode===`steer`)){let origin=resolveAnnounceOrigin(entry,params.requesterOrigin);return enqueueAnnounce({key:canonicalKey,item:{announceId:params.announceId,prompt:params.triggerMessage,summaryLine:params.summaryLine,enqueuedAt:Date.now(),sessionKey:canonicalKey,origin},settings:queueSettings,send:sendAnnounce}),`queued`}return`none`}function queueOutcomeToDeliveryResult(outcome){return outcome===`steered`?{delivered:!0,path:`steered`}:outcome===`queued`?{delivered:!0,path:`queued`}:{delivered:!1,path:`none`}}async function sendSubagentAnnounceDirectly(params){let canonicalRequesterSessionKey=resolveRequesterStoreKey(loadConfig(),params.targetRequesterSessionKey);try{let completionDirectOrigin=normalizeDeliveryContext(params.completionDirectOrigin),completionChannelRaw=typeof completionDirectOrigin?.channel==`string`?completionDirectOrigin.channel.trim():``,completionChannel=completionChannelRaw&&isDeliverableMessageChannel(completionChannelRaw)?completionChannelRaw:``,completionTo=typeof completionDirectOrigin?.to==`string`?completionDirectOrigin.to.trim():``,hasCompletionDirectTarget=!params.requesterIsSubagent&&!!completionChannel&&!!completionTo;if(params.expectsCompletionMessage&&hasCompletionDirectTarget&&params.completionMessage?.trim()){let completionThreadId=completionDirectOrigin?.threadId!=null&&completionDirectOrigin.threadId!==``?String(completionDirectOrigin.threadId):void 0;return await callGateway({method:`send`,params:{channel:completionChannel,to:completionTo,accountId:completionDirectOrigin?.accountId,threadId:completionThreadId,sessionKey:canonicalRequesterSessionKey,message:params.completionMessage,idempotencyKey:params.directIdempotencyKey},timeoutMs:15e3}),{delivered:!0,path:`direct`}}let directOrigin=normalizeDeliveryContext(params.directOrigin),threadId=directOrigin?.threadId!=null&&directOrigin.threadId!==``?String(directOrigin.threadId):void 0;return await callGateway({method:`agent`,params:{sessionKey:canonicalRequesterSessionKey,message:params.triggerMessage,deliver:!params.requesterIsSubagent,channel:params.requesterIsSubagent?void 0:directOrigin?.channel,accountId:params.requesterIsSubagent?void 0:directOrigin?.accountId,to:params.requesterIsSubagent?void 0:directOrigin?.to,threadId:params.requesterIsSubagent?void 0:threadId,idempotencyKey:params.directIdempotencyKey},expectFinal:!0,timeoutMs:15e3}),{delivered:!0,path:`direct`}}catch(err){return{delivered:!1,path:`direct`,error:summarizeDeliveryError(err)}}}async function deliverSubagentAnnouncement(params){if(!params.expectsCompletionMessage){let queued=queueOutcomeToDeliveryResult(await maybeQueueSubagentAnnounce({requesterSessionKey:params.requesterSessionKey,announceId:params.announceId,triggerMessage:params.triggerMessage,summaryLine:params.summaryLine,requesterOrigin:params.requesterOrigin}));if(queued.delivered)return queued}let direct=await sendSubagentAnnounceDirectly({targetRequesterSessionKey:params.targetRequesterSessionKey,triggerMessage:params.triggerMessage,completionMessage:params.completionMessage,directIdempotencyKey:params.directIdempotencyKey,completionDirectOrigin:params.completionDirectOrigin,directOrigin:params.directOrigin,requesterIsSubagent:params.requesterIsSubagent,expectsCompletionMessage:params.expectsCompletionMessage});if(direct.delivered||!params.expectsCompletionMessage)return direct;let queueOutcome=await maybeQueueSubagentAnnounce({requesterSessionKey:params.requesterSessionKey,announceId:params.announceId,triggerMessage:params.triggerMessage,summaryLine:params.summaryLine,requesterOrigin:params.requesterOrigin});return queueOutcome===`steered`||queueOutcome===`queued`?queueOutcomeToDeliveryResult(queueOutcome):direct}function loadSessionEntryByKey(sessionKey){let cfg=loadConfig(),agentId=resolveAgentIdFromSessionKey(sessionKey);return loadSessionStore(resolveStorePath(cfg.session?.store,{agentId}))[sessionKey]}function buildSubagentSystemPrompt(params){let taskText=typeof params.task==`string`&&params.task.trim()?params.task.replace(/\s+/g,` `).trim():`{{TASK_DESCRIPTION}}`,childDepth=typeof params.childDepth==`number`?params.childDepth:1,canSpawn=childDepth<(typeof params.maxSpawnDepth==`number`?params.maxSpawnDepth:1),parentLabel=childDepth>=2?`parent orchestrator`:`main agent`,lines=[`# Subagent Context`,``,`You are a **subagent** spawned by the ${parentLabel} for a specific task.`,``,`## Your Role`,`- You were created to handle: ${taskText}`,`- Complete this task. That's your entire purpose.`,`- You are NOT the ${parentLabel}. Don't try to be.`,``,`## Rules`,`1. **Stay focused** - Do your assigned task, nothing else`,`2. **Complete the task** - Your final message will be automatically reported to the ${parentLabel}`,`3. **Don't initiate** - No heartbeats, no proactive actions, no side quests`,`4. **Be ephemeral** - You may be terminated after task completion. That's fine.`,`5. **Trust push-based completion** - Descendant results are auto-announced back to you; do not busy-poll for status.`,"6. **Recover from compacted/truncated tool output** - If you see `[compacted: tool output removed to free context]` or `[truncated: output exceeded context limit]`, assume prior output was reduced. Re-read only what you need using smaller chunks (`read` with offset/limit, or targeted `rg`/`head`/`tail`) instead of full-file `cat`.",``,`## Output Format`,`When complete, your final response should include:`,`- What you accomplished or found`,`- Any relevant details the ${parentLabel} should know`,`- Keep it concise but informative`,``,`## What You DON'T Do`,`- NO user conversations (that's ${parentLabel}'s job)`,`- NO external messages (email, tweets, etc.) unless explicitly tasked with a specific recipient/channel`,`- NO cron jobs or persistent state`,`- NO pretending to be the ${parentLabel}`,`- Only use the \`message\` tool when explicitly instructed to contact a specific external recipient; otherwise return plain text and let the ${parentLabel} deliver it`,``];return canSpawn?lines.push(`## Sub-Agent Spawning`,"You CAN spawn your own sub-agents for parallel or complex work using `sessions_spawn`.","Use the `subagents` tool to steer, kill, or do an on-demand status check for your spawned sub-agents.",`Your sub-agents will announce their results back to you automatically (not to the main agent).`,`Default workflow: spawn work, continue orchestrating, and wait for auto-announced completions.`,"Do NOT repeatedly poll `subagents list` in a loop unless you are actively debugging or intervening.",`Coordinate their work and synthesize results before reporting back.`,``):childDepth>=2&&lines.push(`## Sub-Agent Spawning`,`You are a leaf worker and CANNOT spawn further sub-agents. Focus on your assigned task.`,``),lines.push(`## Session Context`,...[params.label?`- Label: ${params.label}`:void 0,params.requesterSessionKey?`- Requester session: ${params.requesterSessionKey}.`:void 0,params.requesterOrigin?.channel?`- Requester channel: ${params.requesterOrigin.channel}.`:void 0,`- Your session: ${params.childSessionKey}.`].filter(line=>line!==void 0),``),lines.join(`
44
- `)}function buildAnnounceReplyInstruction(params){if(params.expectsCompletionMessage)return`A completed ${params.announceType} is ready for user delivery. Convert the result above into your normal assistant voice and send that user-facing update now. Keep this internal context private (don't mention system/log/stats/session details or announce type).`;if(params.remainingActiveSubagentRuns>0){let activeRunsLabel=params.remainingActiveSubagentRuns===1?`run`:`runs`;return`There are still ${params.remainingActiveSubagentRuns} active subagent ${activeRunsLabel} for this session. If they are part of the same workflow, wait for the remaining results before sending a user update. If they are unrelated, respond normally using only the result above.`}return params.requesterIsSubagent?`Convert this completion into a concise internal orchestration update for your parent agent in your own words. Keep this internal context private (don't mention system/log/stats/session details or announce type). If this result is duplicate or no update is needed, reply ONLY: ${SILENT_REPLY_TOKEN}.`:`A completed ${params.announceType} is ready for user delivery. Convert the result above into your normal assistant voice and send that user-facing update now. Keep this internal context private (don't mention system/log/stats/session details or announce type), and do not copy the system message verbatim. Reply ONLY: ${SILENT_REPLY_TOKEN} if this exact result was already delivered to the user in this same turn.`}async function runSubagentAnnounceFlow(params){let didAnnounce=!1,expectsCompletionMessage=params.expectsCompletionMessage===!0,shouldDeleteChildSession=params.cleanup===`delete`;try{let targetRequesterSessionKey=params.requesterSessionKey,targetRequesterOrigin=normalizeDeliveryContext(params.requesterOrigin),childSessionId=(()=>{let entry=loadSessionEntryByKey(params.childSessionKey);return typeof entry?.sessionId==`string`&&entry.sessionId.trim()?entry.sessionId.trim():void 0})(),settleTimeoutMs=Math.min(Math.max(params.timeoutMs,1),12e4),reply=params.roundOneReply,outcome=params.outcome;if(!expectsCompletionMessage&&childSessionId&&isEmbeddedRunActive(childSessionId)&&!await waitForEmbeddedRunEnd(childSessionId,settleTimeoutMs)&&isEmbeddedRunActive(childSessionId))return shouldDeleteChildSession=!1,!1;if(!reply&&params.waitForCompletion!==!1){let waitMs=settleTimeoutMs,wait=await callGateway({method:`agent.wait`,params:{runId:params.childRunId,timeoutMs:waitMs},timeoutMs:waitMs+2e3}),waitError=typeof wait?.error==`string`?wait.error:void 0;wait?.status===`timeout`?outcome={status:`timeout`}:wait?.status===`error`?outcome={status:`error`,error:waitError}:wait?.status===`ok`&&(outcome={status:`ok`}),typeof wait?.startedAt==`number`&&!params.startedAt&&(params.startedAt=wait.startedAt),typeof wait?.endedAt==`number`&&!params.endedAt&&(params.endedAt=wait.endedAt),wait?.status===`timeout`&&(outcome||={status:`timeout`}),reply=await readLatestSubagentOutput(params.childSessionKey)}if(reply||=await readLatestSubagentOutput(params.childSessionKey),reply?.trim()||(reply=await readLatestSubagentOutputWithRetry({sessionKey:params.childSessionKey,maxWaitMs:params.timeoutMs})),!expectsCompletionMessage&&!reply?.trim()&&childSessionId&&isEmbeddedRunActive(childSessionId))return shouldDeleteChildSession=!1,!1;outcome||={status:`unknown`};let activeChildDescendantRuns=0;try{let{countActiveDescendantRuns}=await import(`./subagent-registry-DR5M5QUP.js`);activeChildDescendantRuns=Math.max(0,await countActiveDescendantRuns(params.childSessionKey))}catch{}if(!expectsCompletionMessage&&activeChildDescendantRuns>0)return shouldDeleteChildSession=!1,!1;let statusLabel=outcome.status===`ok`?`completed successfully`:outcome.status===`timeout`?`timed out`:outcome.status===`error`?`failed: ${outcome.error||`unknown error`}`:`finished with unknown status`,announceType=params.announceType??`subagent task`,taskLabel=params.label||params.task||`task`,subagentName=resolveAgentIdFromSessionKey(params.childSessionKey),announceSessionId=childSessionId||`unknown`,findings=reply||`(no output)`,completionMessage=``,triggerMessage=``,requesterDepth=getSubagentDepthFromSessionStore(targetRequesterSessionKey),requesterIsSubagent=!expectsCompletionMessage&&requesterDepth>=1;if(requesterIsSubagent){let{isSubagentSessionRunActive,resolveRequesterForChildSession}=await import(`./subagent-registry-DR5M5QUP.js`);if(!isSubagentSessionRunActive(targetRequesterSessionKey)){let parentSessionEntry=loadSessionEntryByKey(targetRequesterSessionKey);if(!(parentSessionEntry&&typeof parentSessionEntry.sessionId==`string`&&parentSessionEntry.sessionId.trim())){let fallback=await resolveRequesterForChildSession(targetRequesterSessionKey);if(!fallback?.requesterSessionKey)return shouldDeleteChildSession=!1,!1;targetRequesterSessionKey=fallback.requesterSessionKey,targetRequesterOrigin=normalizeDeliveryContext(fallback.requesterOrigin)??targetRequesterOrigin,requesterDepth=getSubagentDepthFromSessionStore(targetRequesterSessionKey),requesterIsSubagent=requesterDepth>=1}}}let remainingActiveSubagentRuns=0;try{let{countActiveDescendantRuns}=await import(`./subagent-registry-DR5M5QUP.js`);remainingActiveSubagentRuns=Math.max(0,await countActiveDescendantRuns(targetRequesterSessionKey))}catch{}let replyInstruction=buildAnnounceReplyInstruction({remainingActiveSubagentRuns,requesterIsSubagent,announceType,expectsCompletionMessage}),statsLine=await buildCompactAnnounceStatsLine({sessionKey:params.childSessionKey,startedAt:params.startedAt,endedAt:params.endedAt});completionMessage=buildCompletionDeliveryMessage({findings,subagentName}),triggerMessage=[[`[System Message] [sessionId: ${announceSessionId}] A ${announceType} "${taskLabel}" just ${statusLabel}.`,``,`Result:`,findings,``,statsLine].join(`
44
+ `)}function buildAnnounceReplyInstruction(params){if(params.expectsCompletionMessage)return`A completed ${params.announceType} is ready for user delivery. Convert the result above into your normal assistant voice and send that user-facing update now. Keep this internal context private (don't mention system/log/stats/session details or announce type).`;if(params.remainingActiveSubagentRuns>0){let activeRunsLabel=params.remainingActiveSubagentRuns===1?`run`:`runs`;return`There are still ${params.remainingActiveSubagentRuns} active subagent ${activeRunsLabel} for this session. If they are part of the same workflow, wait for the remaining results before sending a user update. If they are unrelated, respond normally using only the result above.`}return params.requesterIsSubagent?`Convert this completion into a concise internal orchestration update for your parent agent in your own words. Keep this internal context private (don't mention system/log/stats/session details or announce type). If this result is duplicate or no update is needed, reply ONLY: ${SILENT_REPLY_TOKEN}.`:`A completed ${params.announceType} is ready for user delivery. Convert the result above into your normal assistant voice and send that user-facing update now. Keep this internal context private (don't mention system/log/stats/session details or announce type), and do not copy the system message verbatim. Reply ONLY: ${SILENT_REPLY_TOKEN} if this exact result was already delivered to the user in this same turn.`}async function runSubagentAnnounceFlow(params){let didAnnounce=!1,expectsCompletionMessage=params.expectsCompletionMessage===!0,shouldDeleteChildSession=params.cleanup===`delete`;try{let targetRequesterSessionKey=params.requesterSessionKey,targetRequesterOrigin=normalizeDeliveryContext(params.requesterOrigin),childSessionId=(()=>{let entry=loadSessionEntryByKey(params.childSessionKey);return typeof entry?.sessionId==`string`&&entry.sessionId.trim()?entry.sessionId.trim():void 0})(),settleTimeoutMs=Math.min(Math.max(params.timeoutMs,1),12e4),reply=params.roundOneReply,outcome=params.outcome;if(!expectsCompletionMessage&&childSessionId&&isEmbeddedRunActive(childSessionId)&&!await waitForEmbeddedRunEnd(childSessionId,settleTimeoutMs)&&isEmbeddedRunActive(childSessionId))return shouldDeleteChildSession=!1,!1;if(!reply&&params.waitForCompletion!==!1){let waitMs=settleTimeoutMs,wait=await callGateway({method:`agent.wait`,params:{runId:params.childRunId,timeoutMs:waitMs},timeoutMs:waitMs+2e3}),waitError=typeof wait?.error==`string`?wait.error:void 0;wait?.status===`timeout`?outcome={status:`timeout`}:wait?.status===`error`?outcome={status:`error`,error:waitError}:wait?.status===`ok`&&(outcome={status:`ok`}),typeof wait?.startedAt==`number`&&!params.startedAt&&(params.startedAt=wait.startedAt),typeof wait?.endedAt==`number`&&!params.endedAt&&(params.endedAt=wait.endedAt),wait?.status===`timeout`&&(outcome||={status:`timeout`}),reply=await readLatestSubagentOutput(params.childSessionKey)}if(reply||=await readLatestSubagentOutput(params.childSessionKey),reply?.trim()||(reply=await readLatestSubagentOutputWithRetry({sessionKey:params.childSessionKey,maxWaitMs:params.timeoutMs})),!expectsCompletionMessage&&!reply?.trim()&&childSessionId&&isEmbeddedRunActive(childSessionId))return shouldDeleteChildSession=!1,!1;outcome||={status:`unknown`};let activeChildDescendantRuns=0;try{let{countActiveDescendantRuns}=await import(`./subagent-registry-CiYeuaym.js`);activeChildDescendantRuns=Math.max(0,await countActiveDescendantRuns(params.childSessionKey))}catch{}if(!expectsCompletionMessage&&activeChildDescendantRuns>0)return shouldDeleteChildSession=!1,!1;let statusLabel=outcome.status===`ok`?`completed successfully`:outcome.status===`timeout`?`timed out`:outcome.status===`error`?`failed: ${outcome.error||`unknown error`}`:`finished with unknown status`,announceType=params.announceType??`subagent task`,taskLabel=params.label||params.task||`task`,subagentName=resolveAgentIdFromSessionKey(params.childSessionKey),announceSessionId=childSessionId||`unknown`,findings=reply||`(no output)`,completionMessage=``,triggerMessage=``,requesterDepth=getSubagentDepthFromSessionStore(targetRequesterSessionKey),requesterIsSubagent=!expectsCompletionMessage&&requesterDepth>=1;if(requesterIsSubagent){let{isSubagentSessionRunActive,resolveRequesterForChildSession}=await import(`./subagent-registry-CiYeuaym.js`);if(!isSubagentSessionRunActive(targetRequesterSessionKey)){let parentSessionEntry=loadSessionEntryByKey(targetRequesterSessionKey);if(!(parentSessionEntry&&typeof parentSessionEntry.sessionId==`string`&&parentSessionEntry.sessionId.trim())){let fallback=await resolveRequesterForChildSession(targetRequesterSessionKey);if(!fallback?.requesterSessionKey)return shouldDeleteChildSession=!1,!1;targetRequesterSessionKey=fallback.requesterSessionKey,targetRequesterOrigin=normalizeDeliveryContext(fallback.requesterOrigin)??targetRequesterOrigin,requesterDepth=getSubagentDepthFromSessionStore(targetRequesterSessionKey),requesterIsSubagent=requesterDepth>=1}}}let remainingActiveSubagentRuns=0;try{let{countActiveDescendantRuns}=await import(`./subagent-registry-CiYeuaym.js`);remainingActiveSubagentRuns=Math.max(0,await countActiveDescendantRuns(targetRequesterSessionKey))}catch{}let replyInstruction=buildAnnounceReplyInstruction({remainingActiveSubagentRuns,requesterIsSubagent,announceType,expectsCompletionMessage}),statsLine=await buildCompactAnnounceStatsLine({sessionKey:params.childSessionKey,startedAt:params.startedAt,endedAt:params.endedAt});completionMessage=buildCompletionDeliveryMessage({findings,subagentName}),triggerMessage=[[`[System Message] [sessionId: ${announceSessionId}] A ${announceType} "${taskLabel}" just ${statusLabel}.`,``,`Result:`,findings,``,statsLine].join(`
45
45
  `),``,replyInstruction].join(`
46
46
  `);let announceId=buildAnnounceIdFromChildRun({childSessionKey:params.childSessionKey,childRunId:params.childRunId}),directOrigin=targetRequesterOrigin;if(!requesterIsSubagent){let{entry}=loadRequesterSessionEntry(targetRequesterSessionKey);directOrigin=resolveAnnounceOrigin(entry,targetRequesterOrigin)}let directIdempotencyKey=buildAnnounceIdempotencyKey(announceId),delivery=await deliverSubagentAnnouncement({requesterSessionKey:targetRequesterSessionKey,announceId,triggerMessage,completionMessage,summaryLine:taskLabel,requesterOrigin:targetRequesterOrigin,completionDirectOrigin:targetRequesterOrigin,directOrigin,targetRequesterSessionKey,requesterIsSubagent,expectsCompletionMessage,directIdempotencyKey});didAnnounce=delivery.delivered,!delivery.delivered&&delivery.path===`direct`&&delivery.error&&defaultRuntime.error?.(`Subagent completion direct announce failed for run ${params.childRunId}: ${delivery.error}`)}catch(err){defaultRuntime.error?.(`Subagent announce failed: ${String(err)}`)}finally{if(params.label)try{await callGateway({method:`sessions.patch`,params:{key:params.childSessionKey,label:params.label},timeoutMs:1e4})}catch{}if(shouldDeleteChildSession)try{await callGateway({method:`sessions.delete`,params:{key:params.childSessionKey,deleteTranscript:!0},timeoutMs:1e4})}catch{}}return didAnnounce}function resolveSubagentStateDir(env=process.env){return env.BUILDERFORCE_AGENTS_STATE_DIR?.trim()?resolveStateDir(env):env.VITEST||env.NODE_ENV===`test`?path.join(os.tmpdir(),`builderforce-test-state`,String(process.pid)):resolveStateDir(env)}function resolveSubagentRegistryPath(){return path.join(resolveSubagentStateDir(process.env),`subagents`,`runs.json`)}async function loadSubagentRegistryFromDisk(){let raw=await loadJsonFile(resolveSubagentRegistryPath());if(!raw||typeof raw!=`object`)return new Map;let record=raw;if(record.version!==1&&record.version!==2)return new Map;let runsRaw=record.runs;if(!runsRaw||typeof runsRaw!=`object`)return new Map;let out=new Map,isLegacy=record.version===1,migrated=!1;for(let[runId,entry]of Object.entries(runsRaw)){if(!entry||typeof entry!=`object`)continue;let typed=entry;if(!typed.runId||typeof typed.runId!=`string`)continue;let legacyCompletedAt=isLegacy&&typeof typed.announceCompletedAt==`number`?typed.announceCompletedAt:void 0,cleanupCompletedAt=typeof typed.cleanupCompletedAt==`number`?typed.cleanupCompletedAt:legacyCompletedAt,cleanupHandled=typeof typed.cleanupHandled==`boolean`?typed.cleanupHandled:isLegacy?!!(typed.announceHandled??cleanupCompletedAt):void 0,requesterOrigin=normalizeDeliveryContext(typed.requesterOrigin??{channel:typeof typed.requesterChannel==`string`?typed.requesterChannel:void 0,accountId:typeof typed.requesterAccountId==`string`?typed.requesterAccountId:void 0}),{announceCompletedAt:_announceCompletedAt,announceHandled:_announceHandled,requesterChannel:_channel,requesterAccountId:_accountId,...rest}=typed;out.set(runId,{...rest,requesterOrigin,cleanupCompletedAt,cleanupHandled}),isLegacy&&(migrated=!0)}if(migrated)try{await saveSubagentRegistryToDisk(out)}catch{}return out}async function saveSubagentRegistryToDisk(runs){let pathname=resolveSubagentRegistryPath(),serialized={};for(let[runId,entry]of runs.entries())serialized[runId]=entry;await saveJsonFile(pathname,{version:2,runs:serialized})}const subagentRuns=new Map;let sweeper$1=null,listenerStarted=!1;var restoreAttempted=!1;const ANNOUNCE_EXPIRY_MS=5*6e4;function resolveAnnounceRetryDelayMs(retryCount){let boundedRetryCount=Math.max(0,Math.min(retryCount,10)),baseDelay=1e3*2**Math.max(0,boundedRetryCount-1);return Math.min(baseDelay,8e3)}function logAnnounceGiveUp(entry,reason){let retryCount=entry.announceRetryCount??0,endedAgoMs=typeof entry.endedAt==`number`?Math.max(0,Date.now()-entry.endedAt):void 0,endedAgoLabel=endedAgoMs==null?`n/a`:`${Math.round(endedAgoMs/1e3)}s`;defaultRuntime.log(`[warn] Subagent announce give up (${reason}) run=${entry.runId} child=${entry.childSessionKey} requester=${entry.requesterSessionKey} retries=${retryCount} endedAgo=${endedAgoLabel}`)}let persistChain=Promise.resolve();function persistSubagentRuns(){return persistChain=persistChain.then(()=>saveSubagentRegistryToDisk(subagentRuns)).catch(err=>{logWarn(`subagent registry persist failed: ${String(err)}`)}),persistChain}const resumedRuns=new Set;function suppressAnnounceForSteerRestart(entry){return entry?.suppressAnnounceReason===`steer-restart`}function startSubagentAnnounceCleanupFlow(runId,entry){if(!beginSubagentCleanup(runId))return!1;let requesterOrigin=normalizeDeliveryContext(entry.requesterOrigin);return runSubagentAnnounceFlow({childSessionKey:entry.childSessionKey,childRunId:entry.runId,requesterSessionKey:entry.requesterSessionKey,requesterOrigin,requesterDisplayKey:entry.requesterDisplayKey,task:entry.task,expectsCompletionMessage:entry.expectsCompletionMessage,timeoutMs:12e4,cleanup:entry.cleanup,waitForCompletion:!1,startedAt:entry.startedAt,endedAt:entry.endedAt,label:entry.label,outcome:entry.outcome}).then(didAnnounce=>{finalizeSubagentCleanup(runId,entry.cleanup,didAnnounce)}),!0}function resumeSubagentRun(runId){if(!runId||resumedRuns.has(runId))return;let entry=subagentRuns.get(runId);if(!entry||entry.cleanupCompletedAt)return;if((entry.announceRetryCount??0)>=3){logAnnounceGiveUp(entry,`retry-limit`),entry.cleanupCompletedAt=Date.now(),persistSubagentRuns();return}if(typeof entry.endedAt==`number`&&Date.now()-entry.endedAt>ANNOUNCE_EXPIRY_MS){logAnnounceGiveUp(entry,`expiry`),entry.cleanupCompletedAt=Date.now(),persistSubagentRuns();return}let now=Date.now(),delayMs=resolveAnnounceRetryDelayMs(entry.announceRetryCount??0),earliestRetryAt=(entry.lastAnnounceRetryAt??0)+delayMs;if(entry.expectsCompletionMessage===!0&&entry.lastAnnounceRetryAt&&now<earliestRetryAt){let waitMs=Math.max(1,earliestRetryAt-now);setTimeout(()=>{resumeSubagentRun(runId)},waitMs).unref?.(),resumedRuns.add(runId);return}if(typeof entry.endedAt==`number`&&entry.endedAt>0){if(suppressAnnounceForSteerRestart(entry)){resumedRuns.add(runId);return}if(!startSubagentAnnounceCleanupFlow(runId,entry))return;resumedRuns.add(runId);return}waitForSubagentCompletion(runId,resolveSubagentWaitTimeoutMs(loadConfig(),entry.runTimeoutSeconds)),resumedRuns.add(runId)}async function restoreSubagentRunsOnce(){if(!restoreAttempted){restoreAttempted=!0;try{let restored=await loadSubagentRegistryFromDisk();if(restored.size===0)return;for(let[runId,entry]of restored.entries())!runId||!entry||subagentRuns.has(runId)||subagentRuns.set(runId,entry);ensureListener(),[...subagentRuns.values()].some(entry=>entry.archiveAtMs)&&startSweeper$1();for(let runId of subagentRuns.keys())resumeSubagentRun(runId)}catch(err){let message=`failed to restore subagent runs: ${String(err)}`;defaultRuntime.error(message)}}}function resolveArchiveAfterMs(cfg){let minutes=(cfg??loadConfig()).agents?.defaults?.subagents?.archiveAfterMinutes??60;if(!(!Number.isFinite(minutes)||minutes<=0))return Math.max(1,Math.floor(minutes))*6e4}function resolveSubagentWaitTimeoutMs(cfg,runTimeoutSeconds){return resolveAgentTimeoutMs({cfg,overrideSeconds:runTimeoutSeconds??0})}function startSweeper$1(){sweeper$1||(sweeper$1=setInterval(()=>{sweepSubagentRuns()},6e4),sweeper$1.unref?.())}function stopSweeper$1(){sweeper$1&&=(clearInterval(sweeper$1),null)}async function sweepSubagentRuns(){let now=Date.now(),mutated=!1;for(let[runId,entry]of subagentRuns.entries())if(!(!entry.archiveAtMs||entry.archiveAtMs>now)){subagentRuns.delete(runId),mutated=!0;try{await callGateway({method:`sessions.delete`,params:{key:entry.childSessionKey,deleteTranscript:!0},timeoutMs:1e4})}catch{}}mutated&&await persistSubagentRuns(),subagentRuns.size===0&&stopSweeper$1()}function ensureListener(){listenerStarted||(listenerStarted=!0,onAgentEvent(evt=>{if(!evt||evt.stream!==`lifecycle`)return;let entry=subagentRuns.get(evt.runId);if(!entry)return;let phase=evt.data?.phase;if(phase===`start`){let startedAt=typeof evt.data?.startedAt==`number`?evt.data.startedAt:void 0;startedAt&&(entry.startedAt=startedAt,persistSubagentRuns());return}phase!==`end`&&phase!==`error`||(entry.endedAt=typeof evt.data?.endedAt==`number`?evt.data.endedAt:Date.now(),phase===`error`?entry.outcome={status:`error`,error:typeof evt.data?.error==`string`?evt.data.error:void 0}:evt.data?.aborted?entry.outcome={status:`timeout`}:entry.outcome={status:`ok`},persistSubagentRuns(),!suppressAnnounceForSteerRestart(entry)&&startSubagentAnnounceCleanupFlow(evt.runId,entry))}))}function finalizeSubagentCleanup(runId,cleanup,didAnnounce){let entry=subagentRuns.get(runId);if(entry){if(!didAnnounce){let now=Date.now(),retryCount=(entry.announceRetryCount??0)+1;entry.announceRetryCount=retryCount,entry.lastAnnounceRetryAt=now;let endedAgo=typeof entry.endedAt==`number`?now-entry.endedAt:0;if(retryCount>=3||endedAgo>ANNOUNCE_EXPIRY_MS){logAnnounceGiveUp(entry,retryCount>=3?`retry-limit`:`expiry`),entry.cleanupCompletedAt=now,persistSubagentRuns(),retryDeferredCompletedAnnounces(runId);return}if(entry.cleanupHandled=!1,resumedRuns.delete(runId),persistSubagentRuns(),entry.expectsCompletionMessage!==!0)return;setTimeout(()=>{resumeSubagentRun(runId)},resolveAnnounceRetryDelayMs(entry.announceRetryCount??0)).unref?.();return}if(cleanup===`delete`){subagentRuns.delete(runId),persistSubagentRuns(),retryDeferredCompletedAnnounces(runId);return}entry.cleanupCompletedAt=Date.now(),persistSubagentRuns(),retryDeferredCompletedAnnounces(runId)}}function retryDeferredCompletedAnnounces(excludeRunId){let now=Date.now();for(let[runId,entry]of subagentRuns.entries())if(!(excludeRunId&&runId===excludeRunId)&&typeof entry.endedAt==`number`&&!(entry.cleanupCompletedAt||entry.cleanupHandled)&&!suppressAnnounceForSteerRestart(entry)){if(now-(entry.endedAt??now)>ANNOUNCE_EXPIRY_MS){logAnnounceGiveUp(entry,`expiry`),entry.cleanupCompletedAt=now,persistSubagentRuns();continue}resumedRuns.delete(runId),resumeSubagentRun(runId)}}function beginSubagentCleanup(runId){let entry=subagentRuns.get(runId);return!entry||entry.cleanupCompletedAt||entry.cleanupHandled?!1:(entry.cleanupHandled=!0,persistSubagentRuns(),!0)}function markSubagentRunForSteerRestart(runId){let key=runId.trim();if(!key)return!1;let entry=subagentRuns.get(key);return entry?entry.suppressAnnounceReason===`steer-restart`?!0:(entry.suppressAnnounceReason=`steer-restart`,persistSubagentRuns(),!0):!1}function clearSubagentRunSteerRestart(runId){let key=runId.trim();if(!key)return!1;let entry=subagentRuns.get(key);return entry?entry.suppressAnnounceReason===`steer-restart`?(entry.suppressAnnounceReason=void 0,persistSubagentRuns(),resumedRuns.delete(key),typeof entry.endedAt==`number`&&!entry.cleanupCompletedAt&&resumeSubagentRun(key),!0):!0:!1}function replaceSubagentRunAfterSteer(params){let previousRunId=params.previousRunId.trim(),nextRunId=params.nextRunId.trim();if(!previousRunId||!nextRunId)return!1;let source=subagentRuns.get(previousRunId)??params.fallback;if(!source)return!1;previousRunId!==nextRunId&&(subagentRuns.delete(previousRunId),resumedRuns.delete(previousRunId));let now=Date.now(),cfg=loadConfig(),archiveAfterMs=resolveArchiveAfterMs(cfg),archiveAtMs=archiveAfterMs?now+archiveAfterMs:void 0,runTimeoutSeconds=params.runTimeoutSeconds??source.runTimeoutSeconds??0,waitTimeoutMs=resolveSubagentWaitTimeoutMs(cfg,runTimeoutSeconds),next={...source,runId:nextRunId,startedAt:now,endedAt:void 0,outcome:void 0,cleanupCompletedAt:void 0,cleanupHandled:!1,suppressAnnounceReason:void 0,announceRetryCount:void 0,lastAnnounceRetryAt:void 0,archiveAtMs,runTimeoutSeconds};return subagentRuns.set(nextRunId,next),ensureListener(),persistSubagentRuns(),archiveAfterMs&&startSweeper$1(),waitForSubagentCompletion(nextRunId,waitTimeoutMs),!0}function registerSubagentRun(params){let now=Date.now(),cfg=loadConfig(),archiveAfterMs=resolveArchiveAfterMs(cfg),archiveAtMs=archiveAfterMs?now+archiveAfterMs:void 0,runTimeoutSeconds=params.runTimeoutSeconds??0,waitTimeoutMs=resolveSubagentWaitTimeoutMs(cfg,runTimeoutSeconds),requesterOrigin=normalizeDeliveryContext(params.requesterOrigin);subagentRuns.set(params.runId,{runId:params.runId,childSessionKey:params.childSessionKey,requesterSessionKey:params.requesterSessionKey,requesterOrigin,requesterDisplayKey:params.requesterDisplayKey,task:params.task,cleanup:params.cleanup,expectsCompletionMessage:params.expectsCompletionMessage,label:params.label,model:params.model,runTimeoutSeconds,createdAt:now,startedAt:now,archiveAtMs,cleanupHandled:!1}),ensureListener(),persistSubagentRuns(),archiveAfterMs&&startSweeper$1(),waitForSubagentCompletion(params.runId,waitTimeoutMs)}async function waitForSubagentCompletion(runId,waitTimeoutMs){try{let timeoutMs=Math.max(1,Math.floor(waitTimeoutMs)),wait=await callGateway({method:`agent.wait`,params:{runId,timeoutMs},timeoutMs:timeoutMs+1e4});if(wait?.status!==`ok`&&wait?.status!==`error`&&wait?.status!==`timeout`)return;let entry=subagentRuns.get(runId);if(!entry)return;let mutated=!1;typeof wait.startedAt==`number`&&(entry.startedAt=wait.startedAt,mutated=!0),typeof wait.endedAt==`number`&&(entry.endedAt=wait.endedAt,mutated=!0),entry.endedAt||(entry.endedAt=Date.now(),mutated=!0);let waitError=typeof wait.error==`string`?wait.error:void 0;if(entry.outcome=wait.status===`error`?{status:`error`,error:waitError}:wait.status===`timeout`?{status:`timeout`}:{status:`ok`},mutated=!0,mutated&&persistSubagentRuns(),suppressAnnounceForSteerRestart(entry)||!startSubagentAnnounceCleanupFlow(runId,entry))return}catch(err){let message=`failed to wait for subagent completion: ${String(err)}`;defaultRuntime.error(message)}}async function findRunIdsByChildSessionKey(childSessionKey){let key=childSessionKey.trim();if(!key)return[];let runIds=[],snapshot=await getRunsSnapshotForRead();for(let entry of snapshot.values())entry.childSessionKey===key&&runIds.push(entry.runId);return runIds}async function getRunsSnapshotForRead(){let merged=new Map;if(!process.env.VITEST)try{let restored=await loadSubagentRegistryFromDisk();for(let[runId,entry]of restored.entries())merged.set(runId,entry)}catch(err){let message=`failed to load subagent registry from disk: ${String(err)}`;defaultRuntime.error(message)}for(let[runId,entry]of subagentRuns.entries())merged.set(runId,entry);return merged}async function resolveRequesterForChildSession(childSessionKey){let key=childSessionKey.trim();if(!key)return null;let best;for(let entry of(await getRunsSnapshotForRead()).values())entry.childSessionKey===key&&(!best||entry.createdAt>best.createdAt)&&(best=entry);return best?{requesterSessionKey:best.requesterSessionKey,requesterOrigin:normalizeDeliveryContext(best.requesterOrigin)}:null}async function isSubagentSessionRunActive(childSessionKey){let runIds=await findRunIdsByChildSessionKey(childSessionKey);for(let runId of runIds){let entry=subagentRuns.get(runId);if(entry&&typeof entry.endedAt!=`number`)return!0}return!1}async function markSubagentRunTerminated(params){let runIds=new Set;if(typeof params.runId==`string`&&params.runId.trim()&&runIds.add(params.runId.trim()),typeof params.childSessionKey==`string`&&params.childSessionKey.trim())for(let runId of await findRunIdsByChildSessionKey(params.childSessionKey))runIds.add(runId);if(runIds.size===0)return 0;let now=Date.now(),reason=params.reason?.trim()||`killed`,updated=0;for(let runId of runIds){let entry=subagentRuns.get(runId);entry&&typeof entry.endedAt!=`number`&&(entry.endedAt=now,entry.outcome={status:`error`,error:reason},entry.cleanupHandled=!0,entry.cleanupCompletedAt=now,entry.suppressAnnounceReason=`killed`,updated+=1)}return updated>0&&persistSubagentRuns(),updated}function listSubagentRunsForRequester(requesterSessionKey){let key=requesterSessionKey.trim();return key?[...subagentRuns.values()].filter(entry=>entry.requesterSessionKey===key):[]}async function countActiveRunsForSession(requesterSessionKey){let key=requesterSessionKey.trim();if(!key)return 0;let count=0;for(let entry of(await getRunsSnapshotForRead()).values())entry.requesterSessionKey===key&&typeof entry.endedAt!=`number`&&(count+=1);return count}async function countActiveDescendantRuns(rootSessionKey){let root=rootSessionKey.trim();if(!root)return 0;let runs=await getRunsSnapshotForRead(),pending=[root],visited=new Set([root]),count=0;for(;pending.length>0;){let requester=pending.shift();if(requester)for(let entry of runs.values()){if(entry.requesterSessionKey!==requester)continue;typeof entry.endedAt!=`number`&&(count+=1);let childKey=entry.childSessionKey.trim();!childKey||visited.has(childKey)||(visited.add(childKey),pending.push(childKey))}}return count}async function listDescendantRunsForRequester(rootSessionKey){let root=rootSessionKey.trim();if(!root)return[];let runs=await getRunsSnapshotForRead(),pending=[root],visited=new Set([root]),descendants=[];for(;pending.length>0;){let requester=pending.shift();if(requester)for(let entry of runs.values()){if(entry.requesterSessionKey!==requester)continue;descendants.push(entry);let childKey=entry.childSessionKey.trim();!childKey||visited.has(childKey)||(visited.add(childKey),pending.push(childKey))}}return descendants}function initSubagentRegistry(){return restoreSubagentRunsOnce()}function deriveMentionPatterns(identity){let patterns=[],name=identity?.name?.trim();if(name){let parts=name.split(/\s+/).filter(Boolean).map(escapeRegExp),re=parts.length?parts.join(String.raw`\s+`):escapeRegExp(name);patterns.push(String.raw`\b@?${re}\b`)}let emoji=identity?.emoji?.trim();return emoji&&patterns.push(escapeRegExp(emoji)),patterns}const CURRENT_MESSAGE_MARKER=`[Current message - respond to this]`;function normalizeMentionPattern(pattern){return pattern.includes(`\b`)?pattern.split(`\b`).join(`\\b`):pattern}function normalizeMentionPatterns(patterns){return patterns.map(normalizeMentionPattern)}function resolveMentionPatterns(cfg,agentId){if(!cfg)return[];let agentConfig=agentId?resolveAgentConfig(cfg,agentId):void 0,agentGroupChat=agentConfig?.groupChat;if(agentGroupChat&&Object.hasOwn(agentGroupChat,`mentionPatterns`))return agentGroupChat.mentionPatterns??[];let globalGroupChat=cfg.messages?.groupChat;if(globalGroupChat&&Object.hasOwn(globalGroupChat,`mentionPatterns`))return globalGroupChat.mentionPatterns??[];let derived=deriveMentionPatterns(agentConfig?.identity);return derived.length>0?derived:[]}function buildMentionRegexes(cfg,agentId){return normalizeMentionPatterns(resolveMentionPatterns(cfg,agentId)).map(pattern=>{try{return new RegExp(pattern,`i`)}catch{return null}}).filter(value=>!!value)}function normalizeMentionText(text){return(text??``).replace(/[\u200b-\u200f\u202a-\u202e\u2060-\u206f]/g,``).toLowerCase().replace(/\bopenagentNode\b/g,`builderforce`)}function matchesMentionPatterns(text,mentionRegexes){if(mentionRegexes.length===0)return!1;let cleaned=normalizeMentionText(text??``);return cleaned?mentionRegexes.some(re=>re.test(cleaned)):!1}function matchesMentionWithExplicit(params){let cleaned=normalizeMentionText(params.text??``),explicit=params.explicit?.isExplicitlyMentioned===!0,explicitAvailable=params.explicit?.canResolveExplicit===!0,hasAnyMention=params.explicit?.hasAnyMention===!0,transcriptCleaned=params.transcript?normalizeMentionText(params.transcript):``,textToCheck=cleaned||transcriptCleaned;return hasAnyMention&&explicitAvailable||textToCheck?explicit||params.mentionRegexes.some(re=>re.test(textToCheck)):explicit}function stripStructuralPrefixes(text){return(text.includes(CURRENT_MESSAGE_MARKER)?text.slice(text.indexOf(CURRENT_MESSAGE_MARKER)+35).trimStart():text).replace(/\[[^\]]+\]\s*/g,``).replace(/^[ \t]*[A-Za-z0-9+()\-_. ]+:\s*/gm,``).replace(/\\n/g,` `).replace(/\s+/g,` `).trim()}function stripMentions(text,ctx,cfg,agentId){let result=text,providerId=ctx.Provider?normalizeChannelId$1(ctx.Provider):null,providerMentions=providerId?getChannelDock(providerId)?.mentions:void 0,patterns=normalizeMentionPatterns([...resolveMentionPatterns(cfg,agentId),...providerMentions?.stripPatterns?.({ctx,cfg,agentId})??[]]);for(let p of patterns)try{let re=new RegExp(p,`gi`);result=result.replace(re,` `)}catch{}return providerMentions?.stripMentions&&(result=providerMentions.stripMentions({text:result,ctx,cfg,agentId})),result=result.replace(/@[0-9+]{5,}/g,` `),result.replace(/\s+/g,` `).trim()}const ABORT_TRIGGERS=new Set([`stop`,`esc`,`abort`,`wait`,`exit`,`interrupt`]),ABORT_MEMORY=new Map,ABORT_MEMORY_MAX=2e3;function isAbortTrigger(text){if(!text)return!1;let normalized=text.trim().toLowerCase();return ABORT_TRIGGERS.has(normalized)}function isAbortRequestText(text,options){if(!text)return!1;let normalized=normalizeCommandBody(text,options).trim();return normalized?normalized.toLowerCase()===`/stop`||isAbortTrigger(normalized):!1}function getAbortMemory(key){let normalized=key.trim();if(normalized)return ABORT_MEMORY.get(normalized)}function pruneAbortMemory(){if(ABORT_MEMORY.size<=ABORT_MEMORY_MAX)return;let excess=ABORT_MEMORY.size-ABORT_MEMORY_MAX,removed=0;for(let entryKey of ABORT_MEMORY.keys())if(ABORT_MEMORY.delete(entryKey),removed+=1,removed>=excess)break}function setAbortMemory(key,value){let normalized=key.trim();if(normalized){if(!value){ABORT_MEMORY.delete(normalized);return}ABORT_MEMORY.has(normalized)&&ABORT_MEMORY.delete(normalized),ABORT_MEMORY.set(normalized,!0),pruneAbortMemory()}}function formatAbortReplyText(stoppedSubagents){return typeof stoppedSubagents!=`number`||stoppedSubagents<=0?`⚙️ Agent was aborted.`:`⚙️ Agent was aborted. Stopped ${stoppedSubagents} ${stoppedSubagents===1?`sub-agent`:`sub-agents`}.`}function resolveSessionEntryForKey$1(store,sessionKey){if(!store||!sessionKey)return{};let direct=store[sessionKey];return direct?{entry:direct,key:sessionKey}:{}}function resolveAbortTargetKey(ctx){return ctx.CommandTargetSessionKey?.trim()||ctx.SessionKey?.trim()||void 0}function normalizeRequesterSessionKey(cfg,key){let cleaned=key?.trim();if(!cleaned)return;let{mainKey,alias}=resolveMainSessionAlias(cfg);return resolveInternalSessionKey({key:cleaned,alias,mainKey})}async function stopSubagentsForRequester(params){let requesterKey=normalizeRequesterSessionKey(params.cfg,params.requesterSessionKey);if(!requesterKey)return{stopped:0};let runs=listSubagentRunsForRequester(requesterKey);if(runs.length===0)return{stopped:0};let storeCache=new Map,seenChildKeys=new Set,stopped=0;for(let run of runs){let childKey=run.childSessionKey?.trim();if(!childKey||seenChildKeys.has(childKey))continue;if(seenChildKeys.add(childKey),!run.endedAt){let cleared=clearSessionQueues([childKey]),parsed=parseAgentSessionKey(childKey),storePath=resolveStorePath(params.cfg.session?.store,{agentId:parsed?.agentId}),store=storeCache.get(storePath);store||(store=loadSessionStore(storePath),storeCache.set(storePath,store));let sessionId=store[childKey]?.sessionId,aborted=sessionId?abortEmbeddedRun(sessionId):!1;(await markSubagentRunTerminated({runId:run.runId,childSessionKey:childKey,reason:`killed`})>0||aborted||cleared.followupCleared>0||cleared.laneCleared>0)&&(stopped+=1)}let cascadeResult=await stopSubagentsForRequester({cfg:params.cfg,requesterSessionKey:childKey});stopped+=cascadeResult.stopped}return stopped>0&&logVerbose(`abort: stopped ${stopped} subagent run(s) for ${requesterKey}`),{stopped}}async function tryFastAbortFromMessage(params){let{ctx,cfg}=params,targetKey=resolveAbortTargetKey(ctx),agentId=resolveSessionAgentId({sessionKey:targetKey??ctx.SessionKey??``,config:cfg}),raw=stripStructuralPrefixes(ctx.CommandBody??ctx.RawBody??ctx.Body??``);if(!isAbortRequestText(ctx.ChatType?.trim().toLowerCase()===`group`?stripMentions(raw,ctx,cfg,agentId):raw))return{handled:!1,aborted:!1};let commandAuthorized=ctx.CommandAuthorized,auth=resolveCommandAuthorization({ctx,cfg,commandAuthorized});if(!auth.isAuthorizedSender)return{handled:!1,aborted:!1};let abortKey=targetKey??auth.from??auth.to,requesterSessionKey=targetKey??ctx.SessionKey??abortKey;if(targetKey){let storePath=resolveStorePath(cfg.session?.store,{agentId}),store=loadSessionStore(storePath),{entry,key}=resolveSessionEntryForKey$1(store,targetKey),sessionId=entry?.sessionId,aborted=sessionId?abortEmbeddedRun(sessionId):!1,cleared=clearSessionQueues([key??targetKey,sessionId]);(cleared.followupCleared>0||cleared.laneCleared>0)&&logVerbose(`abort: cleared followups=${cleared.followupCleared} lane=${cleared.laneCleared} keys=${cleared.keys.join(`,`)}`),entry&&key?(entry.abortedLastRun=!0,entry.updatedAt=Date.now(),store[key]=entry,await updateSessionStore(storePath,nextStore=>{let nextEntry=nextStore[key]??entry;nextEntry&&(nextEntry.abortedLastRun=!0,nextEntry.updatedAt=Date.now(),nextStore[key]=nextEntry)})):abortKey&&setAbortMemory(abortKey,!0);let{stopped}=await stopSubagentsForRequester({cfg,requesterSessionKey});return{handled:!0,aborted,stoppedSubagents:stopped}}abortKey&&setAbortMemory(abortKey,!0);let{stopped}=await stopSubagentsForRequester({cfg,requesterSessionKey});return{handled:!0,aborted:!1,stoppedSubagents:stopped}}function hasControlCommand(text,cfg,options){if(!text)return!1;let trimmed=text.trim();if(!trimmed)return!1;let normalizedBody=normalizeCommandBody(trimmed,options);if(!normalizedBody)return!1;let lowered=normalizedBody.toLowerCase(),commands=cfg?listChatCommandsForConfig(cfg):listChatCommands();for(let command of commands)for(let alias of command.textAliases){let normalized=alias.trim().toLowerCase();if(normalized){if(lowered===normalized)return!0;if(command.acceptsArgs&&lowered.startsWith(normalized)){let nextChar=normalizedBody.charAt(normalized.length);if(nextChar&&/\s/.test(nextChar))return!0}}}return!1}function isControlCommandMessage(text,cfg,options){if(!text)return!1;let trimmed=text.trim();return trimmed?hasControlCommand(trimmed,cfg,options)?!0:isAbortTrigger(normalizeCommandBody(trimmed,options).trim().toLowerCase()):!1}function hasInlineCommandTokens(text){let body=text??``;return body.trim()?/(?:^|\s)[/!][a-z]/i.test(body):!1}function shouldComputeCommandAuthorized(text,cfg,options){return isControlCommandMessage(text,cfg,options)||hasInlineCommandTokens(text)}function normalize(value){return value?.trim()||void 0}function resolveSenderLabel(params){let name=normalize(params.name),username=normalize(params.username),tag=normalize(params.tag),e164=normalize(params.e164),id=normalize(params.id),display=name??username??tag??``,idPart=e164??id??``;return display&&idPart&&display!==idPart?`${display} (${idPart})`:display||idPart||null}function resolveTimezone(value){try{return new Intl.DateTimeFormat(`en-US`,{timeZone:value}).format(new Date),value}catch{return}}function formatUtcTimestamp(date,options){let yyyy=String(date.getUTCFullYear()).padStart(4,`0`),mm=String(date.getUTCMonth()+1).padStart(2,`0`),dd=String(date.getUTCDate()).padStart(2,`0`),hh=String(date.getUTCHours()).padStart(2,`0`),min=String(date.getUTCMinutes()).padStart(2,`0`);return options?.displaySeconds?`${yyyy}-${mm}-${dd}T${hh}:${min}:${String(date.getUTCSeconds()).padStart(2,`0`)}Z`:`${yyyy}-${mm}-${dd}T${hh}:${min}Z`}function formatZonedTimestamp(date,options){let intlOptions={timeZone:options?.timeZone,year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,hourCycle:`h23`,timeZoneName:`short`};options?.displaySeconds&&(intlOptions.second=`2-digit`);let parts=new Intl.DateTimeFormat(`en-US`,intlOptions).formatToParts(date),pick=type=>parts.find(part=>part.type===type)?.value,yyyy=pick(`year`),mm=pick(`month`),dd=pick(`day`),hh=pick(`hour`),min=pick(`minute`),sec=options?.displaySeconds?pick(`second`):void 0,tz=[...parts].toReversed().find(part=>part.type===`timeZoneName`)?.value?.trim();if(!(!yyyy||!mm||!dd||!hh||!min))return options?.displaySeconds&&sec?`${yyyy}-${mm}-${dd} ${hh}:${min}:${sec}${tz?` ${tz}`:``}`:`${yyyy}-${mm}-${dd} ${hh}:${min}${tz?` ${tz}`:``}`}function sanitizeEnvelopeHeaderPart(value){return value.replace(/\r\n|\r|\n/g,` `).replaceAll(`[`,`(`).replaceAll(`]`,`)`).replace(/\s+/g,` `).trim()}function resolveEnvelopeFormatOptions(cfg){let defaults=cfg?.agents?.defaults;return{timezone:defaults?.envelopeTimezone,includeTimestamp:defaults?.envelopeTimestamp!==`off`,includeElapsed:defaults?.envelopeElapsed!==`off`,userTimezone:defaults?.userTimezone}}function normalizeEnvelopeOptions(options){let includeTimestamp=options?.includeTimestamp!==!1,includeElapsed=options?.includeElapsed!==!1;return{timezone:options?.timezone?.trim()||`local`,includeTimestamp,includeElapsed,userTimezone:options?.userTimezone}}function resolveEnvelopeTimezone(options){let trimmed=options.timezone?.trim();if(!trimmed)return{mode:`local`};let lowered=trimmed.toLowerCase();if(lowered===`utc`||lowered===`gmt`)return{mode:`utc`};if(lowered===`local`||lowered===`host`)return{mode:`local`};if(lowered===`user`)return{mode:`iana`,timeZone:resolveUserTimezone(options.userTimezone)};let explicit=resolveTimezone(trimmed);return explicit?{mode:`iana`,timeZone:explicit}:{mode:`utc`}}function formatTimestamp$1(ts,options){if(!ts)return;let resolved=normalizeEnvelopeOptions(options);if(!resolved.includeTimestamp)return;let date=ts instanceof Date?ts:new Date(ts);if(Number.isNaN(date.getTime()))return;let zone=resolveEnvelopeTimezone(resolved),weekday=(()=>{try{return zone.mode===`utc`?new Intl.DateTimeFormat(`en-US`,{timeZone:`UTC`,weekday:`short`}).format(date):zone.mode===`local`?new Intl.DateTimeFormat(`en-US`,{weekday:`short`}).format(date):new Intl.DateTimeFormat(`en-US`,{timeZone:zone.timeZone,weekday:`short`}).format(date)}catch{return}})(),formatted=zone.mode===`utc`?formatUtcTimestamp(date):zone.mode===`local`?formatZonedTimestamp(date):formatZonedTimestamp(date,{timeZone:zone.timeZone});if(formatted)return weekday?`${weekday} ${formatted}`:formatted}function formatAgentEnvelope(params){let parts=[sanitizeEnvelopeHeaderPart(params.channel?.trim()||`Channel`)],resolved=normalizeEnvelopeOptions(params.envelope),elapsed;if(resolved.includeElapsed&&params.timestamp&&params.previousTimestamp){let elapsedMs=(params.timestamp instanceof Date?params.timestamp.getTime():params.timestamp)-(params.previousTimestamp instanceof Date?params.previousTimestamp.getTime():params.previousTimestamp);elapsed=Number.isFinite(elapsedMs)&&elapsedMs>=0?formatTimeAgo(elapsedMs,{suffix:!1}):void 0}if(params.from?.trim()){let from=sanitizeEnvelopeHeaderPart(params.from.trim());parts.push(elapsed?`${from} +${elapsed}`:from)}else elapsed&&parts.push(`+${elapsed}`);params.host?.trim()&&parts.push(sanitizeEnvelopeHeaderPart(params.host.trim())),params.ip?.trim()&&parts.push(sanitizeEnvelopeHeaderPart(params.ip.trim()));let ts=formatTimestamp$1(params.timestamp,resolved);return ts&&parts.push(ts),`${`[${parts.join(` `)}]`} ${params.body}`}function formatInboundEnvelope(params){let chatType=normalizeChatType(params.chatType),isDirect=!chatType||chatType===`direct`,resolvedSenderRaw=params.senderLabel?.trim()||resolveSenderLabel(params.sender??{}),resolvedSender=resolvedSenderRaw?sanitizeEnvelopeHeaderPart(resolvedSenderRaw):``,body=!isDirect&&resolvedSender?`${resolvedSender}: ${params.body}`:params.body;return formatAgentEnvelope({channel:params.channel,from:params.from,timestamp:params.timestamp,previousTimestamp:params.previousTimestamp,envelope:params.envelope,body})}function formatInboundFromLabel(params){if(params.isGroup){let label=params.groupLabel?.trim()||params.groupFallback||`Group`,id=params.groupId?.trim();return id?`${label} id:${id}`:label}let directLabel=params.directLabel.trim(),directId=params.directId?.trim();return!directId||directId===directLabel?directLabel:`${directLabel} id:${directId}`}const resolveMs=value=>{if(!(typeof value!=`number`||!Number.isFinite(value)))return Math.max(0,Math.trunc(value))},resolveChannelOverride=params=>{if(params.byChannel)return resolveMs(params.byChannel[params.channel])};function resolveInboundDebounceMs(params){let inbound=params.cfg.messages?.inbound,override=resolveMs(params.overrideMs),byChannel=resolveChannelOverride({byChannel:inbound?.byChannel,channel:params.channel}),base=resolveMs(inbound?.debounceMs);return override??byChannel??base??0}function createInboundDebouncer(params){let buffers=new Map,debounceMs=Math.max(0,Math.trunc(params.debounceMs)),flushBuffer=async(key,buffer)=>{if(buffers.delete(key),buffer.timeout&&=(clearTimeout(buffer.timeout),null),buffer.items.length!==0)try{await params.onFlush(buffer.items)}catch(err){params.onError?.(err,buffer.items)}},flushKey=async key=>{let buffer=buffers.get(key);buffer&&await flushBuffer(key,buffer)},scheduleFlush=(key,buffer)=>{buffer.timeout&&clearTimeout(buffer.timeout),buffer.timeout=setTimeout(()=>{flushBuffer(key,buffer)},debounceMs),buffer.timeout.unref?.()};return{enqueue:async item=>{let key=params.buildKey(item);if(!(debounceMs>0&&(params.shouldDebounce?.(item)??!0))||!key){key&&buffers.has(key)&&await flushKey(key),await params.onFlush([item]);return}let existing=buffers.get(key);if(existing){existing.items.push(item),scheduleFlush(key,existing);return}let buffer={items:[item],timeout:null};buffers.set(key,buffer),scheduleFlush(key,buffer)},flushKey}}function pruneMapToMaxSize(map,maxSize){let limit=Math.max(0,Math.floor(maxSize));if(limit<=0){map.clear();return}for(;map.size>limit;){let oldest=map.keys().next();if(oldest.done)break;map.delete(oldest.value)}}function createDedupeCache(options){let ttlMs=Math.max(0,options.ttlMs),maxSize=Math.max(0,Math.floor(options.maxSize)),cache=new Map,touch=(key,now)=>{cache.delete(key),cache.set(key,now)},prune=now=>{let cutoff=ttlMs>0?now-ttlMs:void 0;if(cutoff!==void 0)for(let[entryKey,entryTs]of cache)entryTs<cutoff&&cache.delete(entryKey);if(maxSize<=0){cache.clear();return}pruneMapToMaxSize(cache,maxSize)};return{check:(key,now=Date.now())=>{if(!key)return!1;let existing=cache.get(key);return existing!==void 0&&(ttlMs<=0||now-existing<ttlMs)?(touch(key,now),!0):(touch(key,now),prune(now),!1)},clear:()=>{cache.clear()},size:()=>cache.size}}const inboundDedupeCache=createDedupeCache({ttlMs:20*6e4,maxSize:5e3}),normalizeProvider=value=>value?.trim().toLowerCase()||``,resolveInboundPeerId=ctx=>ctx.OriginatingTo??ctx.To??ctx.From??ctx.SessionKey;function buildInboundDedupeKey(ctx){let provider=normalizeProvider(ctx.OriginatingChannel??ctx.Provider??ctx.Surface),messageId=ctx.MessageSid?.trim();if(!provider||!messageId)return null;let peerId=resolveInboundPeerId(ctx);if(!peerId)return null;let sessionKey=ctx.SessionKey?.trim()??``;return[provider,ctx.AccountId?.trim()??``,sessionKey,peerId,ctx.MessageThreadId!==void 0&&ctx.MessageThreadId!==null?String(ctx.MessageThreadId):``,messageId].filter(Boolean).join(`|`)}function shouldSkipDuplicateInbound(ctx,opts){let key=buildInboundDedupeKey(ctx);if(!key)return!1;let skipped=(opts?.cache??inboundDedupeCache).check(key,opts?.now);return skipped&&shouldLogVerbose()&&logVerbose(`inbound dedupe: skipped ${key}`),skipped}function parseLineDirectives(payload){let text=payload.text;if(!text)return payload;let result={...payload},lineData={...result.channelData?.line},toSlug=value=>value.toLowerCase().replace(/[^a-z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`device`,lineActionData=(action,extras)=>{let base=[`line.action=${encodeURIComponent(action)}`];if(extras)for(let[key,value]of Object.entries(extras))base.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);return base.join(`&`)},quickRepliesMatch=text.match(/\[\[quick_replies:\s*([^\]]+)\]\]/i);if(quickRepliesMatch){let options=quickRepliesMatch[1].split(`,`).map(s=>s.trim()).filter(Boolean);options.length>0&&(lineData.quickReplies=[...lineData.quickReplies||[],...options]),text=text.replace(quickRepliesMatch[0],``).trim()}let locationMatch=text.match(/\[\[location:\s*([^\]]+)\]\]/i);if(locationMatch&&!lineData.location){let parts=locationMatch[1].split(`|`).map(s=>s.trim());if(parts.length>=4){let[title,address,latStr,lonStr]=parts,latitude=parseFloat(latStr),longitude=parseFloat(lonStr);!isNaN(latitude)&&!isNaN(longitude)&&(lineData.location={title:title||`Location`,address:address||``,latitude,longitude})}text=text.replace(locationMatch[0],``).trim()}let confirmMatch=text.match(/\[\[confirm:\s*([^\]]+)\]\]/i);if(confirmMatch&&!lineData.templateMessage){let parts=confirmMatch[1].split(`|`).map(s=>s.trim());if(parts.length>=3){let[question,yesPart,noPart]=parts,[yesLabel,yesData]=yesPart.includes(`:`)?yesPart.split(`:`).map(s=>s.trim()):[yesPart,yesPart.toLowerCase()],[noLabel,noData]=noPart.includes(`:`)?noPart.split(`:`).map(s=>s.trim()):[noPart,noPart.toLowerCase()];lineData.templateMessage={type:`confirm`,text:question,confirmLabel:yesLabel,confirmData:yesData,cancelLabel:noLabel,cancelData:noData,altText:question}}text=text.replace(confirmMatch[0],``).trim()}let buttonsMatch=text.match(/\[\[buttons:\s*([^\]]+)\]\]/i);if(buttonsMatch&&!lineData.templateMessage){let parts=buttonsMatch[1].split(`|`).map(s=>s.trim());if(parts.length>=3){let[title,bodyText,actionsStr]=parts,actions=actionsStr.split(`,`).map(actionStr=>{let trimmed=actionStr.trim(),colonIndex=(()=>{let index=trimmed.indexOf(`:`);if(index===-1)return-1;let lower=trimmed.toLowerCase();return lower.startsWith(`http://`)||lower.startsWith(`https://`)?-1:index})(),label,data;return colonIndex===-1?(label=trimmed,data=trimmed):(label=trimmed.slice(0,colonIndex).trim(),data=trimmed.slice(colonIndex+1).trim()),data.startsWith(`http://`)||data.startsWith(`https://`)?{type:`uri`,label,uri:data}:data.includes(`=`)?{type:`postback`,label,data}:{type:`message`,label,data:data||label}});actions.length>0&&(lineData.templateMessage={type:`buttons`,title,text:bodyText,actions:actions.slice(0,4),altText:`${title}: ${bodyText}`})}text=text.replace(buttonsMatch[0],``).trim()}let mediaPlayerMatch=text.match(/\[\[media_player:\s*([^\]]+)\]\]/i);if(mediaPlayerMatch&&!lineData.flexMessage){let parts=mediaPlayerMatch[1].split(`|`).map(s=>s.trim());if(parts.length>=1){let[title,artist,source,imageUrl,statusStr]=parts,isPlaying=statusStr?.toLowerCase()===`playing`,validImageUrl=imageUrl?.startsWith(`https://`)?imageUrl:void 0,deviceKey=toSlug(source||title||`media`),card=createMediaPlayerCard({title:title||`Unknown Track`,subtitle:artist||void 0,source:source||void 0,imageUrl:validImageUrl,isPlaying:statusStr?isPlaying:void 0,controls:{previous:{data:lineActionData(`previous`,{"line.device":deviceKey})},play:{data:lineActionData(`play`,{"line.device":deviceKey})},pause:{data:lineActionData(`pause`,{"line.device":deviceKey})},next:{data:lineActionData(`next`,{"line.device":deviceKey})}}});lineData.flexMessage={altText:`🎵 ${title}${artist?` - ${artist}`:``}`,contents:card}}text=text.replace(mediaPlayerMatch[0],``).trim()}let eventMatch=text.match(/\[\[event:\s*([^\]]+)\]\]/i);if(eventMatch&&!lineData.flexMessage){let parts=eventMatch[1].split(`|`).map(s=>s.trim());if(parts.length>=2){let[title,date,time,location,description]=parts,card=createEventCard({title:title||`Event`,date:date||`TBD`,time:time||void 0,location:location||void 0,description:description||void 0});lineData.flexMessage={altText:`📅 ${title} - ${date}${time?` ${time}`:``}`,contents:card}}text=text.replace(eventMatch[0],``).trim()}let appleTvMatch=text.match(/\[\[appletv_remote:\s*([^\]]+)\]\]/i);if(appleTvMatch&&!lineData.flexMessage){let parts=appleTvMatch[1].split(`|`).map(s=>s.trim());if(parts.length>=1){let[deviceName,status]=parts,deviceKey=toSlug(deviceName||`apple_tv`),card=createAppleTvRemoteCard({deviceName:deviceName||`Apple TV`,status:status||void 0,actionData:{up:lineActionData(`up`,{"line.device":deviceKey}),down:lineActionData(`down`,{"line.device":deviceKey}),left:lineActionData(`left`,{"line.device":deviceKey}),right:lineActionData(`right`,{"line.device":deviceKey}),select:lineActionData(`select`,{"line.device":deviceKey}),menu:lineActionData(`menu`,{"line.device":deviceKey}),home:lineActionData(`home`,{"line.device":deviceKey}),play:lineActionData(`play`,{"line.device":deviceKey}),pause:lineActionData(`pause`,{"line.device":deviceKey}),volumeUp:lineActionData(`volume_up`,{"line.device":deviceKey}),volumeDown:lineActionData(`volume_down`,{"line.device":deviceKey}),mute:lineActionData(`mute`,{"line.device":deviceKey})}});lineData.flexMessage={altText:`📺 ${deviceName||`Apple TV`} Remote`,contents:card}}text=text.replace(appleTvMatch[0],``).trim()}let agendaMatch=text.match(/\[\[agenda:\s*([^\]]+)\]\]/i);if(agendaMatch&&!lineData.flexMessage){let parts=agendaMatch[1].split(`|`).map(s=>s.trim());if(parts.length>=2){let[title,eventsStr]=parts,events=eventsStr.split(`,`).map(eventStr=>{let trimmed=eventStr.trim(),colonIdx=trimmed.lastIndexOf(`:`);return colonIdx>0?{title:trimmed.slice(0,colonIdx).trim(),time:trimmed.slice(colonIdx+1).trim()}:{title:trimmed}}),card=createAgendaCard({title:title||`Agenda`,events});lineData.flexMessage={altText:`📋 ${title} (${events.length} events)`,contents:card}}text=text.replace(agendaMatch[0],``).trim()}let deviceMatch=text.match(/\[\[device:\s*([^\]]+)\]\]/i);if(deviceMatch&&!lineData.flexMessage){let parts=deviceMatch[1].split(`|`).map(s=>s.trim());if(parts.length>=1){let[deviceName,deviceType,status,controlsStr]=parts,deviceKey=toSlug(deviceName||`device`),controls=controlsStr?controlsStr.split(`,`).map(ctrlStr=>{let[label,data]=ctrlStr.split(`:`).map(s=>s.trim());return{label,data:lineActionData(data||label.toLowerCase().replace(/\s+/g,`_`),{"line.device":deviceKey})}}):[],card=createDeviceControlCard({deviceName:deviceName||`Device`,deviceType:deviceType||void 0,status:status||void 0,controls});lineData.flexMessage={altText:`📱 ${deviceName}${status?`: ${status}`:``}`,contents:card}}text=text.replace(deviceMatch[0],``).trim()}return text=text.replace(/\n{3,}/g,`
47
47
 
@@ -86,7 +86,7 @@ Assigned content references: ${content.join(`, `)}. Treat these as authoritative
86
86
  `)||``;if(!rawBody)return null;let ackReaction=resolveAckReaction(cfg,route.agentId,{channel:`slack`,accountId:account.accountId}),ackReactionValue=ackReaction??``,shouldAckReaction$2=()=>!!(ackReaction&&shouldAckReaction({scope:ctx.ackReactionScope,isDirect:isDirectMessage,isGroup:isRoomish,isMentionableGroup:isRoom,requireMention:!!shouldRequireMention,canDetectMention,effectiveWasMentioned,shouldBypassMention:mentionGate.shouldBypassMention})),ackReactionMessageTs=message.ts,ackReactionPromise=shouldAckReaction$2()&&ackReactionMessageTs&&ackReactionValue?reactSlackMessage(message.channel,ackReactionMessageTs,ackReactionValue,{token:ctx.botToken,client:ctx.app.client}).then(()=>!0,err=>(logVerbose(`slack react failed for channel ${message.channel}: ${String(err)}`),!1)):null,roomLabel=channelName?`#${channelName}`:`#${message.channel}`,preview=rawBody.replace(/\s+/g,` `).slice(0,160),inboundLabel=isDirectMessage?`Slack DM from ${senderName}`:`Slack message in ${roomLabel} from ${senderName}`,slackFrom=isDirectMessage?`slack:${message.user}`:isRoom?`slack:channel:${message.channel}`:`slack:group:${message.channel}`;enqueueSystemEvent(`${inboundLabel}: ${preview}`,{sessionKey,contextKey:`slack:message:${message.channel}:${message.ts??`unknown`}`});let envelopeFrom=resolveConversationLabel({ChatType:isDirectMessage?`direct`:`channel`,SenderName:senderName,GroupSubject:isRoomish?roomLabel:void 0,From:slackFrom})??(isDirectMessage?senderName:roomLabel),threadInfo=isThreadReply&&threadTs?` thread_ts: ${threadTs}${message.parent_user_id?` parent_user_id: ${message.parent_user_id}`:``}`:``,textWithId=`${rawBody}\n[slack message id: ${message.ts} channel: ${message.channel}${threadInfo}]`,storePath=resolveStorePath(ctx.cfg.session?.store,{agentId:route.agentId}),envelopeOptions=resolveEnvelopeFormatOptions(ctx.cfg),previousTimestamp=readSessionUpdatedAt({storePath,sessionKey:route.sessionKey}),combinedBody=formatInboundEnvelope({channel:`Slack`,from:envelopeFrom,timestamp:message.ts?Math.round(Number(message.ts)*1e3):void 0,body:textWithId,chatType:isDirectMessage?`direct`:`channel`,sender:{name:senderName,id:senderId},previousTimestamp,envelope:envelopeOptions});isRoomish&&ctx.historyLimit>0&&(combinedBody=buildPendingHistoryContextFromMap({historyMap:ctx.channelHistories,historyKey,limit:ctx.historyLimit,currentMessage:combinedBody,formatEntry:entry=>formatInboundEnvelope({channel:`Slack`,from:roomLabel,timestamp:entry.timestamp,body:`${entry.body}${entry.messageId?` [id:${entry.messageId} channel:${message.channel}]`:``}`,chatType:`channel`,senderLabel:entry.sender,envelope:envelopeOptions})}));let slackTo=isDirectMessage?`user:${message.user}`:`channel:${message.channel}`,{untrustedChannelMetadata,groupSystemPrompt}=resolveSlackRoomContextHints({isRoomish,channelInfo,channelConfig}),threadStarterBody,threadHistoryBody,threadSessionPreviousTimestamp,threadLabel,threadStarterMedia=null;if(isThreadReply&&threadTs){let starter=await resolveSlackThreadStarter({channelId:message.channel,threadTs,client:ctx.app.client});if(starter?.text){threadStarterBody=starter.text;let snippet=starter.text.replace(/\s+/g,` `).slice(0,80);threadLabel=`Slack thread ${roomLabel}${snippet?`: ${snippet}`:``}`,!effectiveDirectMedia&&starter.files&&starter.files.length>0&&(threadStarterMedia=await resolveSlackMedia({files:starter.files,token:ctx.botToken,maxBytes:ctx.mediaMaxBytes}),threadStarterMedia&&logVerbose(`slack: hydrated thread starter file ${threadStarterMedia.map(m=>m.placeholder).join(`, `)} from root message`))}else threadLabel=`Slack thread ${roomLabel}`;let threadInitialHistoryLimit=account.config?.thread?.initialHistoryLimit??20;if(threadSessionPreviousTimestamp=readSessionUpdatedAt({storePath,sessionKey}),threadInitialHistoryLimit>0&&!threadSessionPreviousTimestamp){let threadHistory=await resolveSlackThreadHistory({channelId:message.channel,threadTs,client:ctx.app.client,currentMessageTs:message.ts,limit:threadInitialHistoryLimit});if(threadHistory.length>0){let uniqueUserIds=[...new Set(threadHistory.map(m=>m.userId).filter(id=>!!id))],userMap=new Map;await Promise.all(uniqueUserIds.map(async id=>{let user=await ctx.resolveUserName(id);user&&userMap.set(id,user)}));let historyParts=[];for(let historyMsg of threadHistory){let msgSenderName=(historyMsg.userId?userMap.get(historyMsg.userId):null)?.name??(historyMsg.botId?`Bot (${historyMsg.botId})`:`Unknown`),role=historyMsg.botId?`assistant`:`user`,msgWithId=`${historyMsg.text}\n[slack message id: ${historyMsg.ts??`unknown`} channel: ${message.channel}]`;historyParts.push(formatInboundEnvelope({channel:`Slack`,from:`${msgSenderName} (${role})`,timestamp:historyMsg.ts?Math.round(Number(historyMsg.ts)*1e3):void 0,body:msgWithId,chatType:`channel`,envelope:envelopeOptions}))}threadHistoryBody=historyParts.join(`
87
87
 
88
88
  `),logVerbose(`slack: populated thread history with ${threadHistory.length} messages for new session`)}}}let effectiveMedia=effectiveDirectMedia??threadStarterMedia,firstMedia=effectiveMedia?.[0],inboundHistory=isRoomish&&ctx.historyLimit>0?(ctx.channelHistories.get(historyKey)??[]).map(entry=>({sender:entry.sender,body:entry.body,timestamp:entry.timestamp})):void 0,ctxPayload=finalizeInboundContext({Body:combinedBody,BodyForAgent:rawBody,InboundHistory:inboundHistory,RawBody:rawBody,CommandBody:rawBody,From:slackFrom,To:slackTo,SessionKey:sessionKey,AccountId:route.accountId,ChatType:isDirectMessage?`direct`:`channel`,ConversationLabel:envelopeFrom,GroupSubject:isRoomish?roomLabel:void 0,GroupSystemPrompt:isRoomish?groupSystemPrompt:void 0,UntrustedContext:untrustedChannelMetadata?[untrustedChannelMetadata]:void 0,SenderName:senderName,SenderId:senderId,Provider:`slack`,Surface:`slack`,MessageSid:message.ts,ReplyToId:threadContext.replyToId,MessageThreadId:threadContext.messageThreadId,ParentSessionKey:threadKeys.parentSessionKey,ThreadStarterBody:threadStarterBody,ThreadHistoryBody:threadHistoryBody,IsFirstThreadTurn:isThreadReply&&threadTs&&!threadSessionPreviousTimestamp?!0:void 0,ThreadLabel:threadLabel,Timestamp:message.ts?Math.round(Number(message.ts)*1e3):void 0,WasMentioned:isRoomish?effectiveWasMentioned:void 0,MediaPath:firstMedia?.path,MediaType:firstMedia?.contentType,MediaUrl:firstMedia?.path,MediaPaths:effectiveMedia&&effectiveMedia.length>0?effectiveMedia.map(m=>m.path):void 0,MediaUrls:effectiveMedia&&effectiveMedia.length>0?effectiveMedia.map(m=>m.path):void 0,MediaTypes:effectiveMedia&&effectiveMedia.length>0?effectiveMedia.map(m=>m.contentType??``):void 0,CommandAuthorized:commandAuthorized,OriginatingChannel:`slack`,OriginatingTo:slackTo});await recordInboundSession({storePath,sessionKey,ctx:ctxPayload,updateLastRoute:isDirectMessage?{sessionKey:route.mainSessionKey,channel:`slack`,to:`user:${message.user}`,accountId:route.accountId}:void 0,onRecordError:err=>{ctx.logger.warn({error:String(err),storePath,sessionKey},`failed updating session meta`)}});let replyTarget=ctxPayload.To??void 0;return replyTarget?(shouldLogVerbose()&&logVerbose(`slack inbound: channel=${message.channel} from=${slackFrom} preview="${preview}"`),{ctx,account,message,route,channelConfig,replyTarget,ctxPayload,isDirectMessage,isRoomish,historyKey,preview,ackReactionMessageTs,ackReactionValue,ackReactionPromise}):null}const normalizeThreadTs=threadTs=>threadTs?.trim()||void 0;async function resolveThreadTsFromHistory(params){try{let response=await params.client.conversations.history({channel:params.channelId,latest:params.messageTs,oldest:params.messageTs,inclusive:!0,limit:1});return normalizeThreadTs((response.messages?.find(entry=>entry.ts===params.messageTs)??response.messages?.[0])?.thread_ts)}catch(err){shouldLogVerbose()&&logVerbose(`slack inbound: failed to resolve thread_ts via conversations.history for channel=${params.channelId} ts=${params.messageTs}: ${String(err)}`);return}}function createSlackThreadTsResolver(params){let ttlMs=Math.max(0,params.cacheTtlMs??6e4),maxSize=Math.max(0,params.maxSize??500),cache=new Map,inflight=new Map,getCached=(key,now)=>{let entry=cache.get(key);if(entry){if(ttlMs>0&&now-entry.updatedAt>ttlMs){cache.delete(key);return}return cache.delete(key),cache.set(key,{...entry,updatedAt:now}),entry.threadTs}},setCached=(key,threadTs,now)=>{cache.delete(key),cache.set(key,{threadTs,updatedAt:now}),pruneMapToMaxSize(cache,maxSize)};return{resolve:async request=>{let{message}=request;if(!message.parent_user_id||message.thread_ts||!message.ts)return message;let cacheKey=`${message.channel}:${message.ts}`,cached=getCached(cacheKey,Date.now());if(cached!==void 0)return cached?{...message,thread_ts:cached}:message;shouldLogVerbose()&&logVerbose(`slack inbound: missing thread_ts for thread reply channel=${message.channel} ts=${message.ts} source=${request.source}`);let pending=inflight.get(cacheKey);pending||(pending=resolveThreadTsFromHistory({client:params.client,channelId:message.channel,messageTs:message.ts}),inflight.set(cacheKey,pending));let resolved;try{resolved=await pending}finally{inflight.delete(cacheKey)}return setCached(cacheKey,resolved??null,Date.now()),resolved?(shouldLogVerbose()&&logVerbose(`slack inbound: resolved missing thread_ts channel=${message.channel} ts=${message.ts} -> thread_ts=${resolved}`),{...message,thread_ts:resolved}):(shouldLogVerbose()&&logVerbose(`slack inbound: could not resolve missing thread_ts channel=${message.channel} ts=${message.ts}`),message)}}}function createSlackMessageHandler(params){let{ctx,account}=params,debounceMs=resolveInboundDebounceMs({cfg:ctx.cfg,channel:`slack`}),threadTsResolver=createSlackThreadTsResolver({client:ctx.app.client}),debouncer=createInboundDebouncer({debounceMs,buildKey:entry=>{let senderId=entry.message.user??entry.message.bot_id;if(!senderId)return null;let messageTs=entry.message.ts??entry.message.event_ts,threadKey=entry.message.thread_ts?`${entry.message.channel}:${entry.message.thread_ts}`:entry.message.parent_user_id&&messageTs?`${entry.message.channel}:maybe-thread:${messageTs}`:entry.message.channel;return`slack:${ctx.accountId}:${threadKey}:${senderId}`},shouldDebounce:entry=>{let text=entry.message.text??``;return!text.trim()||entry.message.files&&entry.message.files.length>0?!1:!hasControlCommand(stripSlackMentionsForCommandDetection(text),ctx.cfg)},onFlush:async entries=>{let last=entries.at(-1);if(!last)return;let combinedText=entries.length===1?last.message.text??``:entries.map(entry=>entry.message.text??``).filter(Boolean).join(`
89
- `),combinedMentioned=entries.some(entry=>!!entry.opts.wasMentioned),prepared=await prepareSlackMessage({ctx,account,message:{...last.message,text:combinedText},opts:{...last.opts,wasMentioned:combinedMentioned||last.opts.wasMentioned}});if(prepared){if(entries.length>1){let ids=entries.map(entry=>entry.message.ts).filter(Boolean);ids.length>0&&(prepared.ctxPayload.MessageSids=ids,prepared.ctxPayload.MessageSidFirst=ids[0],prepared.ctxPayload.MessageSidLast=ids[ids.length-1])}await dispatchPreparedSlackMessage(prepared)}},onError:err=>{ctx.runtime.error?.(`slack inbound debounce flush failed: ${String(err)}`)}});return async(message,opts)=>{if(opts.source===`message`&&message.type!==`message`||opts.source===`message`&&message.subtype&&message.subtype!==`file_share`&&message.subtype!==`bot_message`||ctx.markMessageSeen(message.channel,message.ts))return;let resolvedMessage=await threadTsResolver.resolve({message,source:opts.source});await debouncer.enqueue({message:resolvedMessage,opts})}}const SLACK_COMMAND_ARG_ACTION_ID=`builderforce_cmdarg`,SLACK_COMMAND_ARG_VALUE_PREFIX=`cmdarg`,SLACK_COMMAND_ARG_EXTERNAL_PREFIX=`builderforce_cmdarg_ext:`,slackExternalArgMenuStore=new Map;function truncatePlainText(value,max){let trimmed=value.trim();return trimmed.length<=max?trimmed:max<=1?trimmed.slice(0,max):`${trimmed.slice(0,max-1)}…`}function escapeSlackMrkdwn(value){return value.replaceAll(`\\`,`\\\\`).replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replace(/([*_`~])/g,`\\$1`)}function buildSlackArgMenuConfirm(params){return{title:{type:`plain_text`,text:`Confirm selection`},text:{type:`mrkdwn`,text:`Run */${escapeSlackMrkdwn(params.command)}* with *${escapeSlackMrkdwn(params.arg)}* set to this value?`},confirm:{type:`plain_text`,text:`Run command`},deny:{type:`plain_text`,text:`Cancel`}}}function pruneSlackExternalArgMenuStore(now=Date.now()){for(let[token,entry]of slackExternalArgMenuStore.entries())entry.expiresAt<=now&&slackExternalArgMenuStore.delete(token)}function storeSlackExternalArgMenu(params){pruneSlackExternalArgMenuStore();let token=`${Date.now().toString(36)}${Math.random().toString(36).slice(2,10)}`;return slackExternalArgMenuStore.set(token,{choices:params.choices,userId:params.userId,expiresAt:Date.now()+6e5}),token}function readSlackExternalArgMenuToken(raw){if(typeof raw!=`string`||!raw.startsWith(SLACK_COMMAND_ARG_EXTERNAL_PREFIX))return;let token=raw.slice(24).trim();return token.length>0?token:void 0}function encodeSlackCommandArgValue(parts){return[SLACK_COMMAND_ARG_VALUE_PREFIX,encodeURIComponent(parts.command),encodeURIComponent(parts.arg),encodeURIComponent(parts.value),encodeURIComponent(parts.userId)].join(`|`)}function parseSlackCommandArgValue(raw){if(!raw)return null;let parts=raw.split(`|`);if(parts.length!==5||parts[0]!==SLACK_COMMAND_ARG_VALUE_PREFIX)return null;let[,command,arg,value,userId]=parts;if(!command||!arg||!value||!userId)return null;let decode=text=>{try{return decodeURIComponent(text)}catch{return null}},decodedCommand=decode(command),decodedArg=decode(arg),decodedValue=decode(value),decodedUserId=decode(userId);return!decodedCommand||!decodedArg||!decodedValue||!decodedUserId?null:{command:decodedCommand,arg:decodedArg,value:decodedValue,userId:decodedUserId}}function buildSlackCommandArgMenuBlocks(params){let encodedChoices=params.choices.map(choice=>({label:choice.label,value:encodeSlackCommandArgValue({command:params.command,arg:params.arg,value:choice.value,userId:params.userId})})),canUseStaticSelect=encodedChoices.every(choice=>choice.value.length<=75),canUseOverflow=canUseStaticSelect&&encodedChoices.length>=3&&encodedChoices.length<=5,canUseExternalSelect=params.supportsExternalSelect&&canUseStaticSelect&&encodedChoices.length>100,rows=canUseOverflow?[{type:`actions`,elements:[{type:`overflow`,action_id:SLACK_COMMAND_ARG_ACTION_ID,confirm:buildSlackArgMenuConfirm({command:params.command,arg:params.arg}),options:encodedChoices.map(choice=>({text:{type:`plain_text`,text:choice.label.slice(0,75)},value:choice.value}))}]}]:canUseExternalSelect?[{type:`actions`,block_id:`${SLACK_COMMAND_ARG_EXTERNAL_PREFIX}${params.createExternalMenuToken(encodedChoices)}`,elements:[{type:`external_select`,action_id:SLACK_COMMAND_ARG_ACTION_ID,confirm:buildSlackArgMenuConfirm({command:params.command,arg:params.arg}),min_query_length:0,placeholder:{type:`plain_text`,text:`Search ${params.arg}`}}]}]:encodedChoices.length<=5||!canUseStaticSelect?chunkItems(encodedChoices,5).map(choices=>({type:`actions`,elements:choices.map(choice=>({type:`button`,action_id:SLACK_COMMAND_ARG_ACTION_ID,text:{type:`plain_text`,text:choice.label},value:choice.value,confirm:buildSlackArgMenuConfirm({command:params.command,arg:params.arg})}))})):chunkItems(encodedChoices,100).map((choices,index)=>({type:`actions`,elements:[{type:`static_select`,action_id:SLACK_COMMAND_ARG_ACTION_ID,confirm:buildSlackArgMenuConfirm({command:params.command,arg:params.arg}),placeholder:{type:`plain_text`,text:index===0?`Choose ${params.arg}`:`Choose ${params.arg} (${index+1})`},options:choices.map(choice=>({text:{type:`plain_text`,text:choice.label.slice(0,75)},value:choice.value}))}]})),headerText=truncatePlainText(`/${params.command}: choose ${params.arg}`,150),sectionText=truncatePlainText(params.title,3e3),contextText=truncatePlainText(`Select one option to continue /${params.command} (${params.arg})`,3e3);return[{type:`header`,text:{type:`plain_text`,text:headerText}},{type:`section`,text:{type:`mrkdwn`,text:sectionText}},{type:`context`,elements:[{type:`mrkdwn`,text:contextText}]},...rows]}async function registerSlackMonitorSlashCommands(params){let{ctx,account}=params,cfg=ctx.cfg,runtime=ctx.runtime,supportsInteractiveArgMenus=typeof ctx.app.action==`function`,supportsExternalArgMenus=typeof ctx.app.options==`function`,slashCommand=resolveSlackSlashCommandConfig(ctx.slashCommand??account.config.slashCommand),handleSlashCommand=async p=>{let{command,ack,respond,prompt,commandArgs,commandDefinition}=p;try{if(!prompt.trim()){await ack({text:`Message required.`,response_type:`ephemeral`});return}if(await ack(),ctx.botUserId&&command.user_id===ctx.botUserId)return;let channelInfo=await ctx.resolveChannelName(command.channel_id),channelType=normalizeSlackChannelType(channelInfo?.type??(command.channel_name===`directmessage`?`im`:void 0),command.channel_id),isDirectMessage=channelType===`im`,isGroupDm=channelType===`mpim`,isRoom=channelType===`channel`||channelType===`group`,isRoomish=isRoom||isGroupDm;if(!ctx.isChannelAllowed({channelId:command.channel_id,channelName:channelInfo?.name,channelType})){await respond({text:`This channel is not allowed.`,response_type:`ephemeral`});return}let storeAllowFrom=await readChannelAllowFromStore(`slack`).catch(()=>[]),effectiveAllowFromLower=normalizeAllowListLower(normalizeAllowList([...ctx.allowFrom,...storeAllowFrom])),commandAuthorized=!1,channelConfig=null;if(isDirectMessage){if(!ctx.dmEnabled||ctx.dmPolicy===`disabled`){await respond({text:`Slack DMs are disabled.`,response_type:`ephemeral`});return}if(ctx.dmPolicy!==`open`){let senderName=(await ctx.resolveUserName(command.user_id))?.name??void 0,allowMatch=resolveSlackAllowListMatch({allowList:effectiveAllowFromLower,id:command.user_id,name:senderName}),allowMatchMeta=formatAllowlistMatchMeta(allowMatch);if(!allowMatch.allowed){if(ctx.dmPolicy===`pairing`){let{code,created}=await upsertChannelPairingRequest({channel:`slack`,id:command.user_id,meta:{name:senderName}});created&&(logVerbose(`slack pairing request sender=${command.user_id} name=${senderName??`unknown`} (${allowMatchMeta})`),await respond({text:buildPairingReply({channel:`slack`,idLine:`Your Slack user id: ${command.user_id}`,code}),response_type:`ephemeral`}))}else logVerbose(`slack: blocked slash sender ${command.user_id} (dmPolicy=${ctx.dmPolicy}, ${allowMatchMeta})`),await respond({text:`You are not authorized to use this command.`,response_type:`ephemeral`});return}}}if(isRoom&&(channelConfig=resolveSlackChannelConfig({channelId:command.channel_id,channelName:channelInfo?.name,channels:ctx.channelsConfig,defaultRequireMention:ctx.defaultRequireMention}),ctx.useAccessGroups)){let channelAllowlistConfigured=!!ctx.channelsConfig&&Object.keys(ctx.channelsConfig??{}).length>0,channelAllowed=channelConfig?.allowed!==!1;if(!isSlackChannelAllowedByPolicy({groupPolicy:ctx.groupPolicy,channelAllowlistConfigured,channelAllowed})){await respond({text:`This channel is not allowed.`,response_type:`ephemeral`});return}let hasExplicitConfig=!!channelConfig?.matchSource;if(!channelAllowed&&(ctx.groupPolicy!==`open`||hasExplicitConfig)){await respond({text:`This channel is not allowed.`,response_type:`ephemeral`});return}}let senderName=(await ctx.resolveUserName(command.user_id))?.name??command.user_name??command.user_id,channelUsersAllowlistConfigured=isRoom&&Array.isArray(channelConfig?.users)&&channelConfig.users.length>0,channelUserAllowed=channelUsersAllowlistConfigured?resolveSlackUserAllowed({allowList:channelConfig?.users,userId:command.user_id,userName:senderName}):!1;if(channelUsersAllowlistConfigured&&!channelUserAllowed){await respond({text:`You are not authorized to use this command here.`,response_type:`ephemeral`});return}let ownerAllowed=resolveSlackAllowListMatch({allowList:effectiveAllowFromLower,id:command.user_id,name:senderName}).allowed;if(commandAuthorized=resolveCommandAuthorizedFromAuthorizers({useAccessGroups:ctx.useAccessGroups,authorizers:[{configured:effectiveAllowFromLower.length>0,allowed:ownerAllowed}],modeWhenAccessGroupsOff:`configured`}),isRoomish&&(commandAuthorized=resolveCommandAuthorizedFromAuthorizers({useAccessGroups:ctx.useAccessGroups,authorizers:[{configured:effectiveAllowFromLower.length>0,allowed:ownerAllowed},{configured:channelUsersAllowlistConfigured,allowed:channelUserAllowed}],modeWhenAccessGroupsOff:`configured`}),ctx.useAccessGroups&&!commandAuthorized)){await respond({text:`You are not authorized to use this command.`,response_type:`ephemeral`});return}if(commandDefinition&&supportsInteractiveArgMenus){let menu=resolveCommandArgMenu({command:commandDefinition,args:commandArgs,cfg});if(menu){let commandLabel=commandDefinition.nativeName??commandDefinition.key,title=menu.title??`Choose ${menu.arg.description||menu.arg.name} for /${commandLabel}.`;await respond({text:title,blocks:buildSlackCommandArgMenuBlocks({title,command:commandLabel,arg:menu.arg.name,choices:menu.choices,userId:command.user_id,supportsExternalSelect:supportsExternalArgMenus,createExternalMenuToken:choices=>storeSlackExternalArgMenu({choices,userId:command.user_id})}),response_type:`ephemeral`});return}}let channelName=channelInfo?.name,roomLabel=channelName?`#${channelName}`:`#${command.channel_id}`,[{resolveAgentRoute},{finalizeInboundContext},{dispatchReplyWithDispatcher}]=await Promise.all([import(`./resolve-route-Bj4Vlrzh.js`),import(`./inbound-context-a0yIq19D.js`),import(`./provider-dispatcher-B6kumPDM.js`)]),[{resolveConversationLabel},{createReplyPrefixOptions}]=await Promise.all([import(`./conversation-label-C40UwLZq.js`),import(`./reply-prefix-YLHlrWfw.js`)]),route=resolveAgentRoute({cfg,channel:`slack`,accountId:account.accountId,teamId:ctx.teamId||void 0,peer:{kind:isDirectMessage?`direct`:isRoom?`channel`:`group`,id:isDirectMessage?command.user_id:command.channel_id}}),{untrustedChannelMetadata,groupSystemPrompt}=resolveSlackRoomContextHints({isRoomish,channelInfo,channelConfig}),ctxPayload=finalizeInboundContext({Body:prompt,BodyForAgent:prompt,RawBody:prompt,CommandBody:prompt,CommandArgs:commandArgs,From:isDirectMessage?`slack:${command.user_id}`:isRoom?`slack:channel:${command.channel_id}`:`slack:group:${command.channel_id}`,To:`slash:${command.user_id}`,ChatType:isDirectMessage?`direct`:`channel`,ConversationLabel:resolveConversationLabel({ChatType:isDirectMessage?`direct`:`channel`,SenderName:senderName,GroupSubject:isRoomish?roomLabel:void 0,From:isDirectMessage?`slack:${command.user_id}`:isRoom?`slack:channel:${command.channel_id}`:`slack:group:${command.channel_id}`})??(isDirectMessage?senderName:roomLabel),GroupSubject:isRoomish?roomLabel:void 0,GroupSystemPrompt:isRoomish?groupSystemPrompt:void 0,UntrustedContext:untrustedChannelMetadata?[untrustedChannelMetadata]:void 0,SenderName:senderName,SenderId:command.user_id,Provider:`slack`,Surface:`slack`,WasMentioned:!0,MessageSid:command.trigger_id,Timestamp:Date.now(),SessionKey:`agent:${route.agentId}:${slashCommand.sessionPrefix}:${command.user_id}`.toLowerCase(),CommandTargetSessionKey:route.sessionKey,AccountId:route.accountId,CommandSource:`native`,CommandAuthorized:commandAuthorized,OriginatingChannel:`slack`,OriginatingTo:`user:${command.user_id}`}),{onModelSelected,...prefixOptions}=createReplyPrefixOptions({cfg,agentId:route.agentId,channel:`slack`,accountId:route.accountId}),deliverSlashPayloads=async replies=>{let[{deliverSlackSlashReplies},{resolveChunkMode},{resolveMarkdownTableMode}]=await Promise.all([import(`./replies-DFfYfMhc.js`),import(`./chunk-OGAjqr5A.js`),import(`./markdown-tables-mfuWd97r.js`)]);await deliverSlackSlashReplies({replies,respond,ephemeral:slashCommand.ephemeral,textLimit:ctx.textLimit,chunkMode:resolveChunkMode(cfg,`slack`,route.accountId),tableMode:resolveMarkdownTableMode({cfg,channel:`slack`,accountId:route.accountId})})},{counts}=await dispatchReplyWithDispatcher({ctx:ctxPayload,cfg,dispatcherOptions:{...prefixOptions,deliver:async payload=>deliverSlashPayloads([payload]),onError:(err,info)=>{runtime.error?.(danger(`slack slash ${info.kind} reply failed: ${String(err)}`))}},replyOptions:{skillFilter:channelConfig?.skills,onModelSelected}});counts.final+counts.tool+counts.block===0&&await deliverSlashPayloads([])}catch(err){runtime.error?.(danger(`slack slash handler failed: ${String(err)}`)),await respond({text:`Sorry, something went wrong handling that command.`,response_type:`ephemeral`})}},nativeEnabled=resolveNativeCommandsEnabled({providerId:`slack`,providerSetting:account.config.commands?.native,globalSetting:cfg.commands?.native}),nativeSkillsEnabled=resolveNativeSkillsEnabled({providerId:`slack`,providerSetting:account.config.commands?.nativeSkills,globalSetting:cfg.commands?.nativeSkills}),nativeCommands=[];if(nativeEnabled&&(nativeCommands=listNativeCommandSpecsForConfig(cfg,{skillCommands:nativeSkillsEnabled?listSkillCommandsForAgents({cfg}):[],provider:`slack`})),nativeCommands.length>0)for(let command of nativeCommands)ctx.app.command(`/${command.name}`,async({command:cmd,ack,respond})=>{let commandDefinition=findCommandByNativeName(command.name,`slack`),rawText=cmd.text?.trim()??``,commandArgs=commandDefinition?parseCommandArgs(commandDefinition,rawText):rawText?{raw:rawText}:void 0;await handleSlashCommand({command:cmd,ack,respond,prompt:commandDefinition?buildCommandTextFromArgs(commandDefinition,commandArgs):rawText?`/${command.name} ${rawText}`:`/${command.name}`,commandArgs,commandDefinition:commandDefinition??void 0})});else slashCommand.enabled?ctx.app.command(buildSlackSlashCommandMatcher(slashCommand.name),async({command,ack,respond})=>{await handleSlashCommand({command,ack,respond,prompt:command.text?.trim()??``})}):logVerbose(`slack: slash commands disabled`);nativeCommands.length===0||!supportsInteractiveArgMenus||((()=>{let optionsHandler=ctx.app.options;typeof optionsHandler==`function`&&optionsHandler(SLACK_COMMAND_ARG_ACTION_ID,async({ack,body})=>{let typedBody=body;pruneSlackExternalArgMenuStore();let token=readSlackExternalArgMenuToken(typedBody.actions?.[0]?.block_id??typedBody.block_id);if(!token){await ack({options:[]});return}let entry=slackExternalArgMenuStore.get(token);if(!entry){await ack({options:[]});return}if(typedBody.user?.id&&typedBody.user.id!==entry.userId){await ack({options:[]});return}let query=typedBody.value?.trim().toLowerCase()??``;await ack({options:entry.choices.filter(choice=>!query||choice.label.toLowerCase().includes(query)).slice(0,100).map(choice=>({text:{type:`plain_text`,text:choice.label.slice(0,75)},value:choice.value}))})})})(),(actionId=>{ctx.app.action(actionId,async args=>{let{ack,body,respond}=args,action=args.action;await ack();let respondFn=respond??(async payload=>{!body.channel?.id||!body.user?.id||await ctx.app.client.chat.postEphemeral({token:ctx.botToken,channel:body.channel.id,user:body.user.id,text:payload.text,blocks:payload.blocks})}),parsed=parseSlackCommandArgValue(action?.value??action?.selected_option?.value);if(!parsed){await respondFn({text:`Sorry, that button is no longer valid.`,response_type:`ephemeral`});return}if(body.user?.id&&parsed.userId!==body.user.id){await respondFn({text:`That menu is for another user.`,response_type:`ephemeral`});return}let commandDefinition=findCommandByNativeName(parsed.command,`slack`),commandArgs={values:{[parsed.arg]:parsed.value}},prompt=commandDefinition?buildCommandTextFromArgs(commandDefinition,commandArgs):`/${parsed.command} ${parsed.value}`,user=body.user,userName=user&&`name`in user&&user.name?user.name:user&&`username`in user&&user.username?user.username:user?.id??``,triggerId=`trigger_id`in body?body.trigger_id:void 0;await handleSlashCommand({command:{user_id:user?.id??``,user_name:userName,channel_id:body.channel?.id??``,channel_name:body.channel?.name??body.channel?.id??``,trigger_id:triggerId??String(Date.now())},ack:async()=>{},respond:respondFn,prompt,commandArgs,commandDefinition:commandDefinition??void 0})})})(SLACK_COMMAND_ARG_ACTION_ID))}const slackBoltModule=SlackBolt,{App,HTTPReceiver}=(slackBoltModule.App?slackBoltModule:slackBoltModule.default)??slackBoltModule;function parseApiAppIdFromAppToken(raw){let token=raw?.trim();if(token)return/^xapp-\d-([a-z0-9]+)-/i.exec(token)?.[1]?.toUpperCase()}async function monitorSlackProvider(opts={}){let cfg=opts.config??loadConfig(),account=resolveSlackAccount({cfg,accountId:opts.accountId}),historyLimit=Math.max(0,account.config.historyLimit??cfg.messages?.groupChat?.historyLimit??50),sessionCfg=cfg.session,sessionScope=sessionCfg?.scope??`per-sender`,mainKey=normalizeMainKey(sessionCfg?.mainKey),slackMode=opts.mode??account.config.mode??`socket`,slackWebhookPath=normalizeSlackWebhookPath(account.config.webhookPath),signingSecret=account.config.signingSecret?.trim(),botToken=resolveSlackBotToken(opts.botToken??account.botToken),appToken=resolveSlackAppToken(opts.appToken??account.appToken);if(!botToken||slackMode!==`http`&&!appToken){let missing=slackMode===`http`?`Slack bot token missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken or SLACK_BOT_TOKEN for default).`:`Slack bot + app tokens missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken/appToken or SLACK_BOT_TOKEN/SLACK_APP_TOKEN for default).`;throw Error(missing)}if(slackMode===`http`&&!signingSecret)throw Error(`Slack signing secret missing for account "${account.accountId}" (set channels.slack.signingSecret or channels.slack.accounts.${account.accountId}.signingSecret).`);let runtime=opts.runtime??createNonExitingRuntime(),slackCfg=account.config,dmConfig=slackCfg.dm,dmEnabled=dmConfig?.enabled??!0,dmPolicy=slackCfg.dmPolicy??dmConfig?.policy??`pairing`,allowFrom=slackCfg.allowFrom??dmConfig?.allowFrom,groupDmEnabled=dmConfig?.groupEnabled??!1,groupDmChannels=dmConfig?.groupChannels,channelsConfig=slackCfg.channels,defaultGroupPolicy=cfg.channels?.defaults?.groupPolicy,groupPolicy=slackCfg.groupPolicy??defaultGroupPolicy??`open`;slackCfg.groupPolicy===void 0&&slackCfg.channels===void 0&&defaultGroupPolicy===void 0&&groupPolicy===`open`&&runtime.log?.(warn(`slack: groupPolicy defaults to "open" when channels.slack is missing; set channels.slack.groupPolicy (or channels.defaults.groupPolicy) or add channels.slack.channels to restrict access.`));let resolveToken=slackCfg.userToken?.trim()||botToken,useAccessGroups=cfg.commands?.useAccessGroups!==!1,reactionMode=slackCfg.reactionNotifications??`own`,reactionAllowlist=slackCfg.reactionAllowlist??[],replyToMode=slackCfg.replyToMode??`all`,threadHistoryScope=slackCfg.thread?.historyScope??`thread`,threadInheritParent=slackCfg.thread?.inheritParent??!1,slashCommand=resolveSlackSlashCommandConfig(opts.slashCommand??slackCfg.slashCommand),textLimit=resolveTextChunkLimit(cfg,`slack`,account.accountId),ackReactionScope=cfg.messages?.ackReactionScope??`group-mentions`,mediaMaxBytes=(opts.mediaMaxMb??slackCfg.mediaMaxMb??20)*1024*1024,removeAckAfterReply=cfg.messages?.removeAckAfterReply??!1,receiver=slackMode===`http`?new HTTPReceiver({signingSecret:signingSecret??``,endpoints:slackWebhookPath}):null,clientOptions=resolveSlackWebClientOptions(),app=new App(slackMode===`socket`?{token:botToken,appToken,socketMode:!0,clientOptions}:{token:botToken,receiver:receiver??void 0,clientOptions}),slackHttpHandler=slackMode===`http`&&receiver?async(req,res)=>{let guard=installRequestBodyLimitGuard(req,res,{maxBytes:1048576,timeoutMs:3e4,responseFormat:`text`});if(!guard.isTripped())try{await Promise.resolve(receiver.requestListener(req,res))}catch(err){if(!guard.isTripped())throw err}finally{guard.dispose()}}:null,unregisterHttpHandler=null,botUserId=``,teamId=``,apiAppId=``,expectedApiAppIdFromAppToken=parseApiAppIdFromAppToken(appToken);try{let auth=await app.client.auth.test({token:botToken});botUserId=auth.user_id??``,teamId=auth.team_id??``,apiAppId=auth.api_app_id??``}catch{}apiAppId&&expectedApiAppIdFromAppToken&&apiAppId!==expectedApiAppIdFromAppToken&&runtime.error?.(`slack token mismatch: bot token api_app_id=${apiAppId} but app token looks like api_app_id=${expectedApiAppIdFromAppToken}`);let ctx=createSlackMonitorContext({cfg,accountId:account.accountId,botToken,app,runtime,botUserId,teamId,apiAppId,historyLimit,sessionScope,mainKey,dmEnabled,dmPolicy,allowFrom,groupDmEnabled,groupDmChannels,defaultRequireMention:slackCfg.requireMention,channelsConfig,groupPolicy,useAccessGroups,reactionMode,reactionAllowlist,replyToMode,threadHistoryScope,threadInheritParent,slashCommand,textLimit,ackReactionScope,mediaMaxBytes,removeAckAfterReply});registerSlackMonitorEvents({ctx,account,handleSlackMessage:createSlackMessageHandler({ctx,account})}),await registerSlackMonitorSlashCommands({ctx,account}),slackMode===`http`&&slackHttpHandler&&(unregisterHttpHandler=registerSlackHttpHandler({path:slackWebhookPath,handler:slackHttpHandler,log:runtime.log,accountId:account.accountId})),resolveToken&&(async()=>{if(opts.abortSignal?.aborted)return;if(channelsConfig&&Object.keys(channelsConfig).length>0)try{let entries=Object.keys(channelsConfig).filter(key=>key!==`*`);if(entries.length>0){let resolved=await resolveSlackChannelAllowlist({token:resolveToken,entries}),nextChannels={...channelsConfig},mapping=[],unresolved=[];for(let entry of resolved){let source=channelsConfig?.[entry.input];if(!source)continue;if(!entry.resolved||!entry.id){unresolved.push(entry.input);continue}mapping.push(`${entry.input}→${entry.id}${entry.archived?` (archived)`:``}`);let existing=nextChannels[entry.id]??{};nextChannels[entry.id]={...source,...existing}}channelsConfig=nextChannels,ctx.channelsConfig=nextChannels,summarizeMapping(`slack channels`,mapping,unresolved,runtime)}}catch(err){runtime.log?.(`slack channel resolve failed; using config entries. ${String(err)}`)}let allowEntries=allowFrom?.filter(entry=>String(entry).trim()&&String(entry).trim()!==`*`)??[];if(allowEntries.length>0)try{let{mapping,unresolved,additions}=buildAllowlistResolutionSummary(await resolveSlackUserAllowlist({token:resolveToken,entries:allowEntries.map(entry=>String(entry))}),{formatResolved:entry=>{let note=entry.note?` (${entry.note})`:``;return`${entry.input}→${entry.id}${note}`}});allowFrom=mergeAllowlist({existing:allowFrom,additions}),ctx.allowFrom=normalizeAllowList(allowFrom),summarizeMapping(`slack users`,mapping,unresolved,runtime)}catch(err){runtime.log?.(`slack user resolve failed; using config entries. ${String(err)}`)}if(channelsConfig&&Object.keys(channelsConfig).length>0){let userEntries=new Set;for(let channel of Object.values(channelsConfig))addAllowlistUserEntriesFromConfigEntry(userEntries,channel);if(userEntries.size>0)try{let{resolvedMap,mapping,unresolved}=buildAllowlistResolutionSummary(await resolveSlackUserAllowlist({token:resolveToken,entries:Array.from(userEntries)})),nextChannels=patchAllowlistUsersInConfigEntries({entries:channelsConfig,resolvedMap});channelsConfig=nextChannels,ctx.channelsConfig=nextChannels,summarizeMapping(`slack channel users`,mapping,unresolved,runtime)}catch(err){runtime.log?.(`slack channel user resolve failed; using config entries. ${String(err)}`)}}})();let stopOnAbort=()=>{opts.abortSignal?.aborted&&slackMode===`socket`&&app.stop()};opts.abortSignal?.addEventListener(`abort`,stopOnAbort,{once:!0});try{if(slackMode===`socket`?(await app.start(),runtime.log?.(`slack socket mode connected`)):runtime.log?.(`slack http mode listening at ${slackWebhookPath}`),opts.abortSignal?.aborted)return;await new Promise(resolve=>{opts.abortSignal?.addEventListener(`abort`,()=>resolve(),{once:!0})})}finally{opts.abortSignal?.removeEventListener(`abort`,stopOnAbort),unregisterHttpHandler?.(),await app.stop().catch(()=>void 0)}}async function probeSlack(token,timeoutMs=2500){let client=createSlackWebClient(token),start=Date.now();try{let result=await withTimeout$2(client.auth.test(),timeoutMs);return result.ok?{ok:!0,status:200,elapsedMs:Date.now()-start,bot:{id:result.user_id??void 0,name:result.user??void 0},team:{id:result.team_id??void 0,name:result.team??void 0}}:{ok:!1,status:200,error:result.error??`unknown`,elapsedMs:Date.now()-start}}catch(err){let message=err instanceof Error?err.message:String(err);return{ok:!1,status:typeof err.status==`number`?err.status:null,error:message,elapsedMs:Date.now()-start}}}function collectTelegramUnmentionedGroupIds(groups){if(!groups||typeof groups!=`object`)return{groupIds:[],unresolvedGroups:0,hasWildcardUnmentionedGroups:!1};let hasWildcardUnmentionedGroups=groups[`*`]?.requireMention===!1&&groups[`*`]?.enabled!==!1,groupIds=[],unresolvedGroups=0;for(let[key,value]of Object.entries(groups)){if(key===`*`||!value||typeof value!=`object`||value.enabled===!1||value.requireMention!==!1)continue;let id=String(key).trim();id&&(/^-?\d+$/.test(id)?groupIds.push(id):unresolvedGroups+=1)}return groupIds.sort((a,b)=>a.localeCompare(b)),{groupIds,unresolvedGroups,hasWildcardUnmentionedGroups}}async function auditTelegramGroupMembership(params){let started=Date.now(),token=params.token?.trim()??``;if(!token||params.groupIds.length===0)return{ok:!0,checkedGroups:0,unresolvedGroups:0,hasWildcardUnmentionedGroups:!1,groups:[],elapsedMs:Date.now()-started};let fetcher=params.proxyUrl?makeProxyFetch(params.proxyUrl):fetch,base=`https://api.telegram.org/bot${token}`,groups=[];for(let chatId of params.groupIds)try{let res=await fetchWithTimeout(`${base}/getChatMember?chat_id=${encodeURIComponent(chatId)}&user_id=${encodeURIComponent(String(params.botId))}`,{},params.timeoutMs,fetcher),json=await res.json();if(!res.ok||!isRecord$1(json)||!json.ok){let desc=isRecord$1(json)&&!json.ok&&typeof json.description==`string`?json.description:`getChatMember failed (${res.status})`;groups.push({chatId,ok:!1,status:null,error:desc,matchKey:chatId,matchSource:`id`});continue}let status=isRecord$1(json.result)?json.result.status??null:null,ok=status===`creator`||status===`administrator`||status===`member`;groups.push({chatId,ok,status,error:ok?null:`bot not in group`,matchKey:chatId,matchSource:`id`})}catch(err){groups.push({chatId,ok:!1,status:null,error:err instanceof Error?err.message:String(err),matchKey:chatId,matchSource:`id`})}return{ok:groups.every(g=>g.ok),checkedGroups:groups.length,unresolvedGroups:0,hasWildcardUnmentionedGroups:!1,groups,elapsedMs:Date.now()-started}}function resolveTelegramAllowedUpdates(){let updates=[...API_CONSTANTS.DEFAULT_UPDATE_TYPES];return updates.includes(`message_reaction`)||updates.push(`message_reaction`),updates.includes(`channel_post`)||updates.push(`channel_post`),updates}function walkUpFrom(startDir,opts,resolveAtDir){let current=path.resolve(startDir),maxDepth=opts.maxDepth??12;for(let i=0;i<maxDepth;i+=1){let resolved=resolveAtDir(current);if(resolved!=null)return resolved;let parent=path.dirname(current);if(parent===current)break;current=parent}return null}function hasGitMarker(repoRoot){let gitPath=path.join(repoRoot,`.git`);try{let stat=fs.statSync(gitPath);return stat.isDirectory()||stat.isFile()}catch{return!1}}function findGitRoot(startDir,opts={}){return walkUpFrom(startDir,opts,repoRoot=>hasGitMarker(repoRoot)?repoRoot:null)}function resolveGitDirFromMarker(repoRoot){let gitPath=path.join(repoRoot,`.git`);try{let stat=fs.statSync(gitPath);if(stat.isDirectory())return gitPath;if(!stat.isFile())return null;let match=fs.readFileSync(gitPath,`utf-8`).match(/gitdir:\s*(.+)/i);return match?.[1]?path.resolve(repoRoot,match[1].trim()):null}catch{return null}}function resolveGitHeadPath(startDir,opts={}){return walkUpFrom(startDir,opts,repoRoot=>{let gitDir=resolveGitDirFromMarker(repoRoot);return gitDir?path.join(gitDir,`HEAD`):null})}const formatCommit=value=>{if(!value)return null;let trimmed=value.trim();return trimmed?trimmed.length>7?trimmed.slice(0,7):trimmed:null};let cachedCommit;const readCommitFromPackageJson=()=>{try{let pkg=createRequire(import.meta.url)(`../../package.json`);return formatCommit(pkg.gitHead??pkg.githead??null)}catch{return null}},readCommitFromBuildInfo=()=>{try{let require=createRequire(import.meta.url);for(let candidate of[`../build-info.json`,`./build-info.json`])try{let formatted=formatCommit(require(candidate).commit??null);if(formatted)return formatted}catch{}return null}catch{return null}},resolveCommitHash=(options={})=>{if(cachedCommit!==void 0)return cachedCommit;let env=options.env??process.env,normalized=formatCommit(env.GIT_COMMIT?.trim()||env.GIT_SHA?.trim());if(normalized)return cachedCommit=normalized,cachedCommit;let buildInfoCommit=readCommitFromBuildInfo();if(buildInfoCommit)return cachedCommit=buildInfoCommit,cachedCommit;let pkgCommit=readCommitFromPackageJson();if(pkgCommit)return cachedCommit=pkgCommit,cachedCommit;try{let headPath=resolveGitHeadPath(options.cwd??process.cwd());if(!headPath)return cachedCommit=null,cachedCommit;let head=fs.readFileSync(headPath,`utf-8`).trim();if(!head)return cachedCommit=null,cachedCommit;if(head.startsWith(`ref:`)){let ref=head.replace(/^ref:\s*/i,``).trim(),refPath=path.resolve(path.dirname(headPath),ref);return cachedCommit=formatCommit(fs.readFileSync(refPath,`utf-8`).trim()),cachedCommit}return cachedCommit=formatCommit(head),cachedCommit}catch{return cachedCommit=null,cachedCommit}},formatTokenCount=formatTokenCount$2;function resolveRuntimeLabel(args){let sessionKey=args.sessionKey?.trim();if(args.config&&sessionKey){let runtimeStatus=resolveSandboxRuntimeStatus({cfg:args.config,sessionKey}),sandboxMode=runtimeStatus.mode??`off`;return sandboxMode===`off`?`direct`:`${runtimeStatus.sandboxed?`docker`:sessionKey?`direct`:`unknown`}/${sandboxMode}`}let sandboxMode=args.agent?.sandbox?.mode??`off`;return sandboxMode===`off`?`direct`:`${sessionKey&&(sandboxMode===`all`||(args.config?resolveSandboxRuntimeStatus({cfg:args.config,sessionKey}).sandboxed:sessionKey!==resolveMainSessionKey({session:{scope:args.sessionScope??`per-sender`}}).trim()))?`docker`:sessionKey?`direct`:`unknown`}/${sandboxMode}`}const formatTokens=(total,contextTokens)=>{let ctx=contextTokens??null;if(total==null)return`?/${ctx?formatTokenCount(ctx):`?`}`;let pct=ctx?Math.min(999,Math.round(total/ctx*100)):null;return`${formatTokenCount(total)}/${ctx?formatTokenCount(ctx):`?`}${pct===null?``:` (${pct}%)`}`},formatContextUsageShort=(total,contextTokens)=>`Context ${formatTokens(total,contextTokens??null)}`,formatQueueDetails=queue=>{if(!queue)return``;let depth=typeof queue.depth==`number`?`depth ${queue.depth}`:null;if(!queue.showDetails)return depth?` (${depth})`:``;let detailParts=[];if(depth&&detailParts.push(depth),typeof queue.debounceMs==`number`){let ms=Math.max(0,Math.round(queue.debounceMs)),label=ms>=1e3?`${ms%1e3==0?ms/1e3:(ms/1e3).toFixed(1)}s`:`${ms}ms`;detailParts.push(`debounce ${label}`)}return typeof queue.cap==`number`&&detailParts.push(`cap ${queue.cap}`),queue.dropPolicy&&detailParts.push(`drop ${queue.dropPolicy}`),detailParts.length?` (${detailParts.join(` · `)})`:``},readUsageFromSessionLog=(sessionId,sessionEntry,agentId,sessionKey,storePath)=>{if(!sessionId)return;let logPath;try{logPath=resolveSessionFilePath(sessionId,sessionEntry,resolveSessionFilePathOptions({agentId:agentId??(sessionKey?resolveAgentIdFromSessionKey(sessionKey):void 0),storePath}))}catch{return}if(fs.existsSync(logPath))try{let lines=fs.readFileSync(logPath,`utf-8`).split(/\n+/),input=0,output=0,promptTokens=0,model,lastUsage;for(let line of lines)if(line.trim())try{let parsed=JSON.parse(line),usage=normalizeUsage(parsed.message?.usage??parsed.usage);usage&&(lastUsage=usage),model=parsed.message?.model??parsed.model??model}catch{}if(!lastUsage)return;input=lastUsage.input??0,output=lastUsage.output??0,promptTokens=derivePromptTokens(lastUsage)??lastUsage.total??input+output;let total=lastUsage.total??promptTokens+output;return promptTokens===0&&total===0?void 0:{input,output,promptTokens,total,model}}catch{return}},formatUsagePair=(input,output)=>input==null&&output==null?null:`🧮 Tokens: ${typeof input==`number`?formatTokenCount(input):`?`} in / ${typeof output==`number`?formatTokenCount(output):`?`} out`,formatMediaUnderstandingLine=decisions=>{if(!decisions||decisions.length===0)return null;let parts=decisions.map(decision=>{let count=decision.attachments.length,countLabel=count>1?` x${count}`:``;if(decision.outcome===`success`){let chosen=decision.attachments.find(entry=>entry.chosen)?.chosen,provider=chosen?.provider?.trim(),model=chosen?.model?.trim(),modelLabel=provider?model?`${provider}/${model}`:provider:null;return`${decision.capability}${countLabel} ok${modelLabel?` (${modelLabel})`:``}`}if(decision.outcome===`no-attachment`)return`${decision.capability} none`;if(decision.outcome===`disabled`)return`${decision.capability} off`;if(decision.outcome===`scope-deny`)return`${decision.capability} denied`;if(decision.outcome===`skipped`){let reason=decision.attachments.flatMap(entry=>entry.attempts.map(attempt=>attempt.reason).filter(Boolean)).find(Boolean),shortReason=reason?reason.split(`:`)[0]?.trim():void 0;return`${decision.capability} skipped${shortReason?` (${shortReason})`:``}`}return null}).filter(part=>part!=null);return parts.length===0||parts.every(part=>part.endsWith(` none`))?null:`📎 Media: ${parts.join(` · `)}`},formatVoiceModeLine=(config,sessionEntry)=>{if(!config)return null;let ttsConfig=resolveTtsConfig(config),prefsPath=resolveTtsPrefsPath(ttsConfig),autoMode=resolveTtsAutoMode({config:ttsConfig,prefsPath,sessionAuto:sessionEntry?.ttsAuto});return autoMode===`off`?null:`🔊 Voice: ${autoMode} · provider=${getTtsProvider(ttsConfig,prefsPath)} · limit=${getTtsMaxLength(prefsPath)} · summary=${isSummarizationEnabled(prefsPath)?`on`:`off`}`};async function buildStatusMessage(args){let now=args.now??Date.now(),entry=args.sessionEntry,resolved=resolveConfiguredModelRef({cfg:{agents:{defaults:args.agent??{}}},defaultProvider:DEFAULT_PROVIDER,defaultModel:DEFAULT_MODEL}),provider=entry?.providerOverride??resolved.provider??DEFAULT_PROVIDER,model=entry?.modelOverride??resolved.model??DEFAULT_MODEL,contextTokens=entry?.contextTokens??args.agent?.contextTokens??lookupContextTokens(model)??DEFAULT_CONTEXT_TOKENS,inputTokens=entry?.inputTokens,outputTokens=entry?.outputTokens,totalTokens=entry?.totalTokens??(entry?.inputTokens??0)+(entry?.outputTokens??0);if(args.includeTranscriptUsage){let logUsage=readUsageFromSessionLog(entry?.sessionId,entry,args.agentId,args.sessionKey,args.sessionStorePath);if(logUsage){let candidate=logUsage.promptTokens||logUsage.total;(!totalTokens||totalTokens===0||candidate>totalTokens)&&(totalTokens=candidate),model||=logUsage.model??model,!contextTokens&&logUsage.model&&(contextTokens=lookupContextTokens(logUsage.model)??contextTokens),(!inputTokens||inputTokens===0)&&(inputTokens=logUsage.input),(!outputTokens||outputTokens===0)&&(outputTokens=logUsage.output)}}let thinkLevel=args.resolvedThink??args.agent?.thinkingDefault??`off`,verboseLevel=args.resolvedVerbose??args.agent?.verboseDefault??`on`,reasoningLevel=args.resolvedReasoning??`off`,elevatedLevel=args.resolvedElevated??args.sessionEntry?.elevatedLevel??args.agent?.elevatedDefault??`on`,runtime={label:resolveRuntimeLabel(args)},updatedAt=entry?.updatedAt,sessionLine=[`Session: ${args.sessionKey??`unknown`}`,typeof updatedAt==`number`?`updated ${formatTimeAgo(now-updatedAt)}`:`no activity`].filter(Boolean).join(` • `),groupActivationValue=entry?.chatType===`group`||entry?.chatType===`channel`||args.sessionKey?.includes(`:group:`)||args.sessionKey?.includes(`:channel:`)?args.groupActivation??entry?.groupActivation??`mention`:void 0,contextLine=[`Context: ${formatTokens(totalTokens,contextTokens??null)}`,`🧹 Compactions: ${entry?.compactionCount??0}`].filter(Boolean).join(` · `),queueMode=args.queue?.mode??`unknown`,queueDetails=formatQueueDetails(args.queue),verboseLabel=verboseLevel===`full`?`verbose:full`:verboseLevel===`on`?`verbose`:null,elevatedLabel=elevatedLevel&&elevatedLevel!==`off`?elevatedLevel===`on`?`elevated`:`elevated:${elevatedLevel}`:null,optionsLine=[`Runtime: ${runtime.label}`,`Think: ${thinkLevel}`,verboseLabel,reasoningLevel===`off`?null:`Reasoning: ${reasoningLevel}`,elevatedLabel].filter(Boolean).join(` · `),activationLine=[groupActivationValue?`👥 Activation: ${groupActivationValue}`:null,`🪢 Queue: ${queueMode}${queueDetails}`].filter(Boolean).join(` · `),authMode=await resolveModelAuthMode(provider,args.config),authLabelValue=args.modelAuth??(authMode&&authMode!==`unknown`?authMode:void 0),showCost=authLabelValue===`api-key`||authLabelValue===`mixed`,costConfig=showCost?resolveModelCostConfig({provider,model,config:args.config}):void 0,hasUsage=typeof inputTokens==`number`||typeof outputTokens==`number`,cost=showCost&&hasUsage?estimateUsageCost({usage:{input:inputTokens??void 0,output:outputTokens??void 0},cost:costConfig}):void 0,costLabel=showCost&&hasUsage?formatUsd(cost):void 0,modelLine=`🧠 Model: ${model?`${provider}/${model}`:`unknown`}${authLabelValue?` · 🔑 ${authLabelValue}`:``}`,commit=resolveCommitHash(),versionLine=`🤖 BuilderForceAgents ${VERSION}${commit?` (${commit})`:``}`,usagePair=formatUsagePair(inputTokens,outputTokens),costLine=costLabel?`💵 Cost: ${costLabel}`:null,usageCostLine=usagePair&&costLine?`${usagePair} · ${costLine}`:usagePair??costLine,mediaLine=formatMediaUnderstandingLine(args.mediaDecisions),voiceLine=formatVoiceModeLine(args.config,args.sessionEntry);return[versionLine,args.timeLine,modelLine,usageCostLine,`📚 ${contextLine}`,mediaLine,args.usageLine,`🧵 ${sessionLine}`,args.subagentsLine,`⚙️ ${optionsLine}`,voiceLine,activationLine].filter(Boolean).join(`
89
+ `),combinedMentioned=entries.some(entry=>!!entry.opts.wasMentioned),prepared=await prepareSlackMessage({ctx,account,message:{...last.message,text:combinedText},opts:{...last.opts,wasMentioned:combinedMentioned||last.opts.wasMentioned}});if(prepared){if(entries.length>1){let ids=entries.map(entry=>entry.message.ts).filter(Boolean);ids.length>0&&(prepared.ctxPayload.MessageSids=ids,prepared.ctxPayload.MessageSidFirst=ids[0],prepared.ctxPayload.MessageSidLast=ids[ids.length-1])}await dispatchPreparedSlackMessage(prepared)}},onError:err=>{ctx.runtime.error?.(`slack inbound debounce flush failed: ${String(err)}`)}});return async(message,opts)=>{if(opts.source===`message`&&message.type!==`message`||opts.source===`message`&&message.subtype&&message.subtype!==`file_share`&&message.subtype!==`bot_message`||ctx.markMessageSeen(message.channel,message.ts))return;let resolvedMessage=await threadTsResolver.resolve({message,source:opts.source});await debouncer.enqueue({message:resolvedMessage,opts})}}const SLACK_COMMAND_ARG_ACTION_ID=`builderforce_cmdarg`,SLACK_COMMAND_ARG_VALUE_PREFIX=`cmdarg`,SLACK_COMMAND_ARG_EXTERNAL_PREFIX=`builderforce_cmdarg_ext:`,slackExternalArgMenuStore=new Map;function truncatePlainText(value,max){let trimmed=value.trim();return trimmed.length<=max?trimmed:max<=1?trimmed.slice(0,max):`${trimmed.slice(0,max-1)}…`}function escapeSlackMrkdwn(value){return value.replaceAll(`\\`,`\\\\`).replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replace(/([*_`~])/g,`\\$1`)}function buildSlackArgMenuConfirm(params){return{title:{type:`plain_text`,text:`Confirm selection`},text:{type:`mrkdwn`,text:`Run */${escapeSlackMrkdwn(params.command)}* with *${escapeSlackMrkdwn(params.arg)}* set to this value?`},confirm:{type:`plain_text`,text:`Run command`},deny:{type:`plain_text`,text:`Cancel`}}}function pruneSlackExternalArgMenuStore(now=Date.now()){for(let[token,entry]of slackExternalArgMenuStore.entries())entry.expiresAt<=now&&slackExternalArgMenuStore.delete(token)}function storeSlackExternalArgMenu(params){pruneSlackExternalArgMenuStore();let token=`${Date.now().toString(36)}${Math.random().toString(36).slice(2,10)}`;return slackExternalArgMenuStore.set(token,{choices:params.choices,userId:params.userId,expiresAt:Date.now()+6e5}),token}function readSlackExternalArgMenuToken(raw){if(typeof raw!=`string`||!raw.startsWith(SLACK_COMMAND_ARG_EXTERNAL_PREFIX))return;let token=raw.slice(24).trim();return token.length>0?token:void 0}function encodeSlackCommandArgValue(parts){return[SLACK_COMMAND_ARG_VALUE_PREFIX,encodeURIComponent(parts.command),encodeURIComponent(parts.arg),encodeURIComponent(parts.value),encodeURIComponent(parts.userId)].join(`|`)}function parseSlackCommandArgValue(raw){if(!raw)return null;let parts=raw.split(`|`);if(parts.length!==5||parts[0]!==SLACK_COMMAND_ARG_VALUE_PREFIX)return null;let[,command,arg,value,userId]=parts;if(!command||!arg||!value||!userId)return null;let decode=text=>{try{return decodeURIComponent(text)}catch{return null}},decodedCommand=decode(command),decodedArg=decode(arg),decodedValue=decode(value),decodedUserId=decode(userId);return!decodedCommand||!decodedArg||!decodedValue||!decodedUserId?null:{command:decodedCommand,arg:decodedArg,value:decodedValue,userId:decodedUserId}}function buildSlackCommandArgMenuBlocks(params){let encodedChoices=params.choices.map(choice=>({label:choice.label,value:encodeSlackCommandArgValue({command:params.command,arg:params.arg,value:choice.value,userId:params.userId})})),canUseStaticSelect=encodedChoices.every(choice=>choice.value.length<=75),canUseOverflow=canUseStaticSelect&&encodedChoices.length>=3&&encodedChoices.length<=5,canUseExternalSelect=params.supportsExternalSelect&&canUseStaticSelect&&encodedChoices.length>100,rows=canUseOverflow?[{type:`actions`,elements:[{type:`overflow`,action_id:SLACK_COMMAND_ARG_ACTION_ID,confirm:buildSlackArgMenuConfirm({command:params.command,arg:params.arg}),options:encodedChoices.map(choice=>({text:{type:`plain_text`,text:choice.label.slice(0,75)},value:choice.value}))}]}]:canUseExternalSelect?[{type:`actions`,block_id:`${SLACK_COMMAND_ARG_EXTERNAL_PREFIX}${params.createExternalMenuToken(encodedChoices)}`,elements:[{type:`external_select`,action_id:SLACK_COMMAND_ARG_ACTION_ID,confirm:buildSlackArgMenuConfirm({command:params.command,arg:params.arg}),min_query_length:0,placeholder:{type:`plain_text`,text:`Search ${params.arg}`}}]}]:encodedChoices.length<=5||!canUseStaticSelect?chunkItems(encodedChoices,5).map(choices=>({type:`actions`,elements:choices.map(choice=>({type:`button`,action_id:SLACK_COMMAND_ARG_ACTION_ID,text:{type:`plain_text`,text:choice.label},value:choice.value,confirm:buildSlackArgMenuConfirm({command:params.command,arg:params.arg})}))})):chunkItems(encodedChoices,100).map((choices,index)=>({type:`actions`,elements:[{type:`static_select`,action_id:SLACK_COMMAND_ARG_ACTION_ID,confirm:buildSlackArgMenuConfirm({command:params.command,arg:params.arg}),placeholder:{type:`plain_text`,text:index===0?`Choose ${params.arg}`:`Choose ${params.arg} (${index+1})`},options:choices.map(choice=>({text:{type:`plain_text`,text:choice.label.slice(0,75)},value:choice.value}))}]})),headerText=truncatePlainText(`/${params.command}: choose ${params.arg}`,150),sectionText=truncatePlainText(params.title,3e3),contextText=truncatePlainText(`Select one option to continue /${params.command} (${params.arg})`,3e3);return[{type:`header`,text:{type:`plain_text`,text:headerText}},{type:`section`,text:{type:`mrkdwn`,text:sectionText}},{type:`context`,elements:[{type:`mrkdwn`,text:contextText}]},...rows]}async function registerSlackMonitorSlashCommands(params){let{ctx,account}=params,cfg=ctx.cfg,runtime=ctx.runtime,supportsInteractiveArgMenus=typeof ctx.app.action==`function`,supportsExternalArgMenus=typeof ctx.app.options==`function`,slashCommand=resolveSlackSlashCommandConfig(ctx.slashCommand??account.config.slashCommand),handleSlashCommand=async p=>{let{command,ack,respond,prompt,commandArgs,commandDefinition}=p;try{if(!prompt.trim()){await ack({text:`Message required.`,response_type:`ephemeral`});return}if(await ack(),ctx.botUserId&&command.user_id===ctx.botUserId)return;let channelInfo=await ctx.resolveChannelName(command.channel_id),channelType=normalizeSlackChannelType(channelInfo?.type??(command.channel_name===`directmessage`?`im`:void 0),command.channel_id),isDirectMessage=channelType===`im`,isGroupDm=channelType===`mpim`,isRoom=channelType===`channel`||channelType===`group`,isRoomish=isRoom||isGroupDm;if(!ctx.isChannelAllowed({channelId:command.channel_id,channelName:channelInfo?.name,channelType})){await respond({text:`This channel is not allowed.`,response_type:`ephemeral`});return}let storeAllowFrom=await readChannelAllowFromStore(`slack`).catch(()=>[]),effectiveAllowFromLower=normalizeAllowListLower(normalizeAllowList([...ctx.allowFrom,...storeAllowFrom])),commandAuthorized=!1,channelConfig=null;if(isDirectMessage){if(!ctx.dmEnabled||ctx.dmPolicy===`disabled`){await respond({text:`Slack DMs are disabled.`,response_type:`ephemeral`});return}if(ctx.dmPolicy!==`open`){let senderName=(await ctx.resolveUserName(command.user_id))?.name??void 0,allowMatch=resolveSlackAllowListMatch({allowList:effectiveAllowFromLower,id:command.user_id,name:senderName}),allowMatchMeta=formatAllowlistMatchMeta(allowMatch);if(!allowMatch.allowed){if(ctx.dmPolicy===`pairing`){let{code,created}=await upsertChannelPairingRequest({channel:`slack`,id:command.user_id,meta:{name:senderName}});created&&(logVerbose(`slack pairing request sender=${command.user_id} name=${senderName??`unknown`} (${allowMatchMeta})`),await respond({text:buildPairingReply({channel:`slack`,idLine:`Your Slack user id: ${command.user_id}`,code}),response_type:`ephemeral`}))}else logVerbose(`slack: blocked slash sender ${command.user_id} (dmPolicy=${ctx.dmPolicy}, ${allowMatchMeta})`),await respond({text:`You are not authorized to use this command.`,response_type:`ephemeral`});return}}}if(isRoom&&(channelConfig=resolveSlackChannelConfig({channelId:command.channel_id,channelName:channelInfo?.name,channels:ctx.channelsConfig,defaultRequireMention:ctx.defaultRequireMention}),ctx.useAccessGroups)){let channelAllowlistConfigured=!!ctx.channelsConfig&&Object.keys(ctx.channelsConfig??{}).length>0,channelAllowed=channelConfig?.allowed!==!1;if(!isSlackChannelAllowedByPolicy({groupPolicy:ctx.groupPolicy,channelAllowlistConfigured,channelAllowed})){await respond({text:`This channel is not allowed.`,response_type:`ephemeral`});return}let hasExplicitConfig=!!channelConfig?.matchSource;if(!channelAllowed&&(ctx.groupPolicy!==`open`||hasExplicitConfig)){await respond({text:`This channel is not allowed.`,response_type:`ephemeral`});return}}let senderName=(await ctx.resolveUserName(command.user_id))?.name??command.user_name??command.user_id,channelUsersAllowlistConfigured=isRoom&&Array.isArray(channelConfig?.users)&&channelConfig.users.length>0,channelUserAllowed=channelUsersAllowlistConfigured?resolveSlackUserAllowed({allowList:channelConfig?.users,userId:command.user_id,userName:senderName}):!1;if(channelUsersAllowlistConfigured&&!channelUserAllowed){await respond({text:`You are not authorized to use this command here.`,response_type:`ephemeral`});return}let ownerAllowed=resolveSlackAllowListMatch({allowList:effectiveAllowFromLower,id:command.user_id,name:senderName}).allowed;if(commandAuthorized=resolveCommandAuthorizedFromAuthorizers({useAccessGroups:ctx.useAccessGroups,authorizers:[{configured:effectiveAllowFromLower.length>0,allowed:ownerAllowed}],modeWhenAccessGroupsOff:`configured`}),isRoomish&&(commandAuthorized=resolveCommandAuthorizedFromAuthorizers({useAccessGroups:ctx.useAccessGroups,authorizers:[{configured:effectiveAllowFromLower.length>0,allowed:ownerAllowed},{configured:channelUsersAllowlistConfigured,allowed:channelUserAllowed}],modeWhenAccessGroupsOff:`configured`}),ctx.useAccessGroups&&!commandAuthorized)){await respond({text:`You are not authorized to use this command.`,response_type:`ephemeral`});return}if(commandDefinition&&supportsInteractiveArgMenus){let menu=resolveCommandArgMenu({command:commandDefinition,args:commandArgs,cfg});if(menu){let commandLabel=commandDefinition.nativeName??commandDefinition.key,title=menu.title??`Choose ${menu.arg.description||menu.arg.name} for /${commandLabel}.`;await respond({text:title,blocks:buildSlackCommandArgMenuBlocks({title,command:commandLabel,arg:menu.arg.name,choices:menu.choices,userId:command.user_id,supportsExternalSelect:supportsExternalArgMenus,createExternalMenuToken:choices=>storeSlackExternalArgMenu({choices,userId:command.user_id})}),response_type:`ephemeral`});return}}let channelName=channelInfo?.name,roomLabel=channelName?`#${channelName}`:`#${command.channel_id}`,[{resolveAgentRoute},{finalizeInboundContext},{dispatchReplyWithDispatcher}]=await Promise.all([import(`./resolve-route-Bj4Vlrzh.js`),import(`./inbound-context-a0yIq19D.js`),import(`./provider-dispatcher-kL8Yl9XU.js`)]),[{resolveConversationLabel},{createReplyPrefixOptions}]=await Promise.all([import(`./conversation-label-C40UwLZq.js`),import(`./reply-prefix-YLHlrWfw.js`)]),route=resolveAgentRoute({cfg,channel:`slack`,accountId:account.accountId,teamId:ctx.teamId||void 0,peer:{kind:isDirectMessage?`direct`:isRoom?`channel`:`group`,id:isDirectMessage?command.user_id:command.channel_id}}),{untrustedChannelMetadata,groupSystemPrompt}=resolveSlackRoomContextHints({isRoomish,channelInfo,channelConfig}),ctxPayload=finalizeInboundContext({Body:prompt,BodyForAgent:prompt,RawBody:prompt,CommandBody:prompt,CommandArgs:commandArgs,From:isDirectMessage?`slack:${command.user_id}`:isRoom?`slack:channel:${command.channel_id}`:`slack:group:${command.channel_id}`,To:`slash:${command.user_id}`,ChatType:isDirectMessage?`direct`:`channel`,ConversationLabel:resolveConversationLabel({ChatType:isDirectMessage?`direct`:`channel`,SenderName:senderName,GroupSubject:isRoomish?roomLabel:void 0,From:isDirectMessage?`slack:${command.user_id}`:isRoom?`slack:channel:${command.channel_id}`:`slack:group:${command.channel_id}`})??(isDirectMessage?senderName:roomLabel),GroupSubject:isRoomish?roomLabel:void 0,GroupSystemPrompt:isRoomish?groupSystemPrompt:void 0,UntrustedContext:untrustedChannelMetadata?[untrustedChannelMetadata]:void 0,SenderName:senderName,SenderId:command.user_id,Provider:`slack`,Surface:`slack`,WasMentioned:!0,MessageSid:command.trigger_id,Timestamp:Date.now(),SessionKey:`agent:${route.agentId}:${slashCommand.sessionPrefix}:${command.user_id}`.toLowerCase(),CommandTargetSessionKey:route.sessionKey,AccountId:route.accountId,CommandSource:`native`,CommandAuthorized:commandAuthorized,OriginatingChannel:`slack`,OriginatingTo:`user:${command.user_id}`}),{onModelSelected,...prefixOptions}=createReplyPrefixOptions({cfg,agentId:route.agentId,channel:`slack`,accountId:route.accountId}),deliverSlashPayloads=async replies=>{let[{deliverSlackSlashReplies},{resolveChunkMode},{resolveMarkdownTableMode}]=await Promise.all([import(`./replies-DFfYfMhc.js`),import(`./chunk-OGAjqr5A.js`),import(`./markdown-tables-mfuWd97r.js`)]);await deliverSlackSlashReplies({replies,respond,ephemeral:slashCommand.ephemeral,textLimit:ctx.textLimit,chunkMode:resolveChunkMode(cfg,`slack`,route.accountId),tableMode:resolveMarkdownTableMode({cfg,channel:`slack`,accountId:route.accountId})})},{counts}=await dispatchReplyWithDispatcher({ctx:ctxPayload,cfg,dispatcherOptions:{...prefixOptions,deliver:async payload=>deliverSlashPayloads([payload]),onError:(err,info)=>{runtime.error?.(danger(`slack slash ${info.kind} reply failed: ${String(err)}`))}},replyOptions:{skillFilter:channelConfig?.skills,onModelSelected}});counts.final+counts.tool+counts.block===0&&await deliverSlashPayloads([])}catch(err){runtime.error?.(danger(`slack slash handler failed: ${String(err)}`)),await respond({text:`Sorry, something went wrong handling that command.`,response_type:`ephemeral`})}},nativeEnabled=resolveNativeCommandsEnabled({providerId:`slack`,providerSetting:account.config.commands?.native,globalSetting:cfg.commands?.native}),nativeSkillsEnabled=resolveNativeSkillsEnabled({providerId:`slack`,providerSetting:account.config.commands?.nativeSkills,globalSetting:cfg.commands?.nativeSkills}),nativeCommands=[];if(nativeEnabled&&(nativeCommands=listNativeCommandSpecsForConfig(cfg,{skillCommands:nativeSkillsEnabled?listSkillCommandsForAgents({cfg}):[],provider:`slack`})),nativeCommands.length>0)for(let command of nativeCommands)ctx.app.command(`/${command.name}`,async({command:cmd,ack,respond})=>{let commandDefinition=findCommandByNativeName(command.name,`slack`),rawText=cmd.text?.trim()??``,commandArgs=commandDefinition?parseCommandArgs(commandDefinition,rawText):rawText?{raw:rawText}:void 0;await handleSlashCommand({command:cmd,ack,respond,prompt:commandDefinition?buildCommandTextFromArgs(commandDefinition,commandArgs):rawText?`/${command.name} ${rawText}`:`/${command.name}`,commandArgs,commandDefinition:commandDefinition??void 0})});else slashCommand.enabled?ctx.app.command(buildSlackSlashCommandMatcher(slashCommand.name),async({command,ack,respond})=>{await handleSlashCommand({command,ack,respond,prompt:command.text?.trim()??``})}):logVerbose(`slack: slash commands disabled`);nativeCommands.length===0||!supportsInteractiveArgMenus||((()=>{let optionsHandler=ctx.app.options;typeof optionsHandler==`function`&&optionsHandler(SLACK_COMMAND_ARG_ACTION_ID,async({ack,body})=>{let typedBody=body;pruneSlackExternalArgMenuStore();let token=readSlackExternalArgMenuToken(typedBody.actions?.[0]?.block_id??typedBody.block_id);if(!token){await ack({options:[]});return}let entry=slackExternalArgMenuStore.get(token);if(!entry){await ack({options:[]});return}if(typedBody.user?.id&&typedBody.user.id!==entry.userId){await ack({options:[]});return}let query=typedBody.value?.trim().toLowerCase()??``;await ack({options:entry.choices.filter(choice=>!query||choice.label.toLowerCase().includes(query)).slice(0,100).map(choice=>({text:{type:`plain_text`,text:choice.label.slice(0,75)},value:choice.value}))})})})(),(actionId=>{ctx.app.action(actionId,async args=>{let{ack,body,respond}=args,action=args.action;await ack();let respondFn=respond??(async payload=>{!body.channel?.id||!body.user?.id||await ctx.app.client.chat.postEphemeral({token:ctx.botToken,channel:body.channel.id,user:body.user.id,text:payload.text,blocks:payload.blocks})}),parsed=parseSlackCommandArgValue(action?.value??action?.selected_option?.value);if(!parsed){await respondFn({text:`Sorry, that button is no longer valid.`,response_type:`ephemeral`});return}if(body.user?.id&&parsed.userId!==body.user.id){await respondFn({text:`That menu is for another user.`,response_type:`ephemeral`});return}let commandDefinition=findCommandByNativeName(parsed.command,`slack`),commandArgs={values:{[parsed.arg]:parsed.value}},prompt=commandDefinition?buildCommandTextFromArgs(commandDefinition,commandArgs):`/${parsed.command} ${parsed.value}`,user=body.user,userName=user&&`name`in user&&user.name?user.name:user&&`username`in user&&user.username?user.username:user?.id??``,triggerId=`trigger_id`in body?body.trigger_id:void 0;await handleSlashCommand({command:{user_id:user?.id??``,user_name:userName,channel_id:body.channel?.id??``,channel_name:body.channel?.name??body.channel?.id??``,trigger_id:triggerId??String(Date.now())},ack:async()=>{},respond:respondFn,prompt,commandArgs,commandDefinition:commandDefinition??void 0})})})(SLACK_COMMAND_ARG_ACTION_ID))}const slackBoltModule=SlackBolt,{App,HTTPReceiver}=(slackBoltModule.App?slackBoltModule:slackBoltModule.default)??slackBoltModule;function parseApiAppIdFromAppToken(raw){let token=raw?.trim();if(token)return/^xapp-\d-([a-z0-9]+)-/i.exec(token)?.[1]?.toUpperCase()}async function monitorSlackProvider(opts={}){let cfg=opts.config??loadConfig(),account=resolveSlackAccount({cfg,accountId:opts.accountId}),historyLimit=Math.max(0,account.config.historyLimit??cfg.messages?.groupChat?.historyLimit??50),sessionCfg=cfg.session,sessionScope=sessionCfg?.scope??`per-sender`,mainKey=normalizeMainKey(sessionCfg?.mainKey),slackMode=opts.mode??account.config.mode??`socket`,slackWebhookPath=normalizeSlackWebhookPath(account.config.webhookPath),signingSecret=account.config.signingSecret?.trim(),botToken=resolveSlackBotToken(opts.botToken??account.botToken),appToken=resolveSlackAppToken(opts.appToken??account.appToken);if(!botToken||slackMode!==`http`&&!appToken){let missing=slackMode===`http`?`Slack bot token missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken or SLACK_BOT_TOKEN for default).`:`Slack bot + app tokens missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken/appToken or SLACK_BOT_TOKEN/SLACK_APP_TOKEN for default).`;throw Error(missing)}if(slackMode===`http`&&!signingSecret)throw Error(`Slack signing secret missing for account "${account.accountId}" (set channels.slack.signingSecret or channels.slack.accounts.${account.accountId}.signingSecret).`);let runtime=opts.runtime??createNonExitingRuntime(),slackCfg=account.config,dmConfig=slackCfg.dm,dmEnabled=dmConfig?.enabled??!0,dmPolicy=slackCfg.dmPolicy??dmConfig?.policy??`pairing`,allowFrom=slackCfg.allowFrom??dmConfig?.allowFrom,groupDmEnabled=dmConfig?.groupEnabled??!1,groupDmChannels=dmConfig?.groupChannels,channelsConfig=slackCfg.channels,defaultGroupPolicy=cfg.channels?.defaults?.groupPolicy,groupPolicy=slackCfg.groupPolicy??defaultGroupPolicy??`open`;slackCfg.groupPolicy===void 0&&slackCfg.channels===void 0&&defaultGroupPolicy===void 0&&groupPolicy===`open`&&runtime.log?.(warn(`slack: groupPolicy defaults to "open" when channels.slack is missing; set channels.slack.groupPolicy (or channels.defaults.groupPolicy) or add channels.slack.channels to restrict access.`));let resolveToken=slackCfg.userToken?.trim()||botToken,useAccessGroups=cfg.commands?.useAccessGroups!==!1,reactionMode=slackCfg.reactionNotifications??`own`,reactionAllowlist=slackCfg.reactionAllowlist??[],replyToMode=slackCfg.replyToMode??`all`,threadHistoryScope=slackCfg.thread?.historyScope??`thread`,threadInheritParent=slackCfg.thread?.inheritParent??!1,slashCommand=resolveSlackSlashCommandConfig(opts.slashCommand??slackCfg.slashCommand),textLimit=resolveTextChunkLimit(cfg,`slack`,account.accountId),ackReactionScope=cfg.messages?.ackReactionScope??`group-mentions`,mediaMaxBytes=(opts.mediaMaxMb??slackCfg.mediaMaxMb??20)*1024*1024,removeAckAfterReply=cfg.messages?.removeAckAfterReply??!1,receiver=slackMode===`http`?new HTTPReceiver({signingSecret:signingSecret??``,endpoints:slackWebhookPath}):null,clientOptions=resolveSlackWebClientOptions(),app=new App(slackMode===`socket`?{token:botToken,appToken,socketMode:!0,clientOptions}:{token:botToken,receiver:receiver??void 0,clientOptions}),slackHttpHandler=slackMode===`http`&&receiver?async(req,res)=>{let guard=installRequestBodyLimitGuard(req,res,{maxBytes:1048576,timeoutMs:3e4,responseFormat:`text`});if(!guard.isTripped())try{await Promise.resolve(receiver.requestListener(req,res))}catch(err){if(!guard.isTripped())throw err}finally{guard.dispose()}}:null,unregisterHttpHandler=null,botUserId=``,teamId=``,apiAppId=``,expectedApiAppIdFromAppToken=parseApiAppIdFromAppToken(appToken);try{let auth=await app.client.auth.test({token:botToken});botUserId=auth.user_id??``,teamId=auth.team_id??``,apiAppId=auth.api_app_id??``}catch{}apiAppId&&expectedApiAppIdFromAppToken&&apiAppId!==expectedApiAppIdFromAppToken&&runtime.error?.(`slack token mismatch: bot token api_app_id=${apiAppId} but app token looks like api_app_id=${expectedApiAppIdFromAppToken}`);let ctx=createSlackMonitorContext({cfg,accountId:account.accountId,botToken,app,runtime,botUserId,teamId,apiAppId,historyLimit,sessionScope,mainKey,dmEnabled,dmPolicy,allowFrom,groupDmEnabled,groupDmChannels,defaultRequireMention:slackCfg.requireMention,channelsConfig,groupPolicy,useAccessGroups,reactionMode,reactionAllowlist,replyToMode,threadHistoryScope,threadInheritParent,slashCommand,textLimit,ackReactionScope,mediaMaxBytes,removeAckAfterReply});registerSlackMonitorEvents({ctx,account,handleSlackMessage:createSlackMessageHandler({ctx,account})}),await registerSlackMonitorSlashCommands({ctx,account}),slackMode===`http`&&slackHttpHandler&&(unregisterHttpHandler=registerSlackHttpHandler({path:slackWebhookPath,handler:slackHttpHandler,log:runtime.log,accountId:account.accountId})),resolveToken&&(async()=>{if(opts.abortSignal?.aborted)return;if(channelsConfig&&Object.keys(channelsConfig).length>0)try{let entries=Object.keys(channelsConfig).filter(key=>key!==`*`);if(entries.length>0){let resolved=await resolveSlackChannelAllowlist({token:resolveToken,entries}),nextChannels={...channelsConfig},mapping=[],unresolved=[];for(let entry of resolved){let source=channelsConfig?.[entry.input];if(!source)continue;if(!entry.resolved||!entry.id){unresolved.push(entry.input);continue}mapping.push(`${entry.input}→${entry.id}${entry.archived?` (archived)`:``}`);let existing=nextChannels[entry.id]??{};nextChannels[entry.id]={...source,...existing}}channelsConfig=nextChannels,ctx.channelsConfig=nextChannels,summarizeMapping(`slack channels`,mapping,unresolved,runtime)}}catch(err){runtime.log?.(`slack channel resolve failed; using config entries. ${String(err)}`)}let allowEntries=allowFrom?.filter(entry=>String(entry).trim()&&String(entry).trim()!==`*`)??[];if(allowEntries.length>0)try{let{mapping,unresolved,additions}=buildAllowlistResolutionSummary(await resolveSlackUserAllowlist({token:resolveToken,entries:allowEntries.map(entry=>String(entry))}),{formatResolved:entry=>{let note=entry.note?` (${entry.note})`:``;return`${entry.input}→${entry.id}${note}`}});allowFrom=mergeAllowlist({existing:allowFrom,additions}),ctx.allowFrom=normalizeAllowList(allowFrom),summarizeMapping(`slack users`,mapping,unresolved,runtime)}catch(err){runtime.log?.(`slack user resolve failed; using config entries. ${String(err)}`)}if(channelsConfig&&Object.keys(channelsConfig).length>0){let userEntries=new Set;for(let channel of Object.values(channelsConfig))addAllowlistUserEntriesFromConfigEntry(userEntries,channel);if(userEntries.size>0)try{let{resolvedMap,mapping,unresolved}=buildAllowlistResolutionSummary(await resolveSlackUserAllowlist({token:resolveToken,entries:Array.from(userEntries)})),nextChannels=patchAllowlistUsersInConfigEntries({entries:channelsConfig,resolvedMap});channelsConfig=nextChannels,ctx.channelsConfig=nextChannels,summarizeMapping(`slack channel users`,mapping,unresolved,runtime)}catch(err){runtime.log?.(`slack channel user resolve failed; using config entries. ${String(err)}`)}}})();let stopOnAbort=()=>{opts.abortSignal?.aborted&&slackMode===`socket`&&app.stop()};opts.abortSignal?.addEventListener(`abort`,stopOnAbort,{once:!0});try{if(slackMode===`socket`?(await app.start(),runtime.log?.(`slack socket mode connected`)):runtime.log?.(`slack http mode listening at ${slackWebhookPath}`),opts.abortSignal?.aborted)return;await new Promise(resolve=>{opts.abortSignal?.addEventListener(`abort`,()=>resolve(),{once:!0})})}finally{opts.abortSignal?.removeEventListener(`abort`,stopOnAbort),unregisterHttpHandler?.(),await app.stop().catch(()=>void 0)}}async function probeSlack(token,timeoutMs=2500){let client=createSlackWebClient(token),start=Date.now();try{let result=await withTimeout$2(client.auth.test(),timeoutMs);return result.ok?{ok:!0,status:200,elapsedMs:Date.now()-start,bot:{id:result.user_id??void 0,name:result.user??void 0},team:{id:result.team_id??void 0,name:result.team??void 0}}:{ok:!1,status:200,error:result.error??`unknown`,elapsedMs:Date.now()-start}}catch(err){let message=err instanceof Error?err.message:String(err);return{ok:!1,status:typeof err.status==`number`?err.status:null,error:message,elapsedMs:Date.now()-start}}}function collectTelegramUnmentionedGroupIds(groups){if(!groups||typeof groups!=`object`)return{groupIds:[],unresolvedGroups:0,hasWildcardUnmentionedGroups:!1};let hasWildcardUnmentionedGroups=groups[`*`]?.requireMention===!1&&groups[`*`]?.enabled!==!1,groupIds=[],unresolvedGroups=0;for(let[key,value]of Object.entries(groups)){if(key===`*`||!value||typeof value!=`object`||value.enabled===!1||value.requireMention!==!1)continue;let id=String(key).trim();id&&(/^-?\d+$/.test(id)?groupIds.push(id):unresolvedGroups+=1)}return groupIds.sort((a,b)=>a.localeCompare(b)),{groupIds,unresolvedGroups,hasWildcardUnmentionedGroups}}async function auditTelegramGroupMembership(params){let started=Date.now(),token=params.token?.trim()??``;if(!token||params.groupIds.length===0)return{ok:!0,checkedGroups:0,unresolvedGroups:0,hasWildcardUnmentionedGroups:!1,groups:[],elapsedMs:Date.now()-started};let fetcher=params.proxyUrl?makeProxyFetch(params.proxyUrl):fetch,base=`https://api.telegram.org/bot${token}`,groups=[];for(let chatId of params.groupIds)try{let res=await fetchWithTimeout(`${base}/getChatMember?chat_id=${encodeURIComponent(chatId)}&user_id=${encodeURIComponent(String(params.botId))}`,{},params.timeoutMs,fetcher),json=await res.json();if(!res.ok||!isRecord$1(json)||!json.ok){let desc=isRecord$1(json)&&!json.ok&&typeof json.description==`string`?json.description:`getChatMember failed (${res.status})`;groups.push({chatId,ok:!1,status:null,error:desc,matchKey:chatId,matchSource:`id`});continue}let status=isRecord$1(json.result)?json.result.status??null:null,ok=status===`creator`||status===`administrator`||status===`member`;groups.push({chatId,ok,status,error:ok?null:`bot not in group`,matchKey:chatId,matchSource:`id`})}catch(err){groups.push({chatId,ok:!1,status:null,error:err instanceof Error?err.message:String(err),matchKey:chatId,matchSource:`id`})}return{ok:groups.every(g=>g.ok),checkedGroups:groups.length,unresolvedGroups:0,hasWildcardUnmentionedGroups:!1,groups,elapsedMs:Date.now()-started}}function resolveTelegramAllowedUpdates(){let updates=[...API_CONSTANTS.DEFAULT_UPDATE_TYPES];return updates.includes(`message_reaction`)||updates.push(`message_reaction`),updates.includes(`channel_post`)||updates.push(`channel_post`),updates}function walkUpFrom(startDir,opts,resolveAtDir){let current=path.resolve(startDir),maxDepth=opts.maxDepth??12;for(let i=0;i<maxDepth;i+=1){let resolved=resolveAtDir(current);if(resolved!=null)return resolved;let parent=path.dirname(current);if(parent===current)break;current=parent}return null}function hasGitMarker(repoRoot){let gitPath=path.join(repoRoot,`.git`);try{let stat=fs.statSync(gitPath);return stat.isDirectory()||stat.isFile()}catch{return!1}}function findGitRoot(startDir,opts={}){return walkUpFrom(startDir,opts,repoRoot=>hasGitMarker(repoRoot)?repoRoot:null)}function resolveGitDirFromMarker(repoRoot){let gitPath=path.join(repoRoot,`.git`);try{let stat=fs.statSync(gitPath);if(stat.isDirectory())return gitPath;if(!stat.isFile())return null;let match=fs.readFileSync(gitPath,`utf-8`).match(/gitdir:\s*(.+)/i);return match?.[1]?path.resolve(repoRoot,match[1].trim()):null}catch{return null}}function resolveGitHeadPath(startDir,opts={}){return walkUpFrom(startDir,opts,repoRoot=>{let gitDir=resolveGitDirFromMarker(repoRoot);return gitDir?path.join(gitDir,`HEAD`):null})}const formatCommit=value=>{if(!value)return null;let trimmed=value.trim();return trimmed?trimmed.length>7?trimmed.slice(0,7):trimmed:null};let cachedCommit;const readCommitFromPackageJson=()=>{try{let pkg=createRequire(import.meta.url)(`../../package.json`);return formatCommit(pkg.gitHead??pkg.githead??null)}catch{return null}},readCommitFromBuildInfo=()=>{try{let require=createRequire(import.meta.url);for(let candidate of[`../build-info.json`,`./build-info.json`])try{let formatted=formatCommit(require(candidate).commit??null);if(formatted)return formatted}catch{}return null}catch{return null}},resolveCommitHash=(options={})=>{if(cachedCommit!==void 0)return cachedCommit;let env=options.env??process.env,normalized=formatCommit(env.GIT_COMMIT?.trim()||env.GIT_SHA?.trim());if(normalized)return cachedCommit=normalized,cachedCommit;let buildInfoCommit=readCommitFromBuildInfo();if(buildInfoCommit)return cachedCommit=buildInfoCommit,cachedCommit;let pkgCommit=readCommitFromPackageJson();if(pkgCommit)return cachedCommit=pkgCommit,cachedCommit;try{let headPath=resolveGitHeadPath(options.cwd??process.cwd());if(!headPath)return cachedCommit=null,cachedCommit;let head=fs.readFileSync(headPath,`utf-8`).trim();if(!head)return cachedCommit=null,cachedCommit;if(head.startsWith(`ref:`)){let ref=head.replace(/^ref:\s*/i,``).trim(),refPath=path.resolve(path.dirname(headPath),ref);return cachedCommit=formatCommit(fs.readFileSync(refPath,`utf-8`).trim()),cachedCommit}return cachedCommit=formatCommit(head),cachedCommit}catch{return cachedCommit=null,cachedCommit}},formatTokenCount=formatTokenCount$2;function resolveRuntimeLabel(args){let sessionKey=args.sessionKey?.trim();if(args.config&&sessionKey){let runtimeStatus=resolveSandboxRuntimeStatus({cfg:args.config,sessionKey}),sandboxMode=runtimeStatus.mode??`off`;return sandboxMode===`off`?`direct`:`${runtimeStatus.sandboxed?`docker`:sessionKey?`direct`:`unknown`}/${sandboxMode}`}let sandboxMode=args.agent?.sandbox?.mode??`off`;return sandboxMode===`off`?`direct`:`${sessionKey&&(sandboxMode===`all`||(args.config?resolveSandboxRuntimeStatus({cfg:args.config,sessionKey}).sandboxed:sessionKey!==resolveMainSessionKey({session:{scope:args.sessionScope??`per-sender`}}).trim()))?`docker`:sessionKey?`direct`:`unknown`}/${sandboxMode}`}const formatTokens=(total,contextTokens)=>{let ctx=contextTokens??null;if(total==null)return`?/${ctx?formatTokenCount(ctx):`?`}`;let pct=ctx?Math.min(999,Math.round(total/ctx*100)):null;return`${formatTokenCount(total)}/${ctx?formatTokenCount(ctx):`?`}${pct===null?``:` (${pct}%)`}`},formatContextUsageShort=(total,contextTokens)=>`Context ${formatTokens(total,contextTokens??null)}`,formatQueueDetails=queue=>{if(!queue)return``;let depth=typeof queue.depth==`number`?`depth ${queue.depth}`:null;if(!queue.showDetails)return depth?` (${depth})`:``;let detailParts=[];if(depth&&detailParts.push(depth),typeof queue.debounceMs==`number`){let ms=Math.max(0,Math.round(queue.debounceMs)),label=ms>=1e3?`${ms%1e3==0?ms/1e3:(ms/1e3).toFixed(1)}s`:`${ms}ms`;detailParts.push(`debounce ${label}`)}return typeof queue.cap==`number`&&detailParts.push(`cap ${queue.cap}`),queue.dropPolicy&&detailParts.push(`drop ${queue.dropPolicy}`),detailParts.length?` (${detailParts.join(` · `)})`:``},readUsageFromSessionLog=(sessionId,sessionEntry,agentId,sessionKey,storePath)=>{if(!sessionId)return;let logPath;try{logPath=resolveSessionFilePath(sessionId,sessionEntry,resolveSessionFilePathOptions({agentId:agentId??(sessionKey?resolveAgentIdFromSessionKey(sessionKey):void 0),storePath}))}catch{return}if(fs.existsSync(logPath))try{let lines=fs.readFileSync(logPath,`utf-8`).split(/\n+/),input=0,output=0,promptTokens=0,model,lastUsage;for(let line of lines)if(line.trim())try{let parsed=JSON.parse(line),usage=normalizeUsage(parsed.message?.usage??parsed.usage);usage&&(lastUsage=usage),model=parsed.message?.model??parsed.model??model}catch{}if(!lastUsage)return;input=lastUsage.input??0,output=lastUsage.output??0,promptTokens=derivePromptTokens(lastUsage)??lastUsage.total??input+output;let total=lastUsage.total??promptTokens+output;return promptTokens===0&&total===0?void 0:{input,output,promptTokens,total,model}}catch{return}},formatUsagePair=(input,output)=>input==null&&output==null?null:`🧮 Tokens: ${typeof input==`number`?formatTokenCount(input):`?`} in / ${typeof output==`number`?formatTokenCount(output):`?`} out`,formatMediaUnderstandingLine=decisions=>{if(!decisions||decisions.length===0)return null;let parts=decisions.map(decision=>{let count=decision.attachments.length,countLabel=count>1?` x${count}`:``;if(decision.outcome===`success`){let chosen=decision.attachments.find(entry=>entry.chosen)?.chosen,provider=chosen?.provider?.trim(),model=chosen?.model?.trim(),modelLabel=provider?model?`${provider}/${model}`:provider:null;return`${decision.capability}${countLabel} ok${modelLabel?` (${modelLabel})`:``}`}if(decision.outcome===`no-attachment`)return`${decision.capability} none`;if(decision.outcome===`disabled`)return`${decision.capability} off`;if(decision.outcome===`scope-deny`)return`${decision.capability} denied`;if(decision.outcome===`skipped`){let reason=decision.attachments.flatMap(entry=>entry.attempts.map(attempt=>attempt.reason).filter(Boolean)).find(Boolean),shortReason=reason?reason.split(`:`)[0]?.trim():void 0;return`${decision.capability} skipped${shortReason?` (${shortReason})`:``}`}return null}).filter(part=>part!=null);return parts.length===0||parts.every(part=>part.endsWith(` none`))?null:`📎 Media: ${parts.join(` · `)}`},formatVoiceModeLine=(config,sessionEntry)=>{if(!config)return null;let ttsConfig=resolveTtsConfig(config),prefsPath=resolveTtsPrefsPath(ttsConfig),autoMode=resolveTtsAutoMode({config:ttsConfig,prefsPath,sessionAuto:sessionEntry?.ttsAuto});return autoMode===`off`?null:`🔊 Voice: ${autoMode} · provider=${getTtsProvider(ttsConfig,prefsPath)} · limit=${getTtsMaxLength(prefsPath)} · summary=${isSummarizationEnabled(prefsPath)?`on`:`off`}`};async function buildStatusMessage(args){let now=args.now??Date.now(),entry=args.sessionEntry,resolved=resolveConfiguredModelRef({cfg:{agents:{defaults:args.agent??{}}},defaultProvider:DEFAULT_PROVIDER,defaultModel:DEFAULT_MODEL}),provider=entry?.providerOverride??resolved.provider??DEFAULT_PROVIDER,model=entry?.modelOverride??resolved.model??DEFAULT_MODEL,contextTokens=entry?.contextTokens??args.agent?.contextTokens??lookupContextTokens(model)??DEFAULT_CONTEXT_TOKENS,inputTokens=entry?.inputTokens,outputTokens=entry?.outputTokens,totalTokens=entry?.totalTokens??(entry?.inputTokens??0)+(entry?.outputTokens??0);if(args.includeTranscriptUsage){let logUsage=readUsageFromSessionLog(entry?.sessionId,entry,args.agentId,args.sessionKey,args.sessionStorePath);if(logUsage){let candidate=logUsage.promptTokens||logUsage.total;(!totalTokens||totalTokens===0||candidate>totalTokens)&&(totalTokens=candidate),model||=logUsage.model??model,!contextTokens&&logUsage.model&&(contextTokens=lookupContextTokens(logUsage.model)??contextTokens),(!inputTokens||inputTokens===0)&&(inputTokens=logUsage.input),(!outputTokens||outputTokens===0)&&(outputTokens=logUsage.output)}}let thinkLevel=args.resolvedThink??args.agent?.thinkingDefault??`off`,verboseLevel=args.resolvedVerbose??args.agent?.verboseDefault??`on`,reasoningLevel=args.resolvedReasoning??`off`,elevatedLevel=args.resolvedElevated??args.sessionEntry?.elevatedLevel??args.agent?.elevatedDefault??`on`,runtime={label:resolveRuntimeLabel(args)},updatedAt=entry?.updatedAt,sessionLine=[`Session: ${args.sessionKey??`unknown`}`,typeof updatedAt==`number`?`updated ${formatTimeAgo(now-updatedAt)}`:`no activity`].filter(Boolean).join(` • `),groupActivationValue=entry?.chatType===`group`||entry?.chatType===`channel`||args.sessionKey?.includes(`:group:`)||args.sessionKey?.includes(`:channel:`)?args.groupActivation??entry?.groupActivation??`mention`:void 0,contextLine=[`Context: ${formatTokens(totalTokens,contextTokens??null)}`,`🧹 Compactions: ${entry?.compactionCount??0}`].filter(Boolean).join(` · `),queueMode=args.queue?.mode??`unknown`,queueDetails=formatQueueDetails(args.queue),verboseLabel=verboseLevel===`full`?`verbose:full`:verboseLevel===`on`?`verbose`:null,elevatedLabel=elevatedLevel&&elevatedLevel!==`off`?elevatedLevel===`on`?`elevated`:`elevated:${elevatedLevel}`:null,optionsLine=[`Runtime: ${runtime.label}`,`Think: ${thinkLevel}`,verboseLabel,reasoningLevel===`off`?null:`Reasoning: ${reasoningLevel}`,elevatedLabel].filter(Boolean).join(` · `),activationLine=[groupActivationValue?`👥 Activation: ${groupActivationValue}`:null,`🪢 Queue: ${queueMode}${queueDetails}`].filter(Boolean).join(` · `),authMode=await resolveModelAuthMode(provider,args.config),authLabelValue=args.modelAuth??(authMode&&authMode!==`unknown`?authMode:void 0),showCost=authLabelValue===`api-key`||authLabelValue===`mixed`,costConfig=showCost?resolveModelCostConfig({provider,model,config:args.config}):void 0,hasUsage=typeof inputTokens==`number`||typeof outputTokens==`number`,cost=showCost&&hasUsage?estimateUsageCost({usage:{input:inputTokens??void 0,output:outputTokens??void 0},cost:costConfig}):void 0,costLabel=showCost&&hasUsage?formatUsd(cost):void 0,modelLine=`🧠 Model: ${model?`${provider}/${model}`:`unknown`}${authLabelValue?` · 🔑 ${authLabelValue}`:``}`,commit=resolveCommitHash(),versionLine=`🤖 BuilderForceAgents ${VERSION}${commit?` (${commit})`:``}`,usagePair=formatUsagePair(inputTokens,outputTokens),costLine=costLabel?`💵 Cost: ${costLabel}`:null,usageCostLine=usagePair&&costLine?`${usagePair} · ${costLine}`:usagePair??costLine,mediaLine=formatMediaUnderstandingLine(args.mediaDecisions),voiceLine=formatVoiceModeLine(args.config,args.sessionEntry);return[versionLine,args.timeLine,modelLine,usageCostLine,`📚 ${contextLine}`,mediaLine,args.usageLine,`🧵 ${sessionLine}`,args.subagentsLine,`⚙️ ${optionsLine}`,voiceLine,activationLine].filter(Boolean).join(`
90
90
  `)}const CATEGORY_LABELS={session:`Session`,options:`Options`,status:`Status`,management:`Management`,media:`Media`,tools:`Tools`,docks:`Docks`},CATEGORY_ORDER=[`session`,`options`,`status`,`management`,`media`,`tools`,`docks`];function groupCommandsByCategory(commands){let grouped=new Map;for(let category of CATEGORY_ORDER)grouped.set(category,[]);for(let command of commands){let category=command.category??`tools`,list=grouped.get(category)??[];list.push(command),grouped.set(category,list)}return grouped}function buildHelpMessage(cfg){let lines=[`ℹ️ Help`,``];lines.push(`Session`),lines.push(` /new | /reset | /compact [instructions] | /stop`),lines.push(``);let optionParts=[`/think <level>`,`/model <id>`,`/verbose on|off`];return cfg?.commands?.config===!0&&optionParts.push(`/config`),cfg?.commands?.debug===!0&&optionParts.push(`/debug`),lines.push(`Options`),lines.push(` ${optionParts.join(` | `)}`),lines.push(``),lines.push(`Status`),lines.push(` /status | /whoami | /context`),lines.push(``),lines.push(`Skills`),lines.push(` /skill <name> [input]`),lines.push(``),lines.push(`More: /commands for full list`),lines.join(`
91
91
  `)}function formatCommandEntry(command){let primary=command.nativeName?`/${command.nativeName}`:command.textAliases[0]?.trim()||`/${command.key}`,seen=new Set,aliases=command.textAliases.map(alias=>alias.trim()).filter(Boolean).filter(alias=>alias.toLowerCase()!==primary.toLowerCase()).filter(alias=>{let key=alias.toLowerCase();return seen.has(key)?!1:(seen.add(key),!0)});return`${primary}${aliases.length?` (${aliases.join(`, `)})`:``}${command.scope===`text`?` [text]`:``} - ${command.description}`}function buildCommandItems(commands,pluginCommands){let grouped=groupCommandsByCategory(commands),items=[];for(let category of CATEGORY_ORDER){let categoryCommands=grouped.get(category)??[];if(categoryCommands.length===0)continue;let label=CATEGORY_LABELS[category];for(let command of categoryCommands)items.push({label,text:formatCommandEntry(command)})}for(let command of pluginCommands){let pluginLabel=command.pluginId?` (${command.pluginId})`:``;items.push({label:`Plugins`,text:`/${command.name}${pluginLabel} - ${command.description}`})}return items}function formatCommandList(items){let lines=[],currentLabel=null;for(let item of items)item.label!==currentLabel&&(lines.length>0&&lines.push(``),lines.push(item.label),currentLabel=item.label),lines.push(` ${item.text}`);return lines.join(`
92
92
  `)}function buildCommandsMessage(cfg,skillCommands,options){return buildCommandsMessagePaginated(cfg,skillCommands,options).text}function buildCommandsMessagePaginated(cfg,skillCommands,options){let page=Math.max(1,options?.page??1),isTelegram=options?.surface?.toLowerCase()===`telegram`,items=buildCommandItems(cfg?listChatCommandsForConfig(cfg,{skillCommands}):listChatCommands({skillCommands}),listPluginCommands());if(!isTelegram){let lines=[`ℹ️ Slash commands`,``];return lines.push(formatCommandList(items)),{text:lines.join(`
@@ -169,7 +169,7 @@ TOOLS.md does not control tool availability; it is user guidance for how to use
169
169
  `)?fenceSplit.reopenFenceLine:`${fenceSplit.reopenFenceLine}\n`}${nextBuffer}`}if(emit(rawChunk),fenceSplit)this.#buffer=nextBuffer;else{let nextStart=breakIdx<this.#buffer.length&&/\s/.test(this.#buffer[breakIdx])?breakIdx+1:breakIdx;this.#buffer=stripLeadingNewlines(this.#buffer.slice(nextStart))}return!0}#pickSoftBreakIndex(buffer,minCharsOverride){let minChars=Math.max(1,Math.floor(minCharsOverride??this.#chunking.minChars));if(buffer.length<minChars)return{index:-1};let fenceSpans=parseFenceSpans(buffer),preference=this.#chunking.breakPreference??`paragraph`;if(preference===`paragraph`){let paragraphIdx=findSafeParagraphBreakIndex({text:buffer,fenceSpans,minChars,reverse:!1});if(paragraphIdx!==-1)return{index:paragraphIdx}}if(preference===`paragraph`||preference===`newline`){let newlineIdx=findSafeNewlineBreakIndex({text:buffer,fenceSpans,minChars,reverse:!1});if(newlineIdx!==-1)return{index:newlineIdx}}if(preference!==`newline`){let sentenceIdx=findSafeSentenceBreakIndex(buffer,fenceSpans,minChars);if(sentenceIdx!==-1)return{index:sentenceIdx}}return{index:-1}}#pickBreakIndex(buffer,minCharsOverride){let minChars=Math.max(1,Math.floor(minCharsOverride??this.#chunking.minChars)),maxChars=Math.max(minChars,Math.floor(this.#chunking.maxChars));if(buffer.length<minChars)return{index:-1};let window=buffer.slice(0,Math.min(maxChars,buffer.length)),fenceSpans=parseFenceSpans(buffer),preference=this.#chunking.breakPreference??`paragraph`;if(preference===`paragraph`){let paragraphIdx=findSafeParagraphBreakIndex({text:window,fenceSpans,minChars,reverse:!0});if(paragraphIdx!==-1)return{index:paragraphIdx}}if(preference===`paragraph`||preference===`newline`){let newlineIdx=findSafeNewlineBreakIndex({text:window,fenceSpans,minChars,reverse:!0});if(newlineIdx!==-1)return{index:newlineIdx}}if(preference!==`newline`){let sentenceIdx=findSafeSentenceBreakIndex(window,fenceSpans,minChars);if(sentenceIdx!==-1)return{index:sentenceIdx}}if(preference===`newline`&&buffer.length<maxChars)return{index:-1};for(let i=window.length-1;i>=minChars;i--)if(/\s/.test(window[i])&&isSafeFenceBreak(fenceSpans,i))return{index:i};if(buffer.length>=maxChars){if(isSafeFenceBreak(fenceSpans,maxChars))return{index:maxChars};let fence=findFenceSpanAt(fenceSpans,maxChars);return fence?{index:maxChars,fenceSplit:{closeFenceLine:`${fence.indent}${fence.marker}`,reopenFenceLine:fence.openLine}}:{index:maxChars}}return{index:-1}}};function stripLeadingNewlines(value){let i=0;for(;i<value.length&&value[i]===`
170
170
  `;)i++;return i>0?value.slice(i):value}function findNextParagraphBreak(buffer,fenceSpans,startIndex=0){if(startIndex<0)return null;let re=/\n[\t ]*\n+/g;re.lastIndex=startIndex;let match;for(;(match=re.exec(buffer))!==null;){let index=match.index??-1;if(!(index<0)&&isSafeFenceBreak(fenceSpans,index))return{index,length:match[0].length}}return null}function resolveTelegramDraftStreamingChunking(cfg,accountId){let providerChunkLimit=getChannelDock(`telegram`)?.outbound?.textChunkLimit,textLimit=resolveTextChunkLimit(cfg,`telegram`,accountId,{fallbackLimit:providerChunkLimit}),normalizedAccountId=normalizeAccountId$2(accountId),draftCfg=cfg?.channels?.telegram?.accounts?.[normalizedAccountId]?.draftChunk??cfg?.channels?.telegram?.draftChunk,maxRequested=Math.max(1,Math.floor(draftCfg?.maxChars??800)),maxChars=Math.max(1,Math.min(maxRequested,textLimit)),minRequested=Math.max(1,Math.floor(draftCfg?.minChars??200));return{minChars:Math.min(minRequested,maxChars),maxChars,breakPreference:draftCfg?.breakPreference===`newline`||draftCfg?.breakPreference===`sentence`?draftCfg.breakPreference:`paragraph`}}const TELEGRAM_STREAM_MAX_CHARS=4096;function createTelegramDraftStream(params){let maxChars=Math.min(params.maxChars??TELEGRAM_STREAM_MAX_CHARS,TELEGRAM_STREAM_MAX_CHARS),throttleMs=Math.max(250,params.throttleMs??1e3),minInitialChars=params.minInitialChars,chatId=params.chatId,threadParams=buildTelegramThreadParams(params.thread),replyParams=params.replyToMessageId==null?threadParams:{...threadParams,reply_to_message_id:params.replyToMessageId},streamMessageId,lastSentText=``,stopped=!1,isFinal=!1,loop=createDraftStreamLoop({throttleMs,isStopped:()=>stopped,sendOrEditStreamMessage:async text=>{if(stopped&&!isFinal)return!1;let trimmed=text.trimEnd();if(!trimmed)return!1;if(trimmed.length>maxChars)return stopped=!0,params.warn?.(`telegram stream preview stopped (text length ${trimmed.length} > ${maxChars})`),!1;if(trimmed===lastSentText)return!0;if(typeof streamMessageId!=`number`&&minInitialChars!=null&&!isFinal&&trimmed.length<minInitialChars)return!1;lastSentText=trimmed;try{if(typeof streamMessageId==`number`)return await params.api.editMessageText(chatId,streamMessageId,trimmed),!0;let sentMessageId=(await params.api.sendMessage(chatId,trimmed,replyParams))?.message_id;return typeof sentMessageId!=`number`||!Number.isFinite(sentMessageId)?(stopped=!0,params.warn?.(`telegram stream preview stopped (missing message id from sendMessage)`),!1):(streamMessageId=Math.trunc(sentMessageId),!0)}catch(err){return stopped=!0,params.warn?.(`telegram stream preview failed: ${err instanceof Error?err.message:String(err)}`),!1}}});return params.log?.(`telegram stream preview ready (maxChars=${maxChars}, throttleMs=${throttleMs})`),{update:text=>{stopped||isFinal||loop.update(text)},flush:loop.flush,messageId:()=>streamMessageId,clear:async()=>{stopped=!0,loop.stop(),await loop.waitForInFlight();let messageId=streamMessageId;if(streamMessageId=void 0,typeof messageId==`number`)try{await params.api.deleteMessage(chatId,messageId)}catch(err){params.warn?.(`telegram stream preview cleanup failed: ${err instanceof Error?err.message:String(err)}`)}},stop:async()=>{isFinal=!0,await loop.flush()},forceNewMessage:()=>{streamMessageId=void 0,lastSentText=``,loop.resetPending()}}}async function resolveStickerVisionSupport(cfg,agentId){try{let catalog=await loadModelCatalog({config:cfg}),defaultModel=resolveDefaultModelForAgent({cfg,agentId}),entry=findModelInCatalog(catalog,defaultModel.provider,defaultModel.model);return entry?modelSupportsVision(entry):!1}catch{return!1}}const dispatchTelegramMessage=async({context,bot,cfg,runtime,replyToMode,streamMode,textLimit,telegramCfg,opts})=>{let{ctxPayload,msg,chatId,isGroup,threadSpec,historyKey,historyLimit,groupHistories,route,skillFilter,sendTyping,sendRecordVoice,ackReactionPromise,reactionApi,removeAckAfterReply}=context,draftMaxChars=Math.min(textLimit,4096),accountBlockStreamingEnabled=typeof telegramCfg.blockStreaming==`boolean`?telegramCfg.blockStreaming:cfg.agents?.defaults?.blockStreamingDefault===`on`,canStreamDraft=streamMode!==`off`&&!accountBlockStreamingEnabled,draftReplyToMessageId=replyToMode!==`off`&&typeof msg.message_id==`number`?msg.message_id:void 0,draftStream=canStreamDraft?createTelegramDraftStream({api:bot.api,chatId,maxChars:draftMaxChars,thread:threadSpec,replyToMessageId:draftReplyToMessageId,minInitialChars:30,log:logVerbose,warn:logVerbose}):void 0,draftChunking=draftStream&&streamMode===`block`?resolveTelegramDraftStreamingChunking(cfg,route.accountId):void 0,shouldSplitPreviewMessages=streamMode===`block`,draftChunker=draftChunking?new EmbeddedBlockChunker(draftChunking):void 0,mediaLocalRoots=getAgentScopedMediaLocalRoots(cfg,route.agentId),lastPartialText=``,draftText=``,hasStreamedMessage=!1,updateDraftFromPartial=text=>{if(!draftStream||!text||text===lastPartialText)return;if(hasStreamedMessage=!0,streamMode===`partial`){if(lastPartialText&&lastPartialText.startsWith(text)&&text.length<lastPartialText.length)return;lastPartialText=text,draftStream.update(text);return}let delta=text;if(text.startsWith(lastPartialText)?delta=text.slice(lastPartialText.length):(draftChunker?.reset(),draftText=``),lastPartialText=text,delta){if(!draftChunker){draftText=text,draftStream.update(draftText);return}draftChunker.append(delta),draftChunker.drain({force:!1,emit:chunk=>{draftText+=chunk,draftStream.update(draftText)}})}},flushDraft=async()=>{draftStream&&(draftChunker?.hasBuffered()&&(draftChunker.drain({force:!0,emit:chunk=>{draftText+=chunk}}),draftChunker.reset(),draftText&&draftStream.update(draftText)),await draftStream.flush())},disableBlockStreaming=typeof telegramCfg.blockStreaming==`boolean`?!telegramCfg.blockStreaming:draftStream||streamMode===`off`?!0:void 0,{onModelSelected,...prefixOptions}=createReplyPrefixOptions({cfg,agentId:route.agentId,channel:`telegram`,accountId:route.accountId}),tableMode=resolveMarkdownTableMode({cfg,channel:`telegram`,accountId:route.accountId}),chunkMode=resolveChunkMode(cfg,`telegram`,route.accountId),sticker=ctxPayload.Sticker;if(sticker?.fileId&&sticker.fileUniqueId&&ctxPayload.MediaPath){let agentDir=resolveAgentDir(cfg,route.agentId),stickerSupportsVision=await resolveStickerVisionSupport(cfg,route.agentId),description=sticker.cachedDescription??null;if(description||=await describeStickerImage({imagePath:ctxPayload.MediaPath,cfg,agentDir,agentId:route.agentId}),description){let stickerContext=[sticker.emoji,sticker.setName?`from "${sticker.setName}"`:null].filter(Boolean).join(` `),formattedDesc=`[Sticker${stickerContext?` ${stickerContext}`:``}] ${description}`;sticker.cachedDescription=description,stickerSupportsVision||(ctxPayload.Body=formattedDesc,ctxPayload.BodyForAgent=formattedDesc,ctxPayload.MediaPath=void 0,ctxPayload.MediaType=void 0,ctxPayload.MediaUrl=void 0,ctxPayload.MediaPaths=void 0,ctxPayload.MediaUrls=void 0,ctxPayload.MediaTypes=void 0),sticker.fileId?(cacheSticker({fileId:sticker.fileId,fileUniqueId:sticker.fileUniqueId,emoji:sticker.emoji,setName:sticker.setName,description,cachedAt:new Date().toISOString(),receivedFrom:ctxPayload.From}),logVerbose(`telegram: cached sticker description for ${sticker.fileUniqueId}`)):logVerbose(`telegram: skipped sticker cache (missing fileId)`)}}let replyQuoteText=ctxPayload.ReplyToIsQuote&&ctxPayload.ReplyToBody&&ctxPayload.ReplyToBody.trim()||void 0,deliveryState={delivered:!1,skippedNonSilent:0},finalizedViaPreviewMessage=!1,clearGroupHistory=()=>{isGroup&&historyKey&&clearHistoryEntriesIfEnabled({historyMap:groupHistories,historyKey,limit:historyLimit})},deliveryBaseOptions={chatId:String(chatId),token:opts.token,runtime,bot,mediaLocalRoots,replyToMode,textLimit,thread:threadSpec,tableMode,chunkMode,linkPreview:telegramCfg.linkPreview,replyQuoteText},queuedFinal=!1;try{({queuedFinal}=await dispatchReplyWithBufferedBlockDispatcher({ctx:ctxPayload,cfg,dispatcherOptions:{...prefixOptions,deliver:async(payload,info)=>{if(info.kind===`final`){await flushDraft();let hasMedia=!!payload.mediaUrl||(payload.mediaUrls?.length??0)>0,previewMessageId=draftStream?.messageId(),finalText=payload.text,currentPreviewText=streamMode===`block`?draftText:lastPartialText,previewButtons=payload.channelData?.telegram?.buttons,draftStoppedForPreviewEdit=!1;if(!finalizedViaPreviewMessage&&!hasMedia&&typeof finalText==`string`&&finalText.length>0&&typeof previewMessageId==`number`&&finalText.length<=draftMaxChars&&!payload.isError){if(await draftStream?.stop(),draftStoppedForPreviewEdit=!0,currentPreviewText&&currentPreviewText.startsWith(finalText)&&finalText.length<currentPreviewText.length)return;try{await editMessageTelegram(chatId,previewMessageId,finalText,{api:bot.api,cfg,accountId:route.accountId,linkPreview:telegramCfg.linkPreview,buttons:previewButtons}),finalizedViaPreviewMessage=!0,deliveryState.delivered=!0;return}catch(err){logVerbose(`telegram: preview final edit failed; falling back to standard send (${String(err)})`)}}!hasMedia&&!payload.isError&&typeof finalText==`string`&&finalText.length>draftMaxChars&&logVerbose(`telegram: preview final too long for edit (${finalText.length} > ${draftMaxChars}); falling back to standard send`),draftStoppedForPreviewEdit||await draftStream?.stop();let messageIdAfterStop=draftStream?.messageId();if(!finalizedViaPreviewMessage&&typeof messageIdAfterStop==`number`&&typeof finalText==`string`&&finalText.length>0&&finalText.length<=draftMaxChars&&!hasMedia&&!payload.isError)try{await editMessageTelegram(chatId,messageIdAfterStop,finalText,{api:bot.api,cfg,accountId:route.accountId,linkPreview:telegramCfg.linkPreview,buttons:previewButtons}),finalizedViaPreviewMessage=!0,deliveryState.delivered=!0;return}catch(err){logVerbose(`telegram: post-stop preview edit failed; falling back to standard send (${String(err)})`)}}(await deliverReplies({...deliveryBaseOptions,replies:[payload],onVoiceRecording:sendRecordVoice})).delivered&&(deliveryState.delivered=!0)},onSkip:(_payload,info)=>{info.reason!==`silent`&&(deliveryState.skippedNonSilent+=1)},onError:(err,info)=>{runtime.error?.(danger(`telegram ${info.kind} reply failed: ${String(err)}`))},onReplyStart:createTypingCallbacks({start:sendTyping,onStartError:err=>{logTypingFailure({log:logVerbose,channel:`telegram`,target:String(chatId),error:err})}}).onReplyStart},replyOptions:{skillFilter,disableBlockStreaming,onPartialReply:draftStream?payload=>updateDraftFromPartial(payload.text):void 0,onAssistantMessageStart:draftStream?()=>{logVerbose(`telegram: onAssistantMessageStart called, hasStreamedMessage=${hasStreamedMessage}`),shouldSplitPreviewMessages&&hasStreamedMessage&&(logVerbose(`telegram: calling forceNewMessage()`),draftStream.forceNewMessage()),lastPartialText=``,draftText=``,draftChunker?.reset()}:void 0,onReasoningEnd:draftStream?()=>{shouldSplitPreviewMessages&&hasStreamedMessage&&draftStream.forceNewMessage(),lastPartialText=``,draftText=``,draftChunker?.reset()}:void 0,onModelSelected}}))}finally{await draftStream?.stop(),finalizedViaPreviewMessage||await draftStream?.clear()}let sentFallback=!1;if(!deliveryState.delivered&&deliveryState.skippedNonSilent>0&&(sentFallback=(await deliverReplies({replies:[{text:`No response generated. Please try again.`}],...deliveryBaseOptions})).delivered),!(queuedFinal||sentFallback)){clearGroupHistory();return}removeAckReactionAfterReply({removeAfterReply:removeAckAfterReply,ackReactionPromise,ackReactionValue:ackReactionPromise?`ack`:null,remove:()=>reactionApi?.(chatId,msg.message_id??0,[])??Promise.resolve(),onError:err=>{msg.message_id&&logAckFailure({log:logVerbose,channel:`telegram`,target:`${chatId}/${msg.message_id}`,error:err})}}),clearGroupHistory()},createTelegramMessageProcessor=deps=>{let{bot,cfg,account,telegramCfg,historyLimit,groupHistories,dmPolicy,allowFrom,groupAllowFrom,ackReactionScope,logger,resolveGroupActivation,resolveGroupRequireMention,resolveTelegramGroupConfig,runtime,replyToMode,streamMode,textLimit,opts}=deps;return async(primaryCtx,allMedia,storeAllowFrom,options)=>{let context=await buildTelegramMessageContext({primaryCtx,allMedia,storeAllowFrom,options,bot,cfg,account,historyLimit,groupHistories,dmPolicy,allowFrom,groupAllowFrom,ackReactionScope,logger,resolveGroupActivation,resolveGroupRequireMention,resolveTelegramGroupConfig});context&&await dispatchTelegramMessage({context,bot,cfg,runtime,replyToMode,streamMode,textLimit,telegramCfg,opts})}};function buildPluginTelegramMenuCommands(params){let{specs,existingCommands}=params,commands=[],issues=[],pluginCommandNames=new Set;for(let spec of specs){let normalized=normalizeTelegramCommandName(spec.name);if(!normalized||!TELEGRAM_COMMAND_NAME_PATTERN.test(normalized)){issues.push(`Plugin command "/${spec.name}" is invalid for Telegram (use a-z, 0-9, underscore; max 32 chars).`);continue}let description=spec.description.trim();if(!description){issues.push(`Plugin command "/${normalized}" is missing a description.`);continue}if(existingCommands.has(normalized)){pluginCommandNames.has(normalized)?issues.push(`Plugin command "/${normalized}" is duplicated.`):issues.push(`Plugin command "/${normalized}" conflicts with an existing Telegram command.`);continue}pluginCommandNames.add(normalized),existingCommands.add(normalized),commands.push({command:normalized,description})}return{commands,issues}}function buildCappedTelegramMenuCommands(params){let{allCommands}=params,maxCommands=params.maxCommands??100,totalCommands=allCommands.length,overflowCount=Math.max(0,totalCommands-maxCommands);return{commandsToRegister:allCommands.slice(0,maxCommands),totalCommands,maxCommands,overflowCount}}function syncTelegramMenuCommands(params){let{bot,runtime,commandsToRegister}=params;(async()=>{typeof bot.api.deleteMyCommands==`function`&&await withTelegramApiErrorLogging({operation:`deleteMyCommands`,runtime,fn:()=>bot.api.deleteMyCommands()}).catch(()=>{}),commandsToRegister.length!==0&&await withTelegramApiErrorLogging({operation:`setMyCommands`,runtime,fn:()=>bot.api.setMyCommands(commandsToRegister)})})().catch(err=>{runtime.error?.(`Telegram command sync failed: ${String(err)}`)})}async function resolveTelegramCommandAuth(params){let{msg,bot,cfg,accountId,telegramCfg,allowFrom,groupAllowFrom,useAccessGroups,resolveGroupPolicy,resolveTelegramGroupConfig,requireAuth}=params,chatId=msg.chat.id,isGroup=msg.chat.type===`group`||msg.chat.type===`supergroup`,messageThreadId=msg.message_thread_id,isForum=msg.chat.is_forum===!0,{resolvedThreadId,storeAllowFrom,groupConfig,topicConfig,effectiveGroupAllow,hasGroupAllowOverride}=await resolveTelegramGroupAllowFromContext({chatId,accountId,isForum,messageThreadId,groupAllowFrom,resolveTelegramGroupConfig}),senderId=msg.from?.id?String(msg.from.id):``,senderUsername=msg.from?.username??``,sendAuthMessage=async text=>(await withTelegramApiErrorLogging({operation:`sendMessage`,fn:()=>bot.api.sendMessage(chatId,text)}),null),rejectNotAuthorized=async()=>await sendAuthMessage(`You are not authorized to use this command.`),baseAccess=evaluateTelegramGroupBaseAccess({isGroup,groupConfig,topicConfig,hasGroupAllowOverride,effectiveGroupAllow,senderId,senderUsername,enforceAllowOverride:requireAuth,requireSenderForAllowOverride:!0});if(!baseAccess.allowed)return baseAccess.reason===`group-disabled`?await sendAuthMessage(`This group is disabled.`):baseAccess.reason===`topic-disabled`?await sendAuthMessage(`This topic is disabled.`):await rejectNotAuthorized();let policyAccess=evaluateTelegramGroupPolicyAccess({isGroup,chatId,cfg,telegramCfg,topicConfig,groupConfig,effectiveGroupAllow,senderId,senderUsername,resolveGroupPolicy,enforcePolicy:useAccessGroups,useTopicAndGroupOverrides:!1,enforceAllowlistAuthorization:requireAuth,allowEmptyAllowlistEntries:!0,requireSenderForAllowlistAuthorization:!0,checkChatAllowlist:useAccessGroups});if(!policyAccess.allowed){if(policyAccess.reason===`group-policy-disabled`)return await sendAuthMessage(`Telegram group commands are disabled.`);if(policyAccess.reason===`group-policy-allowlist-no-sender`||policyAccess.reason===`group-policy-allowlist-unauthorized`)return await rejectNotAuthorized();if(policyAccess.reason===`group-chat-not-allowed`)return await sendAuthMessage(`This group is not allowed.`)}let dmAllow=normalizeAllowFromWithStore$1({allowFrom,storeAllowFrom}),senderAllowed=isSenderAllowed$1({allow:dmAllow,senderId,senderUsername}),commandAuthorized=resolveCommandAuthorizedFromAuthorizers({useAccessGroups,authorizers:[{configured:dmAllow.hasEntries,allowed:senderAllowed}],modeWhenAccessGroupsOff:`configured`});return requireAuth&&!commandAuthorized?await rejectNotAuthorized():{chatId,isGroup,isForum,resolvedThreadId,senderId,senderUsername,groupConfig,topicConfig,commandAuthorized}}const registerTelegramNativeCommands=({bot,cfg,runtime,accountId,telegramCfg,allowFrom,groupAllowFrom,replyToMode,textLimit,useAccessGroups,nativeEnabled,nativeSkillsEnabled,nativeDisabledExplicit,resolveGroupPolicy,resolveTelegramGroupConfig,shouldSkipUpdate,opts})=>{let boundRoute=nativeEnabled&&nativeSkillsEnabled?resolveAgentRoute({cfg,channel:`telegram`,accountId}):null,boundAgentIds=boundRoute?[boundRoute.agentId]:null,skillCommands=nativeEnabled&&nativeSkillsEnabled?listSkillCommandsForAgents(boundAgentIds?{cfg,agentIds:boundAgentIds}:{cfg}):[],nativeCommands=nativeEnabled?listNativeCommandSpecsForConfig(cfg,{skillCommands,provider:`telegram`}):[],reservedCommands=new Set(listNativeCommandSpecs().map(command=>normalizeTelegramCommandName(command.name)));for(let command of skillCommands)reservedCommands.add(command.name.toLowerCase());let customResolution=resolveTelegramCustomCommands({commands:telegramCfg.customCommands,reservedCommands});for(let issue of customResolution.issues)runtime.error?.(danger(issue.message));let customCommands=customResolution.commands,pluginCatalog=buildPluginTelegramMenuCommands({specs:getPluginCommandSpecs(),existingCommands:new Set([...nativeCommands.map(command=>normalizeTelegramCommandName(command.name)),...customCommands.map(command=>command.command)].map(command=>command.toLowerCase()))});for(let issue of pluginCatalog.issues)runtime.error?.(danger(issue));let{commandsToRegister,totalCommands,maxCommands,overflowCount}=buildCappedTelegramMenuCommands({allCommands:[...nativeCommands.map(command=>{let normalized=normalizeTelegramCommandName(command.name);return TELEGRAM_COMMAND_NAME_PATTERN.test(normalized)?{command:normalized,description:command.description}:(runtime.error?.(danger(`Native command "${command.name}" is invalid for Telegram (resolved to "${normalized}"). Skipping.`)),null)}).filter(cmd=>cmd!==null),...nativeEnabled?pluginCatalog.commands:[],...customCommands]});overflowCount>0&&runtime.log?.(`Telegram limits bots to ${maxCommands} commands. ${totalCommands} configured; registering first ${maxCommands}. Use channels.telegram.commands.native: false to disable, or reduce plugin/skill/custom commands.`),syncTelegramMenuCommands({bot,runtime,commandsToRegister});let resolveCommandRuntimeContext=params=>{let{msg,isGroup,isForum,resolvedThreadId}=params,chatId=msg.chat.id,messageThreadId=msg.message_thread_id,threadSpec=resolveTelegramThreadSpec({isGroup,isForum,messageThreadId}),parentPeer=buildTelegramParentPeer({isGroup,resolvedThreadId,chatId}),route=resolveAgentRoute({cfg,channel:`telegram`,accountId,peer:{kind:isGroup?`group`:`direct`,id:isGroup?buildTelegramGroupPeerId(chatId,resolvedThreadId):String(chatId)},parentPeer});return{chatId,threadSpec,route,mediaLocalRoots:getAgentScopedMediaLocalRoots(cfg,route.agentId),tableMode:resolveMarkdownTableMode({cfg,channel:`telegram`,accountId:route.accountId}),chunkMode:resolveChunkMode(cfg,`telegram`,route.accountId)}},buildCommandDeliveryBaseOptions=params=>({chatId:String(params.chatId),token:opts.token,runtime,bot,mediaLocalRoots:params.mediaLocalRoots,replyToMode,textLimit,thread:params.threadSpec,tableMode:params.tableMode,chunkMode:params.chunkMode,linkPreview:telegramCfg.linkPreview});if(commandsToRegister.length>0||pluginCatalog.commands.length>0)if(typeof bot.command!=`function`)logVerbose(`telegram: bot.command unavailable; skipping native handlers`);else{for(let command of nativeCommands){let normalizedCommandName=normalizeTelegramCommandName(command.name);bot.command(normalizedCommandName,async ctx=>{let msg=ctx.message;if(!msg||shouldSkipUpdate(ctx))return;let auth=await resolveTelegramCommandAuth({msg,bot,cfg,accountId,telegramCfg,allowFrom,groupAllowFrom,useAccessGroups,resolveGroupPolicy,resolveTelegramGroupConfig,requireAuth:!0});if(!auth)return;let{chatId,isGroup,isForum,resolvedThreadId,senderId,senderUsername,groupConfig,topicConfig,commandAuthorized}=auth,{threadSpec,route,mediaLocalRoots,tableMode,chunkMode}=resolveCommandRuntimeContext({msg,isGroup,isForum,resolvedThreadId}),deliveryBaseOptions=buildCommandDeliveryBaseOptions({chatId,mediaLocalRoots,threadSpec,tableMode,chunkMode}),threadParams=buildTelegramThreadParams(threadSpec)??{},commandDefinition=findCommandByNativeName(command.name,`telegram`),rawText=ctx.match?.trim()??``,commandArgs=commandDefinition?parseCommandArgs(commandDefinition,rawText):rawText?{raw:rawText}:void 0,prompt=commandDefinition?buildCommandTextFromArgs(commandDefinition,commandArgs):rawText?`/${command.name} ${rawText}`:`/${command.name}`,menu=commandDefinition?resolveCommandArgMenu({command:commandDefinition,args:commandArgs,cfg}):null;if(menu&&commandDefinition){let title=menu.title??`Choose ${menu.arg.description||menu.arg.name} for /${commandDefinition.nativeName??commandDefinition.key}.`,rows=[];for(let i=0;i<menu.choices.length;i+=2){let slice=menu.choices.slice(i,i+2);rows.push(slice.map(choice=>{let args={values:{[menu.arg.name]:choice.value}};return{text:choice.label,callback_data:buildCommandTextFromArgs(commandDefinition,args)}}))}let replyMarkup=buildInlineKeyboard(rows);await withTelegramApiErrorLogging({operation:`sendMessage`,runtime,fn:()=>bot.api.sendMessage(chatId,title,{...replyMarkup?{reply_markup:replyMarkup}:{},...threadParams})});return}let baseSessionKey=route.sessionKey,dmThreadId=threadSpec.scope===`dm`?threadSpec.id:void 0,sessionKey=(dmThreadId==null?null:resolveThreadSessionKeys({baseSessionKey,threadId:String(dmThreadId)}))?.sessionKey??baseSessionKey,skillFilter=firstDefined$2(topicConfig?.skills,groupConfig?.skills),systemPromptParts=[groupConfig?.systemPrompt?.trim()||null,topicConfig?.systemPrompt?.trim()||null].filter(entry=>!!entry),groupSystemPrompt=systemPromptParts.length>0?systemPromptParts.join(`
171
171
 
172
- `):void 0,conversationLabel=isGroup?msg.chat.title?`${msg.chat.title} id:${chatId}`:`group:${chatId}`:buildSenderName(msg)??String(senderId||chatId),ctxPayload=finalizeInboundContext({Body:prompt,BodyForAgent:prompt,RawBody:prompt,CommandBody:prompt,CommandArgs:commandArgs,From:isGroup?buildTelegramGroupFrom(chatId,resolvedThreadId):`telegram:${chatId}`,To:`slash:${senderId||chatId}`,ChatType:isGroup?`group`:`direct`,ConversationLabel:conversationLabel,GroupSubject:isGroup?msg.chat.title??void 0:void 0,GroupSystemPrompt:isGroup?groupSystemPrompt:void 0,SenderName:buildSenderName(msg),SenderId:senderId||void 0,SenderUsername:senderUsername||void 0,Surface:`telegram`,MessageSid:String(msg.message_id),Timestamp:msg.date?msg.date*1e3:void 0,WasMentioned:!0,CommandAuthorized:commandAuthorized,CommandSource:`native`,SessionKey:`telegram:slash:${senderId||chatId}`,AccountId:route.accountId,CommandTargetSessionKey:sessionKey,MessageThreadId:threadSpec.id,IsForum:isForum,OriginatingChannel:`telegram`,OriginatingTo:`telegram:${chatId}`}),disableBlockStreaming=typeof telegramCfg.blockStreaming==`boolean`?!telegramCfg.blockStreaming:void 0,deliveryState={delivered:!1,skippedNonSilent:0},{onModelSelected,...prefixOptions}=createReplyPrefixOptions({cfg,agentId:route.agentId,channel:`telegram`,accountId:route.accountId});await dispatchReplyWithBufferedBlockDispatcher({ctx:ctxPayload,cfg,dispatcherOptions:{...prefixOptions,deliver:async(payload,_info)=>{(await deliverReplies({replies:[payload],...deliveryBaseOptions})).delivered&&(deliveryState.delivered=!0)},onSkip:(_payload,info)=>{info.reason!==`silent`&&(deliveryState.skippedNonSilent+=1)},onError:(err,info)=>{runtime.error?.(danger(`telegram slash ${info.kind} reply failed: ${String(err)}`))}},replyOptions:{skillFilter,disableBlockStreaming,onModelSelected}}),!deliveryState.delivered&&deliveryState.skippedNonSilent>0&&await deliverReplies({replies:[{text:`No response generated. Please try again.`}],...deliveryBaseOptions})})}for(let pluginCommand of pluginCatalog.commands)bot.command(pluginCommand.command,async ctx=>{let msg=ctx.message;if(!msg||shouldSkipUpdate(ctx))return;let chatId=msg.chat.id,rawText=ctx.match?.trim()??``,commandBody=`/${pluginCommand.command}${rawText?` ${rawText}`:``}`,match=matchPluginCommand(commandBody);if(!match){await withTelegramApiErrorLogging({operation:`sendMessage`,runtime,fn:()=>bot.api.sendMessage(chatId,`Command not found.`)});return}let auth=await resolveTelegramCommandAuth({msg,bot,cfg,accountId,telegramCfg,allowFrom,groupAllowFrom,useAccessGroups,resolveGroupPolicy,resolveTelegramGroupConfig,requireAuth:match.command.requireAuth!==!1});if(!auth)return;let{senderId,commandAuthorized,isGroup,isForum,resolvedThreadId}=auth,{threadSpec,mediaLocalRoots,tableMode,chunkMode}=resolveCommandRuntimeContext({msg,isGroup,isForum,resolvedThreadId}),deliveryBaseOptions=buildCommandDeliveryBaseOptions({chatId,mediaLocalRoots,threadSpec,tableMode,chunkMode}),from=isGroup?buildTelegramGroupFrom(chatId,threadSpec.id):`telegram:${chatId}`,to=`telegram:${chatId}`;await deliverReplies({replies:[await executePluginCommand({command:match.command,args:match.args,senderId,channel:`telegram`,isAuthorizedSender:commandAuthorized,commandBody,config:cfg,from,to,accountId,messageThreadId:threadSpec.id})],...deliveryBaseOptions})})}else nativeDisabledExplicit&&withTelegramApiErrorLogging({operation:`setMyCommands`,runtime,fn:()=>bot.api.setMyCommands([])}).catch(()=>{})};function getTelegramSequentialKey(ctx){let reaction=ctx.update?.message_reaction;if(reaction?.chat?.id)return`telegram:${reaction.chat.id}`;let msg=ctx.message??ctx.channelPost??ctx.editedChannelPost??ctx.update?.message??ctx.update?.edited_message??ctx.update?.channel_post??ctx.update?.edited_channel_post??ctx.update?.callback_query?.message,chatId=msg?.chat?.id??ctx.chat?.id,rawText=msg?.text??msg?.caption,botUsername=ctx.me?.username;if(isAbortRequestText(rawText,botUsername?{botUsername}:void 0))return typeof chatId==`number`?`telegram:${chatId}:control`:`telegram:control`;let isGroup=msg?.chat?.type===`group`||msg?.chat?.type===`supergroup`,messageThreadId=msg?.message_thread_id,isForum=msg?.chat?.is_forum,threadId=isGroup?resolveTelegramForumThreadId({isForum,messageThreadId}):messageThreadId;return typeof chatId==`number`?threadId==null?`telegram:${chatId}`:`telegram:${chatId}:topic:${threadId}`:`telegram:unknown`}function createTelegramBot(opts){let runtime=opts.runtime??{log:console.log,error:console.error,exit:code=>{throw Error(`exit ${code}`)}},cfg=opts.config??loadConfig(),account=resolveTelegramAccount({cfg,accountId:opts.accountId}),telegramCfg=account.config,fetchImpl=resolveTelegramFetch(opts.proxyFetch,{network:telegramCfg.network}),shouldProvideFetch=!!fetchImpl,fetchForClient=fetchImpl,timeoutSeconds=typeof telegramCfg?.timeoutSeconds==`number`&&Number.isFinite(telegramCfg.timeoutSeconds)?Math.max(1,Math.floor(telegramCfg.timeoutSeconds)):void 0,client=shouldProvideFetch||timeoutSeconds?{...shouldProvideFetch&&fetchImpl?{fetch:fetchForClient}:{},...timeoutSeconds?{timeoutSeconds}:{}}:void 0,bot=new Bot(opts.token,client?{client}:void 0);bot.api.config.use(apiThrottler()),bot.use(sequentialize(getTelegramSequentialKey)),bot.catch(err=>{runtime.error?.(danger(`telegram bot error: ${formatUncaughtError(err)}`))});let recentUpdates=createTelegramUpdateDedupe(),lastUpdateId=typeof opts.updateOffset?.lastUpdateId==`number`?opts.updateOffset.lastUpdateId:null,recordUpdateId=ctx=>{let updateId=resolveTelegramUpdateId(ctx);typeof updateId==`number`&&(lastUpdateId!==null&&updateId<=lastUpdateId||(lastUpdateId=updateId,opts.updateOffset?.onUpdateId?.(updateId)))},shouldSkipUpdate=ctx=>{let updateId=resolveTelegramUpdateId(ctx);if(typeof updateId==`number`&&lastUpdateId!==null&&updateId<=lastUpdateId)return!0;let key=buildTelegramUpdateKey(ctx),skipped=recentUpdates.check(key);return skipped&&key&&shouldLogVerbose()&&logVerbose(`telegram dedupe: skipped ${key}`),skipped},rawUpdateLogger=createSubsystemLogger(`gateway/channels/telegram/raw-update`),MAX_RAW_UPDATE_CHARS=8e3,stringifyUpdate=update=>{let seen=new WeakSet;return JSON.stringify(update??null,(key,value)=>{if(typeof value==`string`&&value.length>500)return`${value.slice(0,500)}...`;if(Array.isArray(value)&&value.length>20)return[...value.slice(0,20),`...(${value.length-20} more)`];if(value&&typeof value==`object`){if(seen.has(value))return`[Circular]`;seen.add(value)}return value})};bot.use(async(ctx,next)=>{if(shouldLogVerbose())try{let raw=stringifyUpdate(ctx.update),preview=raw.length>MAX_RAW_UPDATE_CHARS?`${raw.slice(0,MAX_RAW_UPDATE_CHARS)}...`:raw;rawUpdateLogger.debug(`telegram update: ${preview}`)}catch(err){rawUpdateLogger.debug(`telegram update log failed: ${String(err)}`)}await next(),recordUpdateId(ctx)});let historyLimit=Math.max(0,telegramCfg.historyLimit??cfg.messages?.groupChat?.historyLimit??50),groupHistories=new Map,textLimit=resolveTextChunkLimit(cfg,`telegram`,account.accountId),dmPolicy=telegramCfg.dmPolicy??`pairing`,allowFrom=opts.allowFrom??telegramCfg.allowFrom,groupAllowFrom=opts.groupAllowFrom??telegramCfg.groupAllowFrom??(telegramCfg.allowFrom&&telegramCfg.allowFrom.length>0?telegramCfg.allowFrom:void 0)??(opts.allowFrom&&opts.allowFrom.length>0?opts.allowFrom:void 0),replyToMode=opts.replyToMode??telegramCfg.replyToMode??`off`,nativeEnabled=resolveNativeCommandsEnabled({providerId:`telegram`,providerSetting:telegramCfg.commands?.native,globalSetting:cfg.commands?.native}),nativeSkillsEnabled=resolveNativeSkillsEnabled({providerId:`telegram`,providerSetting:telegramCfg.commands?.nativeSkills,globalSetting:cfg.commands?.nativeSkills}),nativeDisabledExplicit=isNativeCommandsExplicitlyDisabled({providerSetting:telegramCfg.commands?.native,globalSetting:cfg.commands?.native}),useAccessGroups=cfg.commands?.useAccessGroups!==!1,ackReactionScope=cfg.messages?.ackReactionScope??`group-mentions`,mediaMaxBytes=(opts.mediaMaxMb??telegramCfg.mediaMaxMb??5)*1024*1024,logger=getChildLogger({module:`telegram-auto-reply`}),streamMode=resolveTelegramStreamMode(telegramCfg),resolveGroupPolicy=chatId=>resolveChannelGroupPolicy({cfg,channel:`telegram`,accountId:account.accountId,groupId:String(chatId)}),resolveGroupActivation=params=>{let agentId=params.agentId??resolveDefaultAgentId(cfg),sessionKey=params.sessionKey??`agent:${agentId}:telegram:group:${buildTelegramGroupPeerId(params.chatId,params.messageThreadId)}`,storePath=resolveStorePath(cfg.session?.store,{agentId});try{let entry=loadSessionStore(storePath)[sessionKey];if(entry?.groupActivation===`always`)return!1;if(entry?.groupActivation===`mention`)return!0}catch(err){logVerbose(`Failed to load session for activation check: ${String(err)}`)}},resolveGroupRequireMention=chatId=>resolveChannelGroupRequireMention({cfg,channel:`telegram`,accountId:account.accountId,groupId:String(chatId),requireMentionOverride:opts.requireMention,overrideOrder:`after-config`}),resolveTelegramGroupConfig=(chatId,messageThreadId)=>{let groups=telegramCfg.groups;if(!groups)return{groupConfig:void 0,topicConfig:void 0};let groupConfig=groups[String(chatId)]??groups[`*`];return{groupConfig,topicConfig:messageThreadId==null?void 0:groupConfig?.topics?.[String(messageThreadId)]}},processMessage=createTelegramMessageProcessor({bot,cfg,account,telegramCfg,historyLimit,groupHistories,dmPolicy,allowFrom,groupAllowFrom,ackReactionScope,logger,resolveGroupActivation,resolveGroupRequireMention,resolveTelegramGroupConfig,runtime,replyToMode,streamMode,textLimit,opts});return registerTelegramNativeCommands({bot,cfg,runtime,accountId:account.accountId,telegramCfg,allowFrom,groupAllowFrom,replyToMode,textLimit,useAccessGroups,nativeEnabled,nativeSkillsEnabled,nativeDisabledExplicit,resolveGroupPolicy,resolveTelegramGroupConfig,shouldSkipUpdate,opts}),registerTelegramHandlers({cfg,accountId:account.accountId,bot,opts,runtime,mediaMaxBytes,telegramCfg,groupAllowFrom,resolveGroupPolicy,resolveTelegramGroupConfig,shouldSkipUpdate,processMessage,logger}),bot}function normalizeAccountId(accountId){let trimmed=accountId?.trim();return trimmed?trimmed.replace(/[^a-z0-9._-]+/gi,`_`):`default`}function resolveTelegramUpdateOffsetPath(accountId,env=process.env){let stateDir=resolveStateDir(env,os.homedir),normalized=normalizeAccountId(accountId);return path.join(stateDir,`telegram`,`update-offset-${normalized}.json`)}function safeParseState(raw){try{let parsed=JSON.parse(raw);return parsed?.version!==1||parsed.lastUpdateId!==null&&typeof parsed.lastUpdateId!=`number`?null:parsed}catch{return null}}async function readTelegramUpdateOffset(params){let filePath=resolveTelegramUpdateOffsetPath(params.accountId,params.env);try{return safeParseState(await fs$1.readFile(filePath,`utf-8`))?.lastUpdateId??null}catch(err){return err.code,null}}async function writeTelegramUpdateOffset(params){let filePath=resolveTelegramUpdateOffsetPath(params.accountId,params.env),dir=path.dirname(filePath);await fs$1.mkdir(dir,{recursive:!0,mode:448});let tmp=path.join(dir,`${path.basename(filePath)}.${crypto.randomUUID()}.tmp`),payload={version:1,lastUpdateId:params.updateId};await fs$1.writeFile(tmp,`${JSON.stringify(payload,null,2)}\n`,{encoding:`utf-8`}),await fs$1.chmod(tmp,384),await fs$1.rename(tmp,filePath)}async function deleteTelegramUpdateOffset(params){let filePath=resolveTelegramUpdateOffsetPath(params.accountId,params.env);try{await fs$1.unlink(filePath)}catch(err){if(err.code===`ENOENT`)return;throw err}}async function startTelegramWebhook(opts){let path=opts.path??`/telegram-webhook`,healthPath=opts.healthPath??`/healthz`,port=opts.port??8787,host=opts.host??`127.0.0.1`,secret=typeof opts.secret==`string`?opts.secret.trim():``;if(!secret)throw Error(`Telegram webhook mode requires a non-empty secret token. Set channels.telegram.webhookSecret in your config.`);let runtime=opts.runtime??defaultRuntime,diagnosticsEnabled=isDiagnosticsEnabled(opts.config),bot=createTelegramBot({token:opts.token,runtime,proxyFetch:opts.fetch,config:opts.config,accountId:opts.accountId}),handler=webhookCallback(bot,`http`,{secretToken:secret,onTimeout:`return`,timeoutMilliseconds:1e4});diagnosticsEnabled&&startDiagnosticHeartbeat();let server=createServer((req,res)=>{if(req.url===healthPath){res.writeHead(200),res.end(`ok`);return}if(req.url!==path||req.method!==`POST`){res.writeHead(404),res.end();return}let startTime=Date.now();diagnosticsEnabled&&logWebhookReceived({channel:`telegram`,updateType:`telegram-post`});let guard=installRequestBodyLimitGuard(req,res,{maxBytes:1048576,timeoutMs:3e4,responseFormat:`text`});if(guard.isTripped())return;let handled=handler(req,res);if(handled&&typeof handled.catch==`function`){handled.then(()=>{diagnosticsEnabled&&logWebhookProcessed({channel:`telegram`,updateType:`telegram-post`,durationMs:Date.now()-startTime})}).catch(err=>{if(guard.isTripped())return;let errMsg=formatErrorMessage(err);diagnosticsEnabled&&logWebhookError({channel:`telegram`,updateType:`telegram-post`,error:errMsg}),runtime.log?.(`webhook handler failed: ${errMsg}`),res.headersSent||res.writeHead(500),res.end()}).finally(()=>{guard.dispose()});return}guard.dispose()}),publicUrl=opts.publicUrl??`http://${host===`0.0.0.0`?`localhost`:host}:${port}${path}`;await withTelegramApiErrorLogging({operation:`setWebhook`,runtime,fn:()=>bot.api.setWebhook(publicUrl,{secret_token:secret,allowed_updates:resolveTelegramAllowedUpdates()})}),await new Promise(resolve=>server.listen(port,host,resolve)),runtime.log?.(`webhook listening on ${publicUrl}`);let shutdown=()=>{server.close(),bot.stop(),diagnosticsEnabled&&stopDiagnosticHeartbeat()};return opts.abortSignal&&opts.abortSignal.addEventListener(`abort`,shutdown,{once:!0}),{server,bot,stop:shutdown}}function createTelegramRunnerOptions(cfg){return{sink:{concurrency:resolveAgentMaxConcurrent(cfg)},runner:{fetch:{timeout:30,allowed_updates:resolveTelegramAllowedUpdates()},silent:!0,maxRetryTime:300*1e3,retryInterval:`exponential`}}}const TELEGRAM_POLL_RESTART_POLICY={initialMs:2e3,maxMs:3e4,factor:1.8,jitter:.25},isGetUpdatesConflict=err=>{if(!err||typeof err!=`object`)return!1;let typed=err;return(typed.error_code??typed.errorCode)===409?[typed.method,typed.description,typed.message].filter(value=>typeof value==`string`).join(` `).toLowerCase().includes(`getupdates`):!1},isGrammyHttpError=err=>!err||typeof err!=`object`?!1:err.name===`HttpError`;async function monitorTelegramProvider(opts={}){let log=opts.runtime?.error??console.error,unregisterHandler=registerUnhandledRejectionHandler(err=>isGrammyHttpError(err)&&isRecoverableTelegramNetworkError(err,{context:`polling`})?(log(`[telegram] Suppressed network error: ${formatErrorMessage(err)}`),!0):!1);try{let cfg=opts.config??loadConfig(),account=resolveTelegramAccount({cfg,accountId:opts.accountId}),token=opts.token?.trim()||account.token;if(!token)throw Error(`Telegram bot token missing for account "${account.accountId}" (set channels.telegram.accounts.${account.accountId}.botToken/tokenFile or TELEGRAM_BOT_TOKEN for default).`);let proxyFetch=opts.proxyFetch??(account.config.proxy?makeProxyFetch(account.config.proxy):void 0),lastUpdateId=await readTelegramUpdateOffset({accountId:account.accountId}),bot=createTelegramBot({token,runtime:opts.runtime,proxyFetch,config:cfg,accountId:account.accountId,updateOffset:{lastUpdateId,onUpdateId:async updateId=>{if(!(lastUpdateId!==null&&updateId<=lastUpdateId)){lastUpdateId=updateId;try{await writeTelegramUpdateOffset({accountId:account.accountId,updateId})}catch(err){(opts.runtime?.error??console.error)(`telegram: failed to persist update offset: ${String(err)}`)}}}}});if(opts.useWebhook){await startTelegramWebhook({token,accountId:account.accountId,config:cfg,path:opts.webhookPath,port:opts.webhookPort,secret:opts.webhookSecret??account.config.webhookSecret,host:opts.webhookHost??account.config.webhookHost,runtime:opts.runtime,fetch:proxyFetch,abortSignal:opts.abortSignal,publicUrl:opts.webhookUrl});return}let restartAttempts=0;for(;!opts.abortSignal?.aborted;){let runner=run(bot,createTelegramRunnerOptions(cfg)),stopOnAbort=()=>{opts.abortSignal?.aborted&&runner.stop()};opts.abortSignal?.addEventListener(`abort`,stopOnAbort,{once:!0});try{await runner.task();return}catch(err){if(opts.abortSignal?.aborted)throw err;let isConflict=isGetUpdatesConflict(err),isRecoverable=isRecoverableTelegramNetworkError(err,{context:`polling`});if(!isConflict&&!isRecoverable)throw err;restartAttempts+=1;let delayMs=computeBackoff(TELEGRAM_POLL_RESTART_POLICY,restartAttempts),reason=isConflict?`getUpdates conflict`:`network error`,errMsg=formatErrorMessage(err);(opts.runtime?.error??console.error)(`Telegram ${reason}: ${errMsg}; retrying in ${formatDurationPrecise(delayMs)}.`);try{await sleepWithAbort(delayMs,opts.abortSignal)}catch(sleepErr){if(opts.abortSignal?.aborted)return;throw sleepErr}}finally{opts.abortSignal?.removeEventListener(`abort`,stopOnAbort)}}}finally{unregisterHandler()}}async function probeTelegram(token,timeoutMs,proxyUrl){let started=Date.now(),fetcher=proxyUrl?makeProxyFetch(proxyUrl):fetch,base=`https://api.telegram.org/bot${token}`,retryDelayMs=Math.max(50,Math.min(1e3,timeoutMs)),result={ok:!1,status:null,error:null,elapsedMs:0};try{let meRes=null,fetchError=null;for(let i=0;i<3;i++)try{meRes=await fetchWithTimeout(`${base}/getMe`,{},timeoutMs,fetcher);break}catch(err){fetchError=err,i<2&&await new Promise(resolve=>setTimeout(resolve,retryDelayMs))}if(!meRes)throw fetchError;let meJson=await meRes.json();if(!meRes.ok||!meJson?.ok)return result.status=meRes.status,result.error=meJson?.description??`getMe failed (${meRes.status})`,{...result,elapsedMs:Date.now()-started};result.bot={id:meJson.result?.id??null,username:meJson.result?.username??null,canJoinGroups:typeof meJson.result?.can_join_groups==`boolean`?meJson.result?.can_join_groups:null,canReadAllGroupMessages:typeof meJson.result?.can_read_all_group_messages==`boolean`?meJson.result?.can_read_all_group_messages:null,supportsInlineQueries:typeof meJson.result?.supports_inline_queries==`boolean`?meJson.result?.supports_inline_queries:null};try{let webhookRes=await fetchWithTimeout(`${base}/getWebhookInfo`,{},timeoutMs,fetcher),webhookJson=await webhookRes.json();webhookRes.ok&&webhookJson?.ok&&(result.webhook={url:webhookJson.result?.url??null,hasCustomCert:webhookJson.result?.has_custom_certificate??null})}catch{}return result.ok=!0,result.status=null,result.error=null,result.elapsedMs=Date.now()-started,result}catch(err){return{...result,status:err instanceof Response?err.status:result.status,error:err instanceof Error?err.message:String(err),elapsedMs:Date.now()-started}}}function formatNativeDependencyHint(params){let manager=params.manager??`pnpm`,rebuildCommand=params.rebuildCommand??(manager===`npm`?`npm rebuild ${params.packageName}`:manager===`yarn`?`yarn rebuild ${params.packageName}`:`pnpm rebuild ${params.packageName}`),steps=[params.approveBuildsCommand??(manager===`pnpm`?`pnpm approve-builds (select ${params.packageName})`:void 0),rebuildCommand,params.downloadCommand].filter(step=>!!step);return steps.length===0?`Install ${params.packageName} and rebuild its native module.`:`Install ${params.packageName} and rebuild its native module (${steps.join(`; `)}).`}let cachedVersion=null;function resolveVersion(){if(cachedVersion)return cachedVersion;try{return cachedVersion=createRequire(import.meta.url)(`../../../package.json`).version??`unknown`,cachedVersion}catch{return cachedVersion=`unknown`,cachedVersion}}const sendMessageWhatsAppLazy=async(...args)=>{let{sendMessageWhatsApp}=await loadWebOutbound();return sendMessageWhatsApp(...args)},sendPollWhatsAppLazy=async(...args)=>{let{sendPollWhatsApp}=await loadWebOutbound();return sendPollWhatsApp(...args)},loginWebLazy=async(...args)=>{let{loginWeb}=await loadWebLogin();return loginWeb(...args)},startWebLoginWithQrLazy=async(...args)=>{let{startWebLoginWithQr}=await loadWebLoginQr();return startWebLoginWithQr(...args)},waitForWebLoginLazy=async(...args)=>{let{waitForWebLogin}=await loadWebLoginQr();return waitForWebLogin(...args)},monitorWebChannelLazy=async(...args)=>{let{monitorWebChannel}=await loadWebChannel();return monitorWebChannel(...args)},handleWhatsAppActionLazy=async(...args)=>{let{handleWhatsAppAction}=await loadWhatsAppActions();return handleWhatsAppAction(...args)};let webOutboundPromise=null,webLoginPromise=null,webLoginQrPromise=null,webChannelPromise=null,whatsappActionsPromise=null;function loadWebOutbound(){return webOutboundPromise??=import(`./outbound-Cnu8bKIe.js`),webOutboundPromise}function loadWebLogin(){return webLoginPromise??=import(`./login-sr1eysDj.js`),webLoginPromise}function loadWebLoginQr(){return webLoginQrPromise??=import(`./login-qr-ClJYLoca.js`),webLoginQrPromise}function loadWebChannel(){return webChannelPromise??=import(`./web-Bkk568P6.js`),webChannelPromise}function loadWhatsAppActions(){return whatsappActionsPromise??=import(`./whatsapp-actions-Bvdy4Cod.js`),whatsappActionsPromise}function createPluginRuntime(){return{version:resolveVersion(),config:{loadConfig,writeConfigFile},system:{enqueueSystemEvent,runCommandWithTimeout,formatNativeDependencyHint},media:{loadWebMedia,detectMime,mediaKindFromMime,isVoiceCompatibleAudio,getImageMetadata,resizeToJpeg},tts:{textToSpeechTelephony},tools:{createMemoryGetTool,createMemorySearchTool,registerMemoryCli},channel:{text:{chunkByNewline,chunkMarkdownText,chunkMarkdownTextWithMode,chunkText,chunkTextWithMode,resolveChunkMode,resolveTextChunkLimit,hasControlCommand,resolveMarkdownTableMode,convertMarkdownTables},reply:{dispatchReplyWithBufferedBlockDispatcher,createReplyDispatcherWithTyping,resolveEffectiveMessagesConfig,resolveHumanDelayConfig,dispatchReplyFromConfig,finalizeInboundContext,formatAgentEnvelope,formatInboundEnvelope,resolveEnvelopeFormatOptions},routing:{resolveAgentRoute},pairing:{buildPairingReply,readAllowFromStore:readChannelAllowFromStore,upsertPairingRequest:upsertChannelPairingRequest},media:{fetchRemoteMedia,saveMediaBuffer},activity:{record:recordChannelActivity,get:getChannelActivity},session:{resolveStorePath,readSessionUpdatedAt,recordSessionMetaFromInbound,recordInboundSession,updateLastRoute},mentions:{buildMentionRegexes,matchesMentionPatterns,matchesMentionWithExplicit},reactions:{shouldAckReaction,removeAckReactionAfterReply},groups:{resolveGroupPolicy:resolveChannelGroupPolicy,resolveRequireMention:resolveChannelGroupRequireMention},debounce:{createInboundDebouncer,resolveInboundDebounceMs},commands:{resolveCommandAuthorizedFromAuthorizers,isControlCommandMessage,shouldComputeCommandAuthorized,shouldHandleTextCommands},discord:{messageActions:discordMessageActions,auditChannelPermissions:auditDiscordChannelPermissions,listDirectoryGroupsLive:listDiscordDirectoryGroupsLive,listDirectoryPeersLive:listDiscordDirectoryPeersLive,probeDiscord,resolveChannelAllowlist:resolveDiscordChannelAllowlist,resolveUserAllowlist:resolveDiscordUserAllowlist,sendMessageDiscord,sendPollDiscord,monitorDiscordProvider},slack:{listDirectoryGroupsLive:listSlackDirectoryGroupsLive,listDirectoryPeersLive:listSlackDirectoryPeersLive,probeSlack,resolveChannelAllowlist:resolveSlackChannelAllowlist,resolveUserAllowlist:resolveSlackUserAllowlist,sendMessageSlack,monitorSlackProvider,handleSlackAction},telegram:{auditGroupMembership:auditTelegramGroupMembership,collectUnmentionedGroupIds:collectTelegramUnmentionedGroupIds,probeTelegram,resolveTelegramToken,sendMessageTelegram,sendPollTelegram,monitorTelegramProvider,messageActions:telegramMessageActions},signal:{probeSignal,sendMessageSignal,monitorSignalProvider,messageActions:signalMessageActions},imessage:{monitorIMessageProvider,probeIMessage,sendMessageIMessage},whatsapp:{getActiveWebListener,getWebAuthAgeMs,logoutWeb,logWebSelfId,readWebSelfId,webAuthExists,sendMessageWhatsApp:sendMessageWhatsAppLazy,sendPollWhatsApp:sendPollWhatsAppLazy,loginWeb:loginWebLazy,startWebLoginWithQr:startWebLoginWithQrLazy,waitForWebLogin:waitForWebLoginLazy,monitorWebChannel:monitorWebChannelLazy,handleWhatsAppAction:handleWhatsAppActionLazy,createLoginTool:createWhatsAppLoginTool},line:{listLineAccountIds,resolveDefaultLineAccountId,resolveLineAccount,normalizeAccountId:normalizeAccountId$1,probeLineBot,sendMessageLine,pushMessageLine,pushMessagesLine,pushFlexMessage,pushTemplateMessage,pushLocationMessage,pushTextMessageWithQuickReplies,createQuickReplyItems,buildTemplateMessageFromPayload,monitorLineProvider}},logging:{shouldLogVerbose,getChildLogger:(bindings,opts)=>{let logger=getChildLogger(bindings,{level:opts?.level?normalizeLogLevel(opts.level):void 0});return{debug:message=>logger.debug?.(message),info:message=>logger.info(message),warn:message=>logger.warn(message),error:message=>logger.error(message)}}},state:{resolveStateDir}}}const registryCache=new Map,defaultLogger=()=>createSubsystemLogger(`plugins`),resolvePluginSdkAliasFile=params=>{try{let modulePath=fileURLToPath(import.meta.url),isTest=process.env.VITEST||!1,cursor=path.dirname(modulePath);for(let i=0;i<6;i+=1){let srcCandidate=path.join(cursor,`src`,`plugin-sdk`,params.srcFile),distCandidate=path.join(cursor,`dist`,`plugin-sdk`,params.distFile),orderedCandidates=isTest?[distCandidate,srcCandidate]:[distCandidate];for(let candidate of orderedCandidates)if(fs.existsSync(candidate))return candidate;let parent=path.dirname(cursor);if(parent===cursor)break;cursor=parent}}catch{}return null},resolvePluginSdkAlias=()=>resolvePluginSdkAliasFile({srcFile:`index.ts`,distFile:`index.js`}),resolvePluginSdkAccountIdAlias=()=>resolvePluginSdkAliasFile({srcFile:`account-id.ts`,distFile:`account-id.js`});function buildCacheKey(params){return`${params.workspaceDir?resolveUserPath(params.workspaceDir):``}::${JSON.stringify(params.plugins)}`}function validatePluginConfig(params){let schema=params.schema;if(!schema)return{ok:!0,value:params.value};let result=validateJsonSchemaValue({schema,cacheKey:params.cacheKey??JSON.stringify(schema),value:params.value??{}});return result.ok?{ok:!0,value:params.value}:{ok:!1,errors:result.errors}}function resolvePluginModuleExport(moduleExport){let resolved=moduleExport&&typeof moduleExport==`object`&&`default`in moduleExport?moduleExport.default:moduleExport;if(typeof resolved==`function`)return{register:resolved};if(resolved&&typeof resolved==`object`){let def=resolved;return{definition:def,register:def.register??def.activate}}return{}}function createPluginRecord(params){return{id:params.id,name:params.name??params.id,description:params.description,version:params.version,source:params.source,origin:params.origin,workspaceDir:params.workspaceDir,enabled:params.enabled,status:params.enabled?`loaded`:`disabled`,toolNames:[],hookNames:[],channelIds:[],providerIds:[],gatewayMethods:[],cliCommands:[],services:[],commands:[],httpHandlers:0,hookCount:0,configSchema:params.configSchema,configUiHints:void 0,configJsonSchema:void 0}}function pushDiagnostics(diagnostics,append){diagnostics.push(...append)}function registerManifestHookDirs(params){for(let hookDir of params.hookDirs){let resolvedDir=path.resolve(params.rootDir,hookDir);registerPluginHooksFromDir(params.api,resolvedDir).then(hookResult=>{for(let message of hookResult.errors)params.diagnostics.push({level:`warn`,pluginId:params.record.id,source:params.record.source,message})}).catch(err=>{params.logger.warn(`[plugins] ${params.record.id} failed loading hooks from ${resolvedDir}: ${String(err)}`)})}}function loadBuilderForceAgentsPlugins(options={}){let cfg=applyTestPluginDefaults(options.config??{},process.env),logger=options.logger??defaultLogger(),validateOnly=options.mode===`validate`,normalized=normalizePluginsConfig(cfg.plugins),cacheKey=buildCacheKey({workspaceDir:options.workspaceDir,plugins:normalized}),cacheEnabled=options.cache!==!1;if(cacheEnabled){let cached=registryCache.get(cacheKey);if(cached)return setActivePluginRegistry(cached,cacheKey),cached}clearPluginCommands();let{registry,createApi}=createPluginRegistry({logger,runtime:createPluginRuntime(),coreGatewayHandlers:options.coreGatewayHandlers}),discovery=discoverBuilderForceAgentsPlugins({workspaceDir:options.workspaceDir,extraPaths:normalized.loadPaths}),manifestRegistry=loadPluginManifestRegistry({config:cfg,workspaceDir:options.workspaceDir,cache:options.cache,candidates:discovery.candidates,diagnostics:discovery.diagnostics});pushDiagnostics(registry.diagnostics,manifestRegistry.diagnostics);let jitiLoader=null,getJiti=()=>{if(jitiLoader)return jitiLoader;let pluginSdkAlias=resolvePluginSdkAlias(),pluginSdkAccountIdAlias=resolvePluginSdkAccountIdAlias();return jitiLoader=createJiti(import.meta.url,{interopDefault:!0,extensions:[`.ts`,`.tsx`,`.mts`,`.cts`,`.mtsx`,`.ctsx`,`.js`,`.mjs`,`.cjs`,`.json`],...pluginSdkAlias||pluginSdkAccountIdAlias?{alias:{...pluginSdkAlias?{"@seanhogg/builderforce-agents/plugin-sdk":pluginSdkAlias}:{},...pluginSdkAccountIdAlias?{"@seanhogg/builderforce-agents/plugin-sdk/account-id":pluginSdkAccountIdAlias}:{}}}:{}}),jitiLoader},manifestByRoot=new Map(manifestRegistry.plugins.map(record=>[record.rootDir,record])),seenIds=new Map,memorySlot=normalized.slots.memory,selectedMemoryPluginId=null,memorySlotMatched=!1;for(let candidate of discovery.candidates){let manifestRecord=manifestByRoot.get(candidate.rootDir);if(!manifestRecord)continue;let pluginId=manifestRecord.id,existingOrigin=seenIds.get(pluginId);if(existingOrigin){let record=createPluginRecord({id:pluginId,name:manifestRecord.name??pluginId,description:manifestRecord.description,version:manifestRecord.version,source:candidate.source,origin:candidate.origin,workspaceDir:candidate.workspaceDir,enabled:!1,configSchema:!!manifestRecord.configSchema});record.status=`disabled`,record.error=`overridden by ${existingOrigin} plugin`,registry.plugins.push(record);continue}let enableState=resolveEnableState(pluginId,candidate.origin,normalized),entry=normalized.entries[pluginId],record=createPluginRecord({id:pluginId,name:manifestRecord.name??pluginId,description:manifestRecord.description,version:manifestRecord.version,source:candidate.source,origin:candidate.origin,workspaceDir:candidate.workspaceDir,enabled:enableState.enabled,configSchema:!!manifestRecord.configSchema});if(record.kind=manifestRecord.kind,record.configUiHints=manifestRecord.configUiHints,record.configJsonSchema=manifestRecord.configSchema,!enableState.enabled){record.status=`disabled`,record.error=enableState.reason,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin);continue}if(!manifestRecord.configSchema){record.status=`error`,record.error=`missing config schema`,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:record.error});continue}let mod=null;try{mod=getJiti()(candidate.source)}catch(err){logger.error(`[plugins] ${record.id} failed to load from ${record.source}: ${String(err)}`),record.status=`error`,record.error=String(err),registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:`failed to load plugin: ${String(err)}`});continue}let resolved=resolvePluginModuleExport(mod),definition=resolved.definition,register=resolved.register;definition?.id&&definition.id!==record.id&&registry.diagnostics.push({level:`warn`,pluginId:record.id,source:record.source,message:`plugin id mismatch (config uses "${record.id}", export uses "${definition.id}")`}),record.name=definition?.name??record.name,record.description=definition?.description??record.description,record.version=definition?.version??record.version;let manifestKind=record.kind,exportKind=definition?.kind;manifestKind&&exportKind&&exportKind!==manifestKind&&registry.diagnostics.push({level:`warn`,pluginId:record.id,source:record.source,message:`plugin kind mismatch (manifest uses "${manifestKind}", export uses "${exportKind}")`}),record.kind=definition?.kind??record.kind,record.kind===`memory`&&memorySlot===record.id&&(memorySlotMatched=!0);let memoryDecision=resolveMemorySlotDecision({id:record.id,kind:record.kind,slot:memorySlot,selectedId:selectedMemoryPluginId});if(!memoryDecision.enabled){record.enabled=!1,record.status=`disabled`,record.error=memoryDecision.reason,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin);continue}memoryDecision.selected&&record.kind===`memory`&&(selectedMemoryPluginId=record.id);let validatedConfig=validatePluginConfig({schema:manifestRecord.configSchema,cacheKey:manifestRecord.schemaCacheKey,value:entry?.config});if(!validatedConfig.ok){logger.error(`[plugins] ${record.id} invalid config: ${validatedConfig.errors?.join(`, `)}`),record.status=`error`,record.error=`invalid config: ${validatedConfig.errors?.join(`, `)}`,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:record.error});continue}if(validateOnly){registry.plugins.push(record),seenIds.set(pluginId,candidate.origin);continue}if(typeof register!=`function`){logger.error(`[plugins] ${record.id} missing register/activate export`),record.status=`error`,record.error=`plugin export missing register/activate`,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:record.error});continue}let api=createApi(record,{config:cfg,pluginConfig:validatedConfig.value});try{let result=register(api);result&&typeof result.then==`function`&&registry.diagnostics.push({level:`warn`,pluginId:record.id,source:record.source,message:`plugin register returned a promise; async registration is ignored`}),registerManifestHookDirs({api,record,rootDir:manifestRecord.rootDir,hookDirs:manifestRecord.hooks,diagnostics:registry.diagnostics,logger}),registry.plugins.push(record),seenIds.set(pluginId,candidate.origin)}catch(err){logger.error(`[plugins] ${record.id} failed during register from ${record.source}: ${String(err)}`),record.status=`error`,record.error=String(err),registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:`plugin failed during register: ${String(err)}`})}}return typeof memorySlot==`string`&&!memorySlotMatched&&registry.diagnostics.push({level:`warn`,message:`memory slot plugin not found or not marked as memory: ${memorySlot}`}),cacheEnabled&&registryCache.set(cacheKey,registry),setActivePluginRegistry(registry,cacheKey),initializeGlobalHookRunner(registry),registry}function createPluginLoaderLogger(logger){return{info:msg=>logger.info(msg),warn:msg=>logger.warn(msg),error:msg=>logger.error(msg),debug:msg=>logger.debug?.(msg)}}const log$8=createSubsystemLogger(`plugins`),pluginToolMeta=new WeakMap;function getPluginToolMeta(tool){return pluginToolMeta.get(tool)}function normalizeAllowlist(list){return new Set((list??[]).map(normalizeToolName).filter(Boolean))}function isOptionalToolAllowed(params){if(params.allowlist.size===0)return!1;let toolName=normalizeToolName(params.toolName);if(params.allowlist.has(toolName))return!0;let pluginKey=normalizeToolName(params.pluginId);return params.allowlist.has(pluginKey)?!0:params.allowlist.has(`group:plugins`)}function resolvePluginTools(params){let effectiveConfig=applyTestPluginDefaults(params.context.config??{},process.env);if(!normalizePluginsConfig(effectiveConfig.plugins).enabled)return[];let registry=loadBuilderForceAgentsPlugins({config:effectiveConfig,workspaceDir:params.context.workspaceDir,logger:createPluginLoaderLogger(log$8)}),tools=[],existing=params.existingToolNames??new Set,existingNormalized=new Set(Array.from(existing,tool=>normalizeToolName(tool))),allowlist=normalizeAllowlist(params.toolAllowlist),blockedPlugins=new Set;for(let entry of registry.tools){if(blockedPlugins.has(entry.pluginId))continue;let pluginIdKey=normalizeToolName(entry.pluginId);if(existingNormalized.has(pluginIdKey)){let message=`plugin id conflicts with core tool name (${entry.pluginId})`;log$8.error(message),registry.diagnostics.push({level:`error`,pluginId:entry.pluginId,source:entry.source,message}),blockedPlugins.add(entry.pluginId);continue}let resolved=null;try{resolved=entry.factory(params.context)}catch(err){log$8.error(`plugin tool failed (${entry.pluginId}): ${String(err)}`);continue}if(!resolved)continue;let listRaw=Array.isArray(resolved)?resolved:[resolved],list=entry.optional?listRaw.filter(tool=>isOptionalToolAllowed({toolName:tool.name,pluginId:entry.pluginId,allowlist})):listRaw;if(list.length===0)continue;let nameSet=new Set;for(let tool of list){if(nameSet.has(tool.name)||existing.has(tool.name)){let message=`plugin tool name conflict (${entry.pluginId}): ${tool.name}`;log$8.error(message),registry.diagnostics.push({level:`error`,pluginId:entry.pluginId,source:entry.source,message});continue}nameSet.add(tool.name),existing.add(tool.name),pluginToolMeta.set(tool,{pluginId:entry.pluginId,optional:entry.optional}),tools.push(tool)}}return tools}async function defaultReadFile(filePath){return fs$1.readFile(filePath,`utf8`)}async function applyUpdateHunk(filePath,chunks,options){let originalLines=(await(options?.readFile??defaultReadFile)(filePath).catch(err=>{throw Error(`Failed to read file to update ${filePath}: ${err}`)})).split(`
172
+ `):void 0,conversationLabel=isGroup?msg.chat.title?`${msg.chat.title} id:${chatId}`:`group:${chatId}`:buildSenderName(msg)??String(senderId||chatId),ctxPayload=finalizeInboundContext({Body:prompt,BodyForAgent:prompt,RawBody:prompt,CommandBody:prompt,CommandArgs:commandArgs,From:isGroup?buildTelegramGroupFrom(chatId,resolvedThreadId):`telegram:${chatId}`,To:`slash:${senderId||chatId}`,ChatType:isGroup?`group`:`direct`,ConversationLabel:conversationLabel,GroupSubject:isGroup?msg.chat.title??void 0:void 0,GroupSystemPrompt:isGroup?groupSystemPrompt:void 0,SenderName:buildSenderName(msg),SenderId:senderId||void 0,SenderUsername:senderUsername||void 0,Surface:`telegram`,MessageSid:String(msg.message_id),Timestamp:msg.date?msg.date*1e3:void 0,WasMentioned:!0,CommandAuthorized:commandAuthorized,CommandSource:`native`,SessionKey:`telegram:slash:${senderId||chatId}`,AccountId:route.accountId,CommandTargetSessionKey:sessionKey,MessageThreadId:threadSpec.id,IsForum:isForum,OriginatingChannel:`telegram`,OriginatingTo:`telegram:${chatId}`}),disableBlockStreaming=typeof telegramCfg.blockStreaming==`boolean`?!telegramCfg.blockStreaming:void 0,deliveryState={delivered:!1,skippedNonSilent:0},{onModelSelected,...prefixOptions}=createReplyPrefixOptions({cfg,agentId:route.agentId,channel:`telegram`,accountId:route.accountId});await dispatchReplyWithBufferedBlockDispatcher({ctx:ctxPayload,cfg,dispatcherOptions:{...prefixOptions,deliver:async(payload,_info)=>{(await deliverReplies({replies:[payload],...deliveryBaseOptions})).delivered&&(deliveryState.delivered=!0)},onSkip:(_payload,info)=>{info.reason!==`silent`&&(deliveryState.skippedNonSilent+=1)},onError:(err,info)=>{runtime.error?.(danger(`telegram slash ${info.kind} reply failed: ${String(err)}`))}},replyOptions:{skillFilter,disableBlockStreaming,onModelSelected}}),!deliveryState.delivered&&deliveryState.skippedNonSilent>0&&await deliverReplies({replies:[{text:`No response generated. Please try again.`}],...deliveryBaseOptions})})}for(let pluginCommand of pluginCatalog.commands)bot.command(pluginCommand.command,async ctx=>{let msg=ctx.message;if(!msg||shouldSkipUpdate(ctx))return;let chatId=msg.chat.id,rawText=ctx.match?.trim()??``,commandBody=`/${pluginCommand.command}${rawText?` ${rawText}`:``}`,match=matchPluginCommand(commandBody);if(!match){await withTelegramApiErrorLogging({operation:`sendMessage`,runtime,fn:()=>bot.api.sendMessage(chatId,`Command not found.`)});return}let auth=await resolveTelegramCommandAuth({msg,bot,cfg,accountId,telegramCfg,allowFrom,groupAllowFrom,useAccessGroups,resolveGroupPolicy,resolveTelegramGroupConfig,requireAuth:match.command.requireAuth!==!1});if(!auth)return;let{senderId,commandAuthorized,isGroup,isForum,resolvedThreadId}=auth,{threadSpec,mediaLocalRoots,tableMode,chunkMode}=resolveCommandRuntimeContext({msg,isGroup,isForum,resolvedThreadId}),deliveryBaseOptions=buildCommandDeliveryBaseOptions({chatId,mediaLocalRoots,threadSpec,tableMode,chunkMode}),from=isGroup?buildTelegramGroupFrom(chatId,threadSpec.id):`telegram:${chatId}`,to=`telegram:${chatId}`;await deliverReplies({replies:[await executePluginCommand({command:match.command,args:match.args,senderId,channel:`telegram`,isAuthorizedSender:commandAuthorized,commandBody,config:cfg,from,to,accountId,messageThreadId:threadSpec.id})],...deliveryBaseOptions})})}else nativeDisabledExplicit&&withTelegramApiErrorLogging({operation:`setMyCommands`,runtime,fn:()=>bot.api.setMyCommands([])}).catch(()=>{})};function getTelegramSequentialKey(ctx){let reaction=ctx.update?.message_reaction;if(reaction?.chat?.id)return`telegram:${reaction.chat.id}`;let msg=ctx.message??ctx.channelPost??ctx.editedChannelPost??ctx.update?.message??ctx.update?.edited_message??ctx.update?.channel_post??ctx.update?.edited_channel_post??ctx.update?.callback_query?.message,chatId=msg?.chat?.id??ctx.chat?.id,rawText=msg?.text??msg?.caption,botUsername=ctx.me?.username;if(isAbortRequestText(rawText,botUsername?{botUsername}:void 0))return typeof chatId==`number`?`telegram:${chatId}:control`:`telegram:control`;let isGroup=msg?.chat?.type===`group`||msg?.chat?.type===`supergroup`,messageThreadId=msg?.message_thread_id,isForum=msg?.chat?.is_forum,threadId=isGroup?resolveTelegramForumThreadId({isForum,messageThreadId}):messageThreadId;return typeof chatId==`number`?threadId==null?`telegram:${chatId}`:`telegram:${chatId}:topic:${threadId}`:`telegram:unknown`}function createTelegramBot(opts){let runtime=opts.runtime??{log:console.log,error:console.error,exit:code=>{throw Error(`exit ${code}`)}},cfg=opts.config??loadConfig(),account=resolveTelegramAccount({cfg,accountId:opts.accountId}),telegramCfg=account.config,fetchImpl=resolveTelegramFetch(opts.proxyFetch,{network:telegramCfg.network}),shouldProvideFetch=!!fetchImpl,fetchForClient=fetchImpl,timeoutSeconds=typeof telegramCfg?.timeoutSeconds==`number`&&Number.isFinite(telegramCfg.timeoutSeconds)?Math.max(1,Math.floor(telegramCfg.timeoutSeconds)):void 0,client=shouldProvideFetch||timeoutSeconds?{...shouldProvideFetch&&fetchImpl?{fetch:fetchForClient}:{},...timeoutSeconds?{timeoutSeconds}:{}}:void 0,bot=new Bot(opts.token,client?{client}:void 0);bot.api.config.use(apiThrottler()),bot.use(sequentialize(getTelegramSequentialKey)),bot.catch(err=>{runtime.error?.(danger(`telegram bot error: ${formatUncaughtError(err)}`))});let recentUpdates=createTelegramUpdateDedupe(),lastUpdateId=typeof opts.updateOffset?.lastUpdateId==`number`?opts.updateOffset.lastUpdateId:null,recordUpdateId=ctx=>{let updateId=resolveTelegramUpdateId(ctx);typeof updateId==`number`&&(lastUpdateId!==null&&updateId<=lastUpdateId||(lastUpdateId=updateId,opts.updateOffset?.onUpdateId?.(updateId)))},shouldSkipUpdate=ctx=>{let updateId=resolveTelegramUpdateId(ctx);if(typeof updateId==`number`&&lastUpdateId!==null&&updateId<=lastUpdateId)return!0;let key=buildTelegramUpdateKey(ctx),skipped=recentUpdates.check(key);return skipped&&key&&shouldLogVerbose()&&logVerbose(`telegram dedupe: skipped ${key}`),skipped},rawUpdateLogger=createSubsystemLogger(`gateway/channels/telegram/raw-update`),MAX_RAW_UPDATE_CHARS=8e3,stringifyUpdate=update=>{let seen=new WeakSet;return JSON.stringify(update??null,(key,value)=>{if(typeof value==`string`&&value.length>500)return`${value.slice(0,500)}...`;if(Array.isArray(value)&&value.length>20)return[...value.slice(0,20),`...(${value.length-20} more)`];if(value&&typeof value==`object`){if(seen.has(value))return`[Circular]`;seen.add(value)}return value})};bot.use(async(ctx,next)=>{if(shouldLogVerbose())try{let raw=stringifyUpdate(ctx.update),preview=raw.length>MAX_RAW_UPDATE_CHARS?`${raw.slice(0,MAX_RAW_UPDATE_CHARS)}...`:raw;rawUpdateLogger.debug(`telegram update: ${preview}`)}catch(err){rawUpdateLogger.debug(`telegram update log failed: ${String(err)}`)}await next(),recordUpdateId(ctx)});let historyLimit=Math.max(0,telegramCfg.historyLimit??cfg.messages?.groupChat?.historyLimit??50),groupHistories=new Map,textLimit=resolveTextChunkLimit(cfg,`telegram`,account.accountId),dmPolicy=telegramCfg.dmPolicy??`pairing`,allowFrom=opts.allowFrom??telegramCfg.allowFrom,groupAllowFrom=opts.groupAllowFrom??telegramCfg.groupAllowFrom??(telegramCfg.allowFrom&&telegramCfg.allowFrom.length>0?telegramCfg.allowFrom:void 0)??(opts.allowFrom&&opts.allowFrom.length>0?opts.allowFrom:void 0),replyToMode=opts.replyToMode??telegramCfg.replyToMode??`off`,nativeEnabled=resolveNativeCommandsEnabled({providerId:`telegram`,providerSetting:telegramCfg.commands?.native,globalSetting:cfg.commands?.native}),nativeSkillsEnabled=resolveNativeSkillsEnabled({providerId:`telegram`,providerSetting:telegramCfg.commands?.nativeSkills,globalSetting:cfg.commands?.nativeSkills}),nativeDisabledExplicit=isNativeCommandsExplicitlyDisabled({providerSetting:telegramCfg.commands?.native,globalSetting:cfg.commands?.native}),useAccessGroups=cfg.commands?.useAccessGroups!==!1,ackReactionScope=cfg.messages?.ackReactionScope??`group-mentions`,mediaMaxBytes=(opts.mediaMaxMb??telegramCfg.mediaMaxMb??5)*1024*1024,logger=getChildLogger({module:`telegram-auto-reply`}),streamMode=resolveTelegramStreamMode(telegramCfg),resolveGroupPolicy=chatId=>resolveChannelGroupPolicy({cfg,channel:`telegram`,accountId:account.accountId,groupId:String(chatId)}),resolveGroupActivation=params=>{let agentId=params.agentId??resolveDefaultAgentId(cfg),sessionKey=params.sessionKey??`agent:${agentId}:telegram:group:${buildTelegramGroupPeerId(params.chatId,params.messageThreadId)}`,storePath=resolveStorePath(cfg.session?.store,{agentId});try{let entry=loadSessionStore(storePath)[sessionKey];if(entry?.groupActivation===`always`)return!1;if(entry?.groupActivation===`mention`)return!0}catch(err){logVerbose(`Failed to load session for activation check: ${String(err)}`)}},resolveGroupRequireMention=chatId=>resolveChannelGroupRequireMention({cfg,channel:`telegram`,accountId:account.accountId,groupId:String(chatId),requireMentionOverride:opts.requireMention,overrideOrder:`after-config`}),resolveTelegramGroupConfig=(chatId,messageThreadId)=>{let groups=telegramCfg.groups;if(!groups)return{groupConfig:void 0,topicConfig:void 0};let groupConfig=groups[String(chatId)]??groups[`*`];return{groupConfig,topicConfig:messageThreadId==null?void 0:groupConfig?.topics?.[String(messageThreadId)]}},processMessage=createTelegramMessageProcessor({bot,cfg,account,telegramCfg,historyLimit,groupHistories,dmPolicy,allowFrom,groupAllowFrom,ackReactionScope,logger,resolveGroupActivation,resolveGroupRequireMention,resolveTelegramGroupConfig,runtime,replyToMode,streamMode,textLimit,opts});return registerTelegramNativeCommands({bot,cfg,runtime,accountId:account.accountId,telegramCfg,allowFrom,groupAllowFrom,replyToMode,textLimit,useAccessGroups,nativeEnabled,nativeSkillsEnabled,nativeDisabledExplicit,resolveGroupPolicy,resolveTelegramGroupConfig,shouldSkipUpdate,opts}),registerTelegramHandlers({cfg,accountId:account.accountId,bot,opts,runtime,mediaMaxBytes,telegramCfg,groupAllowFrom,resolveGroupPolicy,resolveTelegramGroupConfig,shouldSkipUpdate,processMessage,logger}),bot}function normalizeAccountId(accountId){let trimmed=accountId?.trim();return trimmed?trimmed.replace(/[^a-z0-9._-]+/gi,`_`):`default`}function resolveTelegramUpdateOffsetPath(accountId,env=process.env){let stateDir=resolveStateDir(env,os.homedir),normalized=normalizeAccountId(accountId);return path.join(stateDir,`telegram`,`update-offset-${normalized}.json`)}function safeParseState(raw){try{let parsed=JSON.parse(raw);return parsed?.version!==1||parsed.lastUpdateId!==null&&typeof parsed.lastUpdateId!=`number`?null:parsed}catch{return null}}async function readTelegramUpdateOffset(params){let filePath=resolveTelegramUpdateOffsetPath(params.accountId,params.env);try{return safeParseState(await fs$1.readFile(filePath,`utf-8`))?.lastUpdateId??null}catch(err){return err.code,null}}async function writeTelegramUpdateOffset(params){let filePath=resolveTelegramUpdateOffsetPath(params.accountId,params.env),dir=path.dirname(filePath);await fs$1.mkdir(dir,{recursive:!0,mode:448});let tmp=path.join(dir,`${path.basename(filePath)}.${crypto.randomUUID()}.tmp`),payload={version:1,lastUpdateId:params.updateId};await fs$1.writeFile(tmp,`${JSON.stringify(payload,null,2)}\n`,{encoding:`utf-8`}),await fs$1.chmod(tmp,384),await fs$1.rename(tmp,filePath)}async function deleteTelegramUpdateOffset(params){let filePath=resolveTelegramUpdateOffsetPath(params.accountId,params.env);try{await fs$1.unlink(filePath)}catch(err){if(err.code===`ENOENT`)return;throw err}}async function startTelegramWebhook(opts){let path=opts.path??`/telegram-webhook`,healthPath=opts.healthPath??`/healthz`,port=opts.port??8787,host=opts.host??`127.0.0.1`,secret=typeof opts.secret==`string`?opts.secret.trim():``;if(!secret)throw Error(`Telegram webhook mode requires a non-empty secret token. Set channels.telegram.webhookSecret in your config.`);let runtime=opts.runtime??defaultRuntime,diagnosticsEnabled=isDiagnosticsEnabled(opts.config),bot=createTelegramBot({token:opts.token,runtime,proxyFetch:opts.fetch,config:opts.config,accountId:opts.accountId}),handler=webhookCallback(bot,`http`,{secretToken:secret,onTimeout:`return`,timeoutMilliseconds:1e4});diagnosticsEnabled&&startDiagnosticHeartbeat();let server=createServer((req,res)=>{if(req.url===healthPath){res.writeHead(200),res.end(`ok`);return}if(req.url!==path||req.method!==`POST`){res.writeHead(404),res.end();return}let startTime=Date.now();diagnosticsEnabled&&logWebhookReceived({channel:`telegram`,updateType:`telegram-post`});let guard=installRequestBodyLimitGuard(req,res,{maxBytes:1048576,timeoutMs:3e4,responseFormat:`text`});if(guard.isTripped())return;let handled=handler(req,res);if(handled&&typeof handled.catch==`function`){handled.then(()=>{diagnosticsEnabled&&logWebhookProcessed({channel:`telegram`,updateType:`telegram-post`,durationMs:Date.now()-startTime})}).catch(err=>{if(guard.isTripped())return;let errMsg=formatErrorMessage(err);diagnosticsEnabled&&logWebhookError({channel:`telegram`,updateType:`telegram-post`,error:errMsg}),runtime.log?.(`webhook handler failed: ${errMsg}`),res.headersSent||res.writeHead(500),res.end()}).finally(()=>{guard.dispose()});return}guard.dispose()}),publicUrl=opts.publicUrl??`http://${host===`0.0.0.0`?`localhost`:host}:${port}${path}`;await withTelegramApiErrorLogging({operation:`setWebhook`,runtime,fn:()=>bot.api.setWebhook(publicUrl,{secret_token:secret,allowed_updates:resolveTelegramAllowedUpdates()})}),await new Promise(resolve=>server.listen(port,host,resolve)),runtime.log?.(`webhook listening on ${publicUrl}`);let shutdown=()=>{server.close(),bot.stop(),diagnosticsEnabled&&stopDiagnosticHeartbeat()};return opts.abortSignal&&opts.abortSignal.addEventListener(`abort`,shutdown,{once:!0}),{server,bot,stop:shutdown}}function createTelegramRunnerOptions(cfg){return{sink:{concurrency:resolveAgentMaxConcurrent(cfg)},runner:{fetch:{timeout:30,allowed_updates:resolveTelegramAllowedUpdates()},silent:!0,maxRetryTime:300*1e3,retryInterval:`exponential`}}}const TELEGRAM_POLL_RESTART_POLICY={initialMs:2e3,maxMs:3e4,factor:1.8,jitter:.25},isGetUpdatesConflict=err=>{if(!err||typeof err!=`object`)return!1;let typed=err;return(typed.error_code??typed.errorCode)===409?[typed.method,typed.description,typed.message].filter(value=>typeof value==`string`).join(` `).toLowerCase().includes(`getupdates`):!1},isGrammyHttpError=err=>!err||typeof err!=`object`?!1:err.name===`HttpError`;async function monitorTelegramProvider(opts={}){let log=opts.runtime?.error??console.error,unregisterHandler=registerUnhandledRejectionHandler(err=>isGrammyHttpError(err)&&isRecoverableTelegramNetworkError(err,{context:`polling`})?(log(`[telegram] Suppressed network error: ${formatErrorMessage(err)}`),!0):!1);try{let cfg=opts.config??loadConfig(),account=resolveTelegramAccount({cfg,accountId:opts.accountId}),token=opts.token?.trim()||account.token;if(!token)throw Error(`Telegram bot token missing for account "${account.accountId}" (set channels.telegram.accounts.${account.accountId}.botToken/tokenFile or TELEGRAM_BOT_TOKEN for default).`);let proxyFetch=opts.proxyFetch??(account.config.proxy?makeProxyFetch(account.config.proxy):void 0),lastUpdateId=await readTelegramUpdateOffset({accountId:account.accountId}),bot=createTelegramBot({token,runtime:opts.runtime,proxyFetch,config:cfg,accountId:account.accountId,updateOffset:{lastUpdateId,onUpdateId:async updateId=>{if(!(lastUpdateId!==null&&updateId<=lastUpdateId)){lastUpdateId=updateId;try{await writeTelegramUpdateOffset({accountId:account.accountId,updateId})}catch(err){(opts.runtime?.error??console.error)(`telegram: failed to persist update offset: ${String(err)}`)}}}}});if(opts.useWebhook){await startTelegramWebhook({token,accountId:account.accountId,config:cfg,path:opts.webhookPath,port:opts.webhookPort,secret:opts.webhookSecret??account.config.webhookSecret,host:opts.webhookHost??account.config.webhookHost,runtime:opts.runtime,fetch:proxyFetch,abortSignal:opts.abortSignal,publicUrl:opts.webhookUrl});return}let restartAttempts=0;for(;!opts.abortSignal?.aborted;){let runner=run(bot,createTelegramRunnerOptions(cfg)),stopOnAbort=()=>{opts.abortSignal?.aborted&&runner.stop()};opts.abortSignal?.addEventListener(`abort`,stopOnAbort,{once:!0});try{await runner.task();return}catch(err){if(opts.abortSignal?.aborted)throw err;let isConflict=isGetUpdatesConflict(err),isRecoverable=isRecoverableTelegramNetworkError(err,{context:`polling`});if(!isConflict&&!isRecoverable)throw err;restartAttempts+=1;let delayMs=computeBackoff(TELEGRAM_POLL_RESTART_POLICY,restartAttempts),reason=isConflict?`getUpdates conflict`:`network error`,errMsg=formatErrorMessage(err);(opts.runtime?.error??console.error)(`Telegram ${reason}: ${errMsg}; retrying in ${formatDurationPrecise(delayMs)}.`);try{await sleepWithAbort(delayMs,opts.abortSignal)}catch(sleepErr){if(opts.abortSignal?.aborted)return;throw sleepErr}}finally{opts.abortSignal?.removeEventListener(`abort`,stopOnAbort)}}}finally{unregisterHandler()}}async function probeTelegram(token,timeoutMs,proxyUrl){let started=Date.now(),fetcher=proxyUrl?makeProxyFetch(proxyUrl):fetch,base=`https://api.telegram.org/bot${token}`,retryDelayMs=Math.max(50,Math.min(1e3,timeoutMs)),result={ok:!1,status:null,error:null,elapsedMs:0};try{let meRes=null,fetchError=null;for(let i=0;i<3;i++)try{meRes=await fetchWithTimeout(`${base}/getMe`,{},timeoutMs,fetcher);break}catch(err){fetchError=err,i<2&&await new Promise(resolve=>setTimeout(resolve,retryDelayMs))}if(!meRes)throw fetchError;let meJson=await meRes.json();if(!meRes.ok||!meJson?.ok)return result.status=meRes.status,result.error=meJson?.description??`getMe failed (${meRes.status})`,{...result,elapsedMs:Date.now()-started};result.bot={id:meJson.result?.id??null,username:meJson.result?.username??null,canJoinGroups:typeof meJson.result?.can_join_groups==`boolean`?meJson.result?.can_join_groups:null,canReadAllGroupMessages:typeof meJson.result?.can_read_all_group_messages==`boolean`?meJson.result?.can_read_all_group_messages:null,supportsInlineQueries:typeof meJson.result?.supports_inline_queries==`boolean`?meJson.result?.supports_inline_queries:null};try{let webhookRes=await fetchWithTimeout(`${base}/getWebhookInfo`,{},timeoutMs,fetcher),webhookJson=await webhookRes.json();webhookRes.ok&&webhookJson?.ok&&(result.webhook={url:webhookJson.result?.url??null,hasCustomCert:webhookJson.result?.has_custom_certificate??null})}catch{}return result.ok=!0,result.status=null,result.error=null,result.elapsedMs=Date.now()-started,result}catch(err){return{...result,status:err instanceof Response?err.status:result.status,error:err instanceof Error?err.message:String(err),elapsedMs:Date.now()-started}}}function formatNativeDependencyHint(params){let manager=params.manager??`pnpm`,rebuildCommand=params.rebuildCommand??(manager===`npm`?`npm rebuild ${params.packageName}`:manager===`yarn`?`yarn rebuild ${params.packageName}`:`pnpm rebuild ${params.packageName}`),steps=[params.approveBuildsCommand??(manager===`pnpm`?`pnpm approve-builds (select ${params.packageName})`:void 0),rebuildCommand,params.downloadCommand].filter(step=>!!step);return steps.length===0?`Install ${params.packageName} and rebuild its native module.`:`Install ${params.packageName} and rebuild its native module (${steps.join(`; `)}).`}let cachedVersion=null;function resolveVersion(){if(cachedVersion)return cachedVersion;try{return cachedVersion=createRequire(import.meta.url)(`../../../package.json`).version??`unknown`,cachedVersion}catch{return cachedVersion=`unknown`,cachedVersion}}const sendMessageWhatsAppLazy=async(...args)=>{let{sendMessageWhatsApp}=await loadWebOutbound();return sendMessageWhatsApp(...args)},sendPollWhatsAppLazy=async(...args)=>{let{sendPollWhatsApp}=await loadWebOutbound();return sendPollWhatsApp(...args)},loginWebLazy=async(...args)=>{let{loginWeb}=await loadWebLogin();return loginWeb(...args)},startWebLoginWithQrLazy=async(...args)=>{let{startWebLoginWithQr}=await loadWebLoginQr();return startWebLoginWithQr(...args)},waitForWebLoginLazy=async(...args)=>{let{waitForWebLogin}=await loadWebLoginQr();return waitForWebLogin(...args)},monitorWebChannelLazy=async(...args)=>{let{monitorWebChannel}=await loadWebChannel();return monitorWebChannel(...args)},handleWhatsAppActionLazy=async(...args)=>{let{handleWhatsAppAction}=await loadWhatsAppActions();return handleWhatsAppAction(...args)};let webOutboundPromise=null,webLoginPromise=null,webLoginQrPromise=null,webChannelPromise=null,whatsappActionsPromise=null;function loadWebOutbound(){return webOutboundPromise??=import(`./outbound-Cnu8bKIe.js`),webOutboundPromise}function loadWebLogin(){return webLoginPromise??=import(`./login-sr1eysDj.js`),webLoginPromise}function loadWebLoginQr(){return webLoginQrPromise??=import(`./login-qr-ClJYLoca.js`),webLoginQrPromise}function loadWebChannel(){return webChannelPromise??=import(`./web--D7qJmx6.js`),webChannelPromise}function loadWhatsAppActions(){return whatsappActionsPromise??=import(`./whatsapp-actions-Bvdy4Cod.js`),whatsappActionsPromise}function createPluginRuntime(){return{version:resolveVersion(),config:{loadConfig,writeConfigFile},system:{enqueueSystemEvent,runCommandWithTimeout,formatNativeDependencyHint},media:{loadWebMedia,detectMime,mediaKindFromMime,isVoiceCompatibleAudio,getImageMetadata,resizeToJpeg},tts:{textToSpeechTelephony},tools:{createMemoryGetTool,createMemorySearchTool,registerMemoryCli},channel:{text:{chunkByNewline,chunkMarkdownText,chunkMarkdownTextWithMode,chunkText,chunkTextWithMode,resolveChunkMode,resolveTextChunkLimit,hasControlCommand,resolveMarkdownTableMode,convertMarkdownTables},reply:{dispatchReplyWithBufferedBlockDispatcher,createReplyDispatcherWithTyping,resolveEffectiveMessagesConfig,resolveHumanDelayConfig,dispatchReplyFromConfig,finalizeInboundContext,formatAgentEnvelope,formatInboundEnvelope,resolveEnvelopeFormatOptions},routing:{resolveAgentRoute},pairing:{buildPairingReply,readAllowFromStore:readChannelAllowFromStore,upsertPairingRequest:upsertChannelPairingRequest},media:{fetchRemoteMedia,saveMediaBuffer},activity:{record:recordChannelActivity,get:getChannelActivity},session:{resolveStorePath,readSessionUpdatedAt,recordSessionMetaFromInbound,recordInboundSession,updateLastRoute},mentions:{buildMentionRegexes,matchesMentionPatterns,matchesMentionWithExplicit},reactions:{shouldAckReaction,removeAckReactionAfterReply},groups:{resolveGroupPolicy:resolveChannelGroupPolicy,resolveRequireMention:resolveChannelGroupRequireMention},debounce:{createInboundDebouncer,resolveInboundDebounceMs},commands:{resolveCommandAuthorizedFromAuthorizers,isControlCommandMessage,shouldComputeCommandAuthorized,shouldHandleTextCommands},discord:{messageActions:discordMessageActions,auditChannelPermissions:auditDiscordChannelPermissions,listDirectoryGroupsLive:listDiscordDirectoryGroupsLive,listDirectoryPeersLive:listDiscordDirectoryPeersLive,probeDiscord,resolveChannelAllowlist:resolveDiscordChannelAllowlist,resolveUserAllowlist:resolveDiscordUserAllowlist,sendMessageDiscord,sendPollDiscord,monitorDiscordProvider},slack:{listDirectoryGroupsLive:listSlackDirectoryGroupsLive,listDirectoryPeersLive:listSlackDirectoryPeersLive,probeSlack,resolveChannelAllowlist:resolveSlackChannelAllowlist,resolveUserAllowlist:resolveSlackUserAllowlist,sendMessageSlack,monitorSlackProvider,handleSlackAction},telegram:{auditGroupMembership:auditTelegramGroupMembership,collectUnmentionedGroupIds:collectTelegramUnmentionedGroupIds,probeTelegram,resolveTelegramToken,sendMessageTelegram,sendPollTelegram,monitorTelegramProvider,messageActions:telegramMessageActions},signal:{probeSignal,sendMessageSignal,monitorSignalProvider,messageActions:signalMessageActions},imessage:{monitorIMessageProvider,probeIMessage,sendMessageIMessage},whatsapp:{getActiveWebListener,getWebAuthAgeMs,logoutWeb,logWebSelfId,readWebSelfId,webAuthExists,sendMessageWhatsApp:sendMessageWhatsAppLazy,sendPollWhatsApp:sendPollWhatsAppLazy,loginWeb:loginWebLazy,startWebLoginWithQr:startWebLoginWithQrLazy,waitForWebLogin:waitForWebLoginLazy,monitorWebChannel:monitorWebChannelLazy,handleWhatsAppAction:handleWhatsAppActionLazy,createLoginTool:createWhatsAppLoginTool},line:{listLineAccountIds,resolveDefaultLineAccountId,resolveLineAccount,normalizeAccountId:normalizeAccountId$1,probeLineBot,sendMessageLine,pushMessageLine,pushMessagesLine,pushFlexMessage,pushTemplateMessage,pushLocationMessage,pushTextMessageWithQuickReplies,createQuickReplyItems,buildTemplateMessageFromPayload,monitorLineProvider}},logging:{shouldLogVerbose,getChildLogger:(bindings,opts)=>{let logger=getChildLogger(bindings,{level:opts?.level?normalizeLogLevel(opts.level):void 0});return{debug:message=>logger.debug?.(message),info:message=>logger.info(message),warn:message=>logger.warn(message),error:message=>logger.error(message)}}},state:{resolveStateDir}}}const registryCache=new Map,defaultLogger=()=>createSubsystemLogger(`plugins`),resolvePluginSdkAliasFile=params=>{try{let modulePath=fileURLToPath(import.meta.url),isTest=process.env.VITEST||!1,cursor=path.dirname(modulePath);for(let i=0;i<6;i+=1){let srcCandidate=path.join(cursor,`src`,`plugin-sdk`,params.srcFile),distCandidate=path.join(cursor,`dist`,`plugin-sdk`,params.distFile),orderedCandidates=isTest?[distCandidate,srcCandidate]:[distCandidate];for(let candidate of orderedCandidates)if(fs.existsSync(candidate))return candidate;let parent=path.dirname(cursor);if(parent===cursor)break;cursor=parent}}catch{}return null},resolvePluginSdkAlias=()=>resolvePluginSdkAliasFile({srcFile:`index.ts`,distFile:`index.js`}),resolvePluginSdkAccountIdAlias=()=>resolvePluginSdkAliasFile({srcFile:`account-id.ts`,distFile:`account-id.js`});function buildCacheKey(params){return`${params.workspaceDir?resolveUserPath(params.workspaceDir):``}::${JSON.stringify(params.plugins)}`}function validatePluginConfig(params){let schema=params.schema;if(!schema)return{ok:!0,value:params.value};let result=validateJsonSchemaValue({schema,cacheKey:params.cacheKey??JSON.stringify(schema),value:params.value??{}});return result.ok?{ok:!0,value:params.value}:{ok:!1,errors:result.errors}}function resolvePluginModuleExport(moduleExport){let resolved=moduleExport&&typeof moduleExport==`object`&&`default`in moduleExport?moduleExport.default:moduleExport;if(typeof resolved==`function`)return{register:resolved};if(resolved&&typeof resolved==`object`){let def=resolved;return{definition:def,register:def.register??def.activate}}return{}}function createPluginRecord(params){return{id:params.id,name:params.name??params.id,description:params.description,version:params.version,source:params.source,origin:params.origin,workspaceDir:params.workspaceDir,enabled:params.enabled,status:params.enabled?`loaded`:`disabled`,toolNames:[],hookNames:[],channelIds:[],providerIds:[],gatewayMethods:[],cliCommands:[],services:[],commands:[],httpHandlers:0,hookCount:0,configSchema:params.configSchema,configUiHints:void 0,configJsonSchema:void 0}}function pushDiagnostics(diagnostics,append){diagnostics.push(...append)}function registerManifestHookDirs(params){for(let hookDir of params.hookDirs){let resolvedDir=path.resolve(params.rootDir,hookDir);registerPluginHooksFromDir(params.api,resolvedDir).then(hookResult=>{for(let message of hookResult.errors)params.diagnostics.push({level:`warn`,pluginId:params.record.id,source:params.record.source,message})}).catch(err=>{params.logger.warn(`[plugins] ${params.record.id} failed loading hooks from ${resolvedDir}: ${String(err)}`)})}}function loadBuilderForceAgentsPlugins(options={}){let cfg=applyTestPluginDefaults(options.config??{},process.env),logger=options.logger??defaultLogger(),validateOnly=options.mode===`validate`,normalized=normalizePluginsConfig(cfg.plugins),cacheKey=buildCacheKey({workspaceDir:options.workspaceDir,plugins:normalized}),cacheEnabled=options.cache!==!1;if(cacheEnabled){let cached=registryCache.get(cacheKey);if(cached)return setActivePluginRegistry(cached,cacheKey),cached}clearPluginCommands();let{registry,createApi}=createPluginRegistry({logger,runtime:createPluginRuntime(),coreGatewayHandlers:options.coreGatewayHandlers}),discovery=discoverBuilderForceAgentsPlugins({workspaceDir:options.workspaceDir,extraPaths:normalized.loadPaths}),manifestRegistry=loadPluginManifestRegistry({config:cfg,workspaceDir:options.workspaceDir,cache:options.cache,candidates:discovery.candidates,diagnostics:discovery.diagnostics});pushDiagnostics(registry.diagnostics,manifestRegistry.diagnostics);let jitiLoader=null,getJiti=()=>{if(jitiLoader)return jitiLoader;let pluginSdkAlias=resolvePluginSdkAlias(),pluginSdkAccountIdAlias=resolvePluginSdkAccountIdAlias();return jitiLoader=createJiti(import.meta.url,{interopDefault:!0,extensions:[`.ts`,`.tsx`,`.mts`,`.cts`,`.mtsx`,`.ctsx`,`.js`,`.mjs`,`.cjs`,`.json`],...pluginSdkAlias||pluginSdkAccountIdAlias?{alias:{...pluginSdkAlias?{"@seanhogg/builderforce-agents/plugin-sdk":pluginSdkAlias}:{},...pluginSdkAccountIdAlias?{"@seanhogg/builderforce-agents/plugin-sdk/account-id":pluginSdkAccountIdAlias}:{}}}:{}}),jitiLoader},manifestByRoot=new Map(manifestRegistry.plugins.map(record=>[record.rootDir,record])),seenIds=new Map,memorySlot=normalized.slots.memory,selectedMemoryPluginId=null,memorySlotMatched=!1;for(let candidate of discovery.candidates){let manifestRecord=manifestByRoot.get(candidate.rootDir);if(!manifestRecord)continue;let pluginId=manifestRecord.id,existingOrigin=seenIds.get(pluginId);if(existingOrigin){let record=createPluginRecord({id:pluginId,name:manifestRecord.name??pluginId,description:manifestRecord.description,version:manifestRecord.version,source:candidate.source,origin:candidate.origin,workspaceDir:candidate.workspaceDir,enabled:!1,configSchema:!!manifestRecord.configSchema});record.status=`disabled`,record.error=`overridden by ${existingOrigin} plugin`,registry.plugins.push(record);continue}let enableState=resolveEnableState(pluginId,candidate.origin,normalized),entry=normalized.entries[pluginId],record=createPluginRecord({id:pluginId,name:manifestRecord.name??pluginId,description:manifestRecord.description,version:manifestRecord.version,source:candidate.source,origin:candidate.origin,workspaceDir:candidate.workspaceDir,enabled:enableState.enabled,configSchema:!!manifestRecord.configSchema});if(record.kind=manifestRecord.kind,record.configUiHints=manifestRecord.configUiHints,record.configJsonSchema=manifestRecord.configSchema,!enableState.enabled){record.status=`disabled`,record.error=enableState.reason,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin);continue}if(!manifestRecord.configSchema){record.status=`error`,record.error=`missing config schema`,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:record.error});continue}let mod=null;try{mod=getJiti()(candidate.source)}catch(err){logger.error(`[plugins] ${record.id} failed to load from ${record.source}: ${String(err)}`),record.status=`error`,record.error=String(err),registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:`failed to load plugin: ${String(err)}`});continue}let resolved=resolvePluginModuleExport(mod),definition=resolved.definition,register=resolved.register;definition?.id&&definition.id!==record.id&&registry.diagnostics.push({level:`warn`,pluginId:record.id,source:record.source,message:`plugin id mismatch (config uses "${record.id}", export uses "${definition.id}")`}),record.name=definition?.name??record.name,record.description=definition?.description??record.description,record.version=definition?.version??record.version;let manifestKind=record.kind,exportKind=definition?.kind;manifestKind&&exportKind&&exportKind!==manifestKind&&registry.diagnostics.push({level:`warn`,pluginId:record.id,source:record.source,message:`plugin kind mismatch (manifest uses "${manifestKind}", export uses "${exportKind}")`}),record.kind=definition?.kind??record.kind,record.kind===`memory`&&memorySlot===record.id&&(memorySlotMatched=!0);let memoryDecision=resolveMemorySlotDecision({id:record.id,kind:record.kind,slot:memorySlot,selectedId:selectedMemoryPluginId});if(!memoryDecision.enabled){record.enabled=!1,record.status=`disabled`,record.error=memoryDecision.reason,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin);continue}memoryDecision.selected&&record.kind===`memory`&&(selectedMemoryPluginId=record.id);let validatedConfig=validatePluginConfig({schema:manifestRecord.configSchema,cacheKey:manifestRecord.schemaCacheKey,value:entry?.config});if(!validatedConfig.ok){logger.error(`[plugins] ${record.id} invalid config: ${validatedConfig.errors?.join(`, `)}`),record.status=`error`,record.error=`invalid config: ${validatedConfig.errors?.join(`, `)}`,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:record.error});continue}if(validateOnly){registry.plugins.push(record),seenIds.set(pluginId,candidate.origin);continue}if(typeof register!=`function`){logger.error(`[plugins] ${record.id} missing register/activate export`),record.status=`error`,record.error=`plugin export missing register/activate`,registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:record.error});continue}let api=createApi(record,{config:cfg,pluginConfig:validatedConfig.value});try{let result=register(api);result&&typeof result.then==`function`&&registry.diagnostics.push({level:`warn`,pluginId:record.id,source:record.source,message:`plugin register returned a promise; async registration is ignored`}),registerManifestHookDirs({api,record,rootDir:manifestRecord.rootDir,hookDirs:manifestRecord.hooks,diagnostics:registry.diagnostics,logger}),registry.plugins.push(record),seenIds.set(pluginId,candidate.origin)}catch(err){logger.error(`[plugins] ${record.id} failed during register from ${record.source}: ${String(err)}`),record.status=`error`,record.error=String(err),registry.plugins.push(record),seenIds.set(pluginId,candidate.origin),registry.diagnostics.push({level:`error`,pluginId:record.id,source:record.source,message:`plugin failed during register: ${String(err)}`})}}return typeof memorySlot==`string`&&!memorySlotMatched&&registry.diagnostics.push({level:`warn`,message:`memory slot plugin not found or not marked as memory: ${memorySlot}`}),cacheEnabled&&registryCache.set(cacheKey,registry),setActivePluginRegistry(registry,cacheKey),initializeGlobalHookRunner(registry),registry}function createPluginLoaderLogger(logger){return{info:msg=>logger.info(msg),warn:msg=>logger.warn(msg),error:msg=>logger.error(msg),debug:msg=>logger.debug?.(msg)}}const log$8=createSubsystemLogger(`plugins`),pluginToolMeta=new WeakMap;function getPluginToolMeta(tool){return pluginToolMeta.get(tool)}function normalizeAllowlist(list){return new Set((list??[]).map(normalizeToolName).filter(Boolean))}function isOptionalToolAllowed(params){if(params.allowlist.size===0)return!1;let toolName=normalizeToolName(params.toolName);if(params.allowlist.has(toolName))return!0;let pluginKey=normalizeToolName(params.pluginId);return params.allowlist.has(pluginKey)?!0:params.allowlist.has(`group:plugins`)}function resolvePluginTools(params){let effectiveConfig=applyTestPluginDefaults(params.context.config??{},process.env);if(!normalizePluginsConfig(effectiveConfig.plugins).enabled)return[];let registry=loadBuilderForceAgentsPlugins({config:effectiveConfig,workspaceDir:params.context.workspaceDir,logger:createPluginLoaderLogger(log$8)}),tools=[],existing=params.existingToolNames??new Set,existingNormalized=new Set(Array.from(existing,tool=>normalizeToolName(tool))),allowlist=normalizeAllowlist(params.toolAllowlist),blockedPlugins=new Set;for(let entry of registry.tools){if(blockedPlugins.has(entry.pluginId))continue;let pluginIdKey=normalizeToolName(entry.pluginId);if(existingNormalized.has(pluginIdKey)){let message=`plugin id conflicts with core tool name (${entry.pluginId})`;log$8.error(message),registry.diagnostics.push({level:`error`,pluginId:entry.pluginId,source:entry.source,message}),blockedPlugins.add(entry.pluginId);continue}let resolved=null;try{resolved=entry.factory(params.context)}catch(err){log$8.error(`plugin tool failed (${entry.pluginId}): ${String(err)}`);continue}if(!resolved)continue;let listRaw=Array.isArray(resolved)?resolved:[resolved],list=entry.optional?listRaw.filter(tool=>isOptionalToolAllowed({toolName:tool.name,pluginId:entry.pluginId,allowlist})):listRaw;if(list.length===0)continue;let nameSet=new Set;for(let tool of list){if(nameSet.has(tool.name)||existing.has(tool.name)){let message=`plugin tool name conflict (${entry.pluginId}): ${tool.name}`;log$8.error(message),registry.diagnostics.push({level:`error`,pluginId:entry.pluginId,source:entry.source,message});continue}nameSet.add(tool.name),existing.add(tool.name),pluginToolMeta.set(tool,{pluginId:entry.pluginId,optional:entry.optional}),tools.push(tool)}}return tools}async function defaultReadFile(filePath){return fs$1.readFile(filePath,`utf8`)}async function applyUpdateHunk(filePath,chunks,options){let originalLines=(await(options?.readFile??defaultReadFile)(filePath).catch(err=>{throw Error(`Failed to read file to update ${filePath}: ${err}`)})).split(`
173
173
  `);originalLines.length>0&&originalLines[originalLines.length-1]===``&&originalLines.pop();let newLines=applyReplacements(originalLines,computeReplacements(originalLines,filePath,chunks));return(newLines.length===0||newLines[newLines.length-1]!==``)&&(newLines=[...newLines,``]),newLines.join(`
174
174
  `)}function computeReplacements(originalLines,filePath,chunks){let replacements=[],lineIndex=0;for(let chunk of chunks){if(chunk.changeContext){let ctxIndex=seekSequence(originalLines,[chunk.changeContext],lineIndex,!1);if(ctxIndex===null)throw Error(`Failed to find context '${chunk.changeContext}' in ${filePath}`);lineIndex=ctxIndex+1}if(chunk.oldLines.length===0){let insertionIndex=originalLines.length>0&&originalLines[originalLines.length-1]===``?originalLines.length-1:originalLines.length;replacements.push([insertionIndex,0,chunk.newLines]);continue}let pattern=chunk.oldLines,newSlice=chunk.newLines,found=seekSequence(originalLines,pattern,lineIndex,chunk.isEndOfFile);if(found===null&&pattern[pattern.length-1]===``&&(pattern=pattern.slice(0,-1),newSlice.length>0&&newSlice[newSlice.length-1]===``&&(newSlice=newSlice.slice(0,-1)),found=seekSequence(originalLines,pattern,lineIndex,chunk.isEndOfFile)),found===null)throw Error(`Failed to find expected lines in ${filePath}:\n${chunk.oldLines.join(`
175
175
  `)}`);replacements.push([found,pattern.length,newSlice]),lineIndex=found+pattern.length}return replacements.sort((a,b)=>a[0]-b[0]),replacements}function applyReplacements(lines,replacements){let result=[...lines];for(let[startIndex,oldLen,newLines]of[...replacements].toReversed()){for(let i=0;i<oldLen;i+=1)startIndex<result.length&&result.splice(startIndex,1);for(let i=0;i<newLines.length;i+=1)result.splice(startIndex+i,0,newLines[i])}return result}function seekSequence(lines,pattern,start,eof){if(pattern.length===0)return start;if(pattern.length>lines.length)return null;let maxStart=lines.length-pattern.length,searchStart=eof&&lines.length>=pattern.length?maxStart:start;if(searchStart>maxStart)return null;for(let i=searchStart;i<=maxStart;i+=1)if(linesMatch(lines,pattern,i,value=>value))return i;for(let i=searchStart;i<=maxStart;i+=1)if(linesMatch(lines,pattern,i,value=>value.trimEnd()))return i;for(let i=searchStart;i<=maxStart;i+=1)if(linesMatch(lines,pattern,i,value=>value.trim()))return i;for(let i=searchStart;i<=maxStart;i+=1)if(linesMatch(lines,pattern,i,value=>normalizePunctuation(value.trim())))return i;return null}function linesMatch(lines,pattern,start,normalize){for(let idx=0;idx<pattern.length;idx+=1)if(normalize(lines[start+idx])!==normalize(pattern[idx]))return!1;return!0}function normalizePunctuation(value){return Array.from(value).map(char=>{switch(char){case`‐`:case`‑`:case`‒`:case`–`:case`—`:case`―`:case`−`:return`-`;case`‘`:case`’`:case`‚`:case`‛`:return`'`;case`“`:case`”`:case`„`:case`‟`:return`"`;case`\xA0`:case` `:case` `:case` `:case` `:case` `:case` `:case` `:case` `:case` `:case` `:case` `:case` `:return` `;default:return char}}).join(``)}const BEGIN_PATCH_MARKER=`*** Begin Patch`,applyPatchSchema=Type.Object({input:Type.String({description:`Patch content using the *** Begin Patch/End Patch format.`})});function createApplyPatchTool(options={}){let cwd=options.cwd??process.cwd(),sandbox=options.sandbox,workspaceOnly=options.workspaceOnly!==!1;return{name:`apply_patch`,label:`apply_patch`,description:`Apply a patch to one or more files using the apply_patch format. The input should include *** Begin Patch and *** End Patch markers.`,parameters:applyPatchSchema,execute:async(_toolCallId,args,signal)=>{let params=args,input=typeof params.input==`string`?params.input:``;if(!input.trim())throw Error(`Provide a patch input.`);if(signal?.aborted){let err=Error(`Aborted`);throw err.name=`AbortError`,err}let result=await applyPatch(input,{cwd,sandbox,workspaceOnly,signal});return{content:[{type:`text`,text:result.text}],details:{summary:result.summary}}}}}async function applyPatch(input,options){let parsed=parsePatchText(input);if(parsed.hunks.length===0)throw Error(`No files were modified.`);let summary={added:[],modified:[],deleted:[]},seen={added:new Set,modified:new Set,deleted:new Set},fileOps=resolvePatchFileOps(options);for(let hunk of parsed.hunks){if(options.signal?.aborted){let err=Error(`Aborted`);throw err.name=`AbortError`,err}if(hunk.kind===`add`){let target=await resolvePatchPath(hunk.path,options);await ensureDir(target.resolved,fileOps),await fileOps.writeFile(target.resolved,hunk.contents),recordSummary(summary,seen,`added`,target.display);continue}if(hunk.kind===`delete`){let target=await resolvePatchPath(hunk.path,options,`unlink`);await fileOps.remove(target.resolved),recordSummary(summary,seen,`deleted`,target.display);continue}let target=await resolvePatchPath(hunk.path,options),applied=await applyUpdateHunk(target.resolved,hunk.chunks,{readFile:path=>fileOps.readFile(path)});if(hunk.movePath){let moveTarget=await resolvePatchPath(hunk.movePath,options);await ensureDir(moveTarget.resolved,fileOps),await fileOps.writeFile(moveTarget.resolved,applied),await fileOps.remove(target.resolved),recordSummary(summary,seen,`modified`,moveTarget.display)}else await fileOps.writeFile(target.resolved,applied),recordSummary(summary,seen,`modified`,target.display)}return{summary,text:formatSummary(summary)}}function recordSummary(summary,seen,bucket,value){seen[bucket].has(value)||(seen[bucket].add(value),summary[bucket].push(value))}function formatSummary(summary){let lines=[`Success. Updated the following files:`];for(let file of summary.added)lines.push(`A ${file}`);for(let file of summary.modified)lines.push(`M ${file}`);for(let file of summary.deleted)lines.push(`D ${file}`);return lines.join(`
@@ -381,7 +381,7 @@ Use jobId as the canonical identifier; id is accepted for compatibility. Use con
381
381
  `)),!message.trim()&&caption.trim()&&(message=caption);let parsed=parseReplyDirectives(message),mergedMediaUrls=[],seenMedia=new Set,pushMedia=value=>{let trimmed=value?.trim();trimmed&&(seenMedia.has(trimmed)||(seenMedia.add(trimmed),mergedMediaUrls.push(trimmed)))};pushMedia(mediaHint);for(let url of parsed.mediaUrls??[])pushMedia(url);pushMedia(parsed.mediaUrl);let normalizedMediaUrls=await normalizeSandboxMediaList({values:mergedMediaUrls,sandboxRoot:input.sandboxRoot});mergedMediaUrls.length=0,mergedMediaUrls.push(...normalizedMediaUrls),message=parsed.text,params.message=message,!params.replyTo&&parsed.replyToId&&(params.replyTo=parsed.replyToId),params.media||=mergedMediaUrls[0]||void 0,message=await maybeApplyCrossContextMarker({cfg,channel,action,target:to,toolContext:input.toolContext,accountId,args:params,message,preferComponents:!0});let mediaUrl=readStringParam(params,`media`,{trim:!1});if(channel===`whatsapp`&&(message=stripWhatsAppLeadingBlankLines(message),message.trim()||(message=``)),!message.trim()&&!mediaUrl&&mergedMediaUrls.length===0&&!hasCard&&!hasComponents)throw Error(`send requires text or media`);params.message=message;let gifPlayback=readBooleanParam(params,`gifPlayback`)??!1,bestEffort=readBooleanParam(params,`bestEffort`),silent=readBooleanParam(params,`silent`),replyToId=readStringParam(params,`replyTo`),resolvedThreadId=resolveAndApplyOutboundThreadId(params,{channel,to,toolContext:input.toolContext,allowSlackAutoThread:channel===`slack`&&!replyToId}),outboundRoute=agentId&&!dryRun?await resolveOutboundSessionRoute({cfg,channel,agentId,accountId,target:to,resolvedTarget,replyToId,threadId:resolvedThreadId}):null;outboundRoute&&agentId&&!dryRun&&await ensureOutboundSessionEntry({cfg,agentId,channel,accountId,route:outboundRoute}),outboundRoute&&!dryRun&&(params.__sessionKey=outboundRoute.sessionKey),agentId&&(params.__agentId=agentId);let mirrorMediaUrls=mergedMediaUrls.length>0?mergedMediaUrls:mediaUrl?[mediaUrl]:void 0;throwIfAborted(abortSignal);let send=await executeSendAction({ctx:{cfg,channel,params,agentId,accountId:accountId??void 0,gateway,toolContext:input.toolContext,deps:input.deps,dryRun,mirror:outboundRoute&&!dryRun?{sessionKey:outboundRoute.sessionKey,agentId,text:message,mediaUrls:mirrorMediaUrls}:void 0,abortSignal,silent:silent??void 0},to,message,mediaUrl:mediaUrl||void 0,mediaUrls:mergedMediaUrls.length?mergedMediaUrls:void 0,gifPlayback,bestEffort:bestEffort??void 0,replyToId:replyToId??void 0,threadId:resolvedThreadId??void 0});return{kind:`send`,channel,action,to,handledBy:send.handledBy,payload:send.payload,toolResult:send.toolResult,sendResult:send.sendResult,dryRun}}async function handlePollAction(ctx){let{cfg,params,channel,accountId,dryRun,gateway,input,abortSignal}=ctx;throwIfAborted(abortSignal);let action=`poll`,to=readStringParam(params,`to`,{required:!0}),question=readStringParam(params,`pollQuestion`,{required:!0}),options=readStringArrayParam(params,`pollOption`,{required:!0})??[];if(options.length<2)throw Error(`pollOption requires at least two values`);let silent=readBooleanParam(params,`silent`),allowMultiselect=readBooleanParam(params,`pollMulti`)??!1,pollAnonymous=readBooleanParam(params,`pollAnonymous`),pollPublic=readBooleanParam(params,`pollPublic`);if(pollAnonymous&&pollPublic)throw Error(`pollAnonymous and pollPublic are mutually exclusive`);let isAnonymous=pollAnonymous?!0:pollPublic?!1:void 0,durationHours=readNumberParam(params,`pollDurationHours`,{integer:!0}),durationSeconds=readNumberParam(params,`pollDurationSeconds`,{integer:!0}),maxSelections=allowMultiselect?Math.max(2,options.length):1;if(durationSeconds!==void 0&&channel!==`telegram`)throw Error(`pollDurationSeconds is only supported for Telegram polls`);if(isAnonymous!==void 0&&channel!==`telegram`)throw Error(`pollAnonymous/pollPublic are only supported for Telegram polls`);let resolvedThreadId=resolveAndApplyOutboundThreadId(params,{channel,to,toolContext:input.toolContext,allowSlackAutoThread:channel===`slack`}),base=typeof params.message==`string`?params.message:``;await maybeApplyCrossContextMarker({cfg,channel,action,target:to,toolContext:input.toolContext,accountId,args:params,message:base,preferComponents:!1});let poll=await executePollAction({ctx:{cfg,channel,params,accountId:accountId??void 0,gateway,toolContext:input.toolContext,dryRun,silent:silent??void 0},to,question,options,maxSelections,durationSeconds:durationSeconds??void 0,durationHours:durationHours??void 0,threadId:resolvedThreadId??void 0,isAnonymous});return{kind:`poll`,channel,action,to,handledBy:poll.handledBy,payload:poll.payload,toolResult:poll.toolResult,pollResult:poll.pollResult,dryRun}}async function handlePluginAction(ctx){let{cfg,params,channel,accountId,dryRun,gateway,input,abortSignal}=ctx;throwIfAborted(abortSignal);let action=input.action;if(dryRun)return{kind:`action`,channel,action,handledBy:`dry-run`,payload:{ok:!0,dryRun:!0,channel,action},dryRun:!0};let handled=await dispatchChannelMessageAction({channel,action,cfg,params,accountId:accountId??void 0,gateway,toolContext:input.toolContext,dryRun});if(!handled)throw Error(`Message action ${action} not supported for channel ${channel}.`);return{kind:`action`,channel,action,handledBy:`plugin`,payload:extractToolPayload(handled),toolResult:handled,dryRun}}async function runMessageAction(input){let cfg=input.cfg,params={...input.params},resolvedAgentId=input.agentId??(input.sessionKey?resolveSessionAgentId({sessionKey:input.sessionKey,config:cfg}):void 0);parseButtonsParam(params),parseCardParam(params),parseComponentsParam(params);let action=input.action;if(action===`broadcast`)return handleBroadcastAction(input,params);let explicitTarget=typeof params.target==`string`?params.target.trim():``,hasLegacyTarget=typeof params.to==`string`&&params.to.trim().length>0||typeof params.channelId==`string`&&params.channelId.trim().length>0;if(explicitTarget&&hasLegacyTarget&&(delete params.to,delete params.channelId),!explicitTarget&&!hasLegacyTarget&&actionRequiresTarget(action)&&!actionHasTarget(action,params)){let inferredTarget=input.toolContext?.currentChannelId?.trim();inferredTarget&&(params.target=inferredTarget)}if(!explicitTarget&&actionRequiresTarget(action)&&hasLegacyTarget){let legacyTo=typeof params.to==`string`?params.to.trim():``,legacyChannelId=typeof params.channelId==`string`?params.channelId.trim():``,legacyTarget=legacyTo||legacyChannelId;legacyTarget&&(params.target=legacyTarget,delete params.to,delete params.channelId)}if(!(typeof params.channel==`string`&&params.channel.trim())){let inferredChannel=normalizeMessageChannel(input.toolContext?.currentChannelProvider);inferredChannel&&isDeliverableMessageChannel(inferredChannel)&&(params.channel=inferredChannel)}if(applyTargetToParams({action,args:params}),actionRequiresTarget(action)&&!actionHasTarget(action,params))throw Error(`Action ${action} requires a target.`);let channel=await resolveChannel(cfg,params),accountId=readStringParam(params,`accountId`)??input.defaultAccountId;accountId&&(params.accountId=accountId);let dryRun=!!(input.dryRun??readBooleanParam(params,`dryRun`));await normalizeSandboxMediaParams({args:params,sandboxRoot:input.sandboxRoot}),await hydrateSendAttachmentParams({cfg,channel,accountId,args:params,action,dryRun}),await hydrateSetGroupIconParams({cfg,channel,accountId,args:params,action,dryRun});let resolvedTarget=await resolveActionTarget({cfg,channel,action,args:params,accountId});enforceCrossContextPolicy({channel,action,args:params,toolContext:input.toolContext,cfg});let gateway=resolveGateway(input);return action===`send`?handleSendAction({cfg,params,channel,accountId,dryRun,gateway,input,agentId:resolvedAgentId,resolvedTarget,abortSignal:input.abortSignal}):action===`poll`?handlePollAction({cfg,params,channel,accountId,dryRun,gateway,input,abortSignal:input.abortSignal}):handlePluginAction({cfg,params,channel,accountId,dryRun,gateway,input,abortSignal:input.abortSignal})}const AllMessageActions=CHANNEL_MESSAGE_ACTION_NAMES,EXPLICIT_TARGET_ACTIONS=new Set([`send`,`sendWithEffect`,`sendAttachment`,`reply`,`thread-reply`,`broadcast`]);function actionNeedsExplicitTarget(action){return EXPLICIT_TARGET_ACTIONS.has(action)}function buildRoutingSchema(){return{channel:Type.Optional(Type.String()),target:Type.Optional(channelTargetSchema({description:`Target channel/user id or name.`})),targets:Type.Optional(channelTargetsSchema()),accountId:Type.Optional(Type.String()),dryRun:Type.Optional(Type.Boolean())}}const discordComponentEmojiSchema=Type.Object({name:Type.String(),id:Type.Optional(Type.String()),animated:Type.Optional(Type.Boolean())}),discordComponentOptionSchema=Type.Object({label:Type.String(),value:Type.String(),description:Type.Optional(Type.String()),emoji:Type.Optional(discordComponentEmojiSchema),default:Type.Optional(Type.Boolean())}),discordComponentButtonSchema=Type.Object({label:Type.String(),style:Type.Optional(stringEnum([`primary`,`secondary`,`success`,`danger`,`link`])),url:Type.Optional(Type.String()),emoji:Type.Optional(discordComponentEmojiSchema),disabled:Type.Optional(Type.Boolean()),allowedUsers:Type.Optional(Type.Array(Type.String({description:`Discord user ids or names allowed to interact with this button.`})))}),discordComponentSelectSchema=Type.Object({type:Type.Optional(stringEnum([`string`,`user`,`role`,`mentionable`,`channel`])),placeholder:Type.Optional(Type.String()),minValues:Type.Optional(Type.Number()),maxValues:Type.Optional(Type.Number()),options:Type.Optional(Type.Array(discordComponentOptionSchema))}),discordComponentBlockSchema=Type.Object({type:Type.String(),text:Type.Optional(Type.String()),texts:Type.Optional(Type.Array(Type.String())),accessory:Type.Optional(Type.Object({type:Type.String(),url:Type.Optional(Type.String()),button:Type.Optional(discordComponentButtonSchema)})),spacing:Type.Optional(stringEnum([`small`,`large`])),divider:Type.Optional(Type.Boolean()),buttons:Type.Optional(Type.Array(discordComponentButtonSchema)),select:Type.Optional(discordComponentSelectSchema),items:Type.Optional(Type.Array(Type.Object({url:Type.String(),description:Type.Optional(Type.String()),spoiler:Type.Optional(Type.Boolean())}))),file:Type.Optional(Type.String()),spoiler:Type.Optional(Type.Boolean())}),discordComponentModalFieldSchema=Type.Object({type:Type.String(),name:Type.Optional(Type.String()),label:Type.String(),description:Type.Optional(Type.String()),placeholder:Type.Optional(Type.String()),required:Type.Optional(Type.Boolean()),options:Type.Optional(Type.Array(discordComponentOptionSchema)),minValues:Type.Optional(Type.Number()),maxValues:Type.Optional(Type.Number()),minLength:Type.Optional(Type.Number()),maxLength:Type.Optional(Type.Number()),style:Type.Optional(stringEnum([`short`,`paragraph`]))}),discordComponentModalSchema=Type.Object({title:Type.String(),triggerLabel:Type.Optional(Type.String()),triggerStyle:Type.Optional(stringEnum([`primary`,`secondary`,`success`,`danger`,`link`])),fields:Type.Array(discordComponentModalFieldSchema)}),discordComponentMessageSchema=Type.Object({text:Type.Optional(Type.String()),reusable:Type.Optional(Type.Boolean({description:`Allow components to be used multiple times until they expire.`})),container:Type.Optional(Type.Object({accentColor:Type.Optional(Type.String()),spoiler:Type.Optional(Type.Boolean())})),blocks:Type.Optional(Type.Array(discordComponentBlockSchema)),modal:Type.Optional(discordComponentModalSchema)},{description:`Discord components v2 payload. Set reusable=true to keep buttons, selects, and forms active until expiry.`});function buildSendSchema(options){let props={message:Type.Optional(Type.String()),effectId:Type.Optional(Type.String({description:`Message effect name/id for sendWithEffect (e.g., invisible ink).`})),effect:Type.Optional(Type.String({description:`Alias for effectId (e.g., invisible-ink, balloons).`})),media:Type.Optional(Type.String({description:`Media URL or local path. data: URLs are not supported here, use buffer.`})),filename:Type.Optional(Type.String()),buffer:Type.Optional(Type.String({description:`Base64 payload for attachments (optionally a data: URL).`})),contentType:Type.Optional(Type.String()),mimeType:Type.Optional(Type.String()),caption:Type.Optional(Type.String()),path:Type.Optional(Type.String()),filePath:Type.Optional(Type.String()),replyTo:Type.Optional(Type.String()),threadId:Type.Optional(Type.String()),asVoice:Type.Optional(Type.Boolean()),silent:Type.Optional(Type.Boolean()),quoteText:Type.Optional(Type.String({description:`Quote text for Telegram reply_parameters`})),bestEffort:Type.Optional(Type.Boolean()),gifPlayback:Type.Optional(Type.Boolean()),buttons:Type.Optional(Type.Array(Type.Array(Type.Object({text:Type.String(),callback_data:Type.String(),style:Type.Optional(stringEnum([`danger`,`success`,`primary`]))})),{description:`Telegram inline keyboard buttons (array of button rows)`})),card:Type.Optional(Type.Object({},{additionalProperties:!0,description:`Adaptive Card JSON object (when supported by the channel)`})),components:Type.Optional(discordComponentMessageSchema)};return options.includeButtons||delete props.buttons,options.includeCards||delete props.card,options.includeComponents||delete props.components,props}function buildReactionSchema(){return{messageId:Type.Optional(Type.String()),emoji:Type.Optional(Type.String()),remove:Type.Optional(Type.Boolean()),targetAuthor:Type.Optional(Type.String()),targetAuthorUuid:Type.Optional(Type.String()),groupId:Type.Optional(Type.String())}}function buildFetchSchema(){return{limit:Type.Optional(Type.Number()),before:Type.Optional(Type.String()),after:Type.Optional(Type.String()),around:Type.Optional(Type.String()),fromMe:Type.Optional(Type.Boolean()),includeArchived:Type.Optional(Type.Boolean())}}function buildPollSchema(){return{pollQuestion:Type.Optional(Type.String()),pollOption:Type.Optional(Type.Array(Type.String())),pollDurationHours:Type.Optional(Type.Number()),pollMulti:Type.Optional(Type.Boolean())}}function buildChannelTargetSchema(){return{channelId:Type.Optional(Type.String({description:`Channel id filter (search/thread list/event create).`})),channelIds:Type.Optional(Type.Array(Type.String({description:`Channel id filter (repeatable).`}))),guildId:Type.Optional(Type.String()),userId:Type.Optional(Type.String()),authorId:Type.Optional(Type.String()),authorIds:Type.Optional(Type.Array(Type.String())),roleId:Type.Optional(Type.String()),roleIds:Type.Optional(Type.Array(Type.String())),participant:Type.Optional(Type.String())}}function buildStickerSchema(){return{emojiName:Type.Optional(Type.String()),stickerId:Type.Optional(Type.Array(Type.String())),stickerName:Type.Optional(Type.String()),stickerDesc:Type.Optional(Type.String()),stickerTags:Type.Optional(Type.String())}}function buildThreadSchema(){return{threadName:Type.Optional(Type.String()),autoArchiveMin:Type.Optional(Type.Number())}}function buildEventSchema(){return{query:Type.Optional(Type.String()),eventName:Type.Optional(Type.String()),eventType:Type.Optional(Type.String()),startTime:Type.Optional(Type.String()),endTime:Type.Optional(Type.String()),desc:Type.Optional(Type.String()),location:Type.Optional(Type.String()),durationMin:Type.Optional(Type.Number()),until:Type.Optional(Type.String())}}function buildModerationSchema(){return{reason:Type.Optional(Type.String()),deleteDays:Type.Optional(Type.Number())}}function buildGatewaySchema(){return{gatewayUrl:Type.Optional(Type.String()),gatewayToken:Type.Optional(Type.String()),timeoutMs:Type.Optional(Type.Number())}}function buildPresenceSchema(){return{activityType:Type.Optional(Type.String({description:`Activity type: playing, streaming, listening, watching, competing, custom.`})),activityName:Type.Optional(Type.String({description:`Activity name shown in sidebar (e.g. 'with fire'). Ignored for custom type.`})),activityUrl:Type.Optional(Type.String({description:`Streaming URL (Twitch or YouTube). Only used with streaming type; may not render for bots.`})),activityState:Type.Optional(Type.String({description:`State text. For custom type this is the status text; for others it shows in the flyout.`})),status:Type.Optional(Type.String({description:`Bot status: online, dnd, idle, invisible.`}))}}function buildChannelManagementSchema(){return{name:Type.Optional(Type.String()),type:Type.Optional(Type.Number()),parentId:Type.Optional(Type.String()),topic:Type.Optional(Type.String()),position:Type.Optional(Type.Number()),nsfw:Type.Optional(Type.Boolean()),rateLimitPerUser:Type.Optional(Type.Number()),categoryId:Type.Optional(Type.String()),clearParent:Type.Optional(Type.Boolean({description:`Clear the parent/category when supported by the provider.`}))}}function buildMessageToolSchemaProps(options){return{...buildRoutingSchema(),...buildSendSchema(options),...buildReactionSchema(),...buildFetchSchema(),...buildPollSchema(),...buildChannelTargetSchema(),...buildStickerSchema(),...buildThreadSchema(),...buildEventSchema(),...buildModerationSchema(),...buildGatewaySchema(),...buildChannelManagementSchema(),...buildPresenceSchema()}}function buildMessageToolSchemaFromActions(actions,options){let props=buildMessageToolSchemaProps(options);return Type.Object({action:stringEnum(actions),...props})}const MessageToolSchema=buildMessageToolSchemaFromActions(AllMessageActions,{includeButtons:!0,includeCards:!0,includeComponents:!0});function resolveMessageToolSchemaActions(params){let currentChannel=normalizeMessageChannel(params.currentChannelProvider);if(currentChannel){let scopedActions=filterActionsForContext({actions:listChannelSupportedActions({cfg:params.cfg,channel:currentChannel}),channel:currentChannel,currentChannelId:params.currentChannelId}),withSend=new Set([`send`,...scopedActions]);return Array.from(withSend)}let actions=listChannelMessageActions(params.cfg);return actions.length>0?actions:[`send`]}function resolveIncludeComponents(params){let currentChannel=normalizeMessageChannel(params.currentChannelProvider);return currentChannel?currentChannel===`discord`:listChannelSupportedActions({cfg:params.cfg,channel:`discord`}).length>0}function buildMessageToolSchema(params){let currentChannel=normalizeMessageChannel(params.currentChannelProvider),actions=resolveMessageToolSchemaActions(params),includeButtons=currentChannel?supportsChannelMessageButtonsForChannel({cfg:params.cfg,channel:currentChannel}):supportsChannelMessageButtons(params.cfg),includeCards=currentChannel?supportsChannelMessageCardsForChannel({cfg:params.cfg,channel:currentChannel}):supportsChannelMessageCards(params.cfg),includeComponents=resolveIncludeComponents(params);return buildMessageToolSchemaFromActions(actions.length>0?actions:[`send`],{includeButtons,includeCards,includeComponents})}function resolveAgentAccountId(value){let trimmed=value?.trim();if(trimmed)return normalizeAccountId$2(trimmed)}function filterActionsForContext(params){let channel=normalizeMessageChannel(params.channel);if(!channel||channel!==`bluebubbles`)return params.actions;let currentChannelId=params.currentChannelId?.trim();if(!currentChannelId)return params.actions;let lowered=(normalizeTargetForProvider(channel,currentChannelId)??currentChannelId).trim().toLowerCase();return lowered.startsWith(`chat_guid:`)||lowered.startsWith(`chat_id:`)||lowered.startsWith(`chat_identifier:`)||lowered.startsWith(`group:`)?params.actions:params.actions.filter(action=>!BLUEBUBBLES_GROUP_ACTIONS.has(action))}function buildMessageToolDescription(options){let baseDescription=`Send, delete, and manage messages via channel plugins.`;if(options?.currentChannel){let channelActions=filterActionsForContext({actions:listChannelSupportedActions({cfg:options.config,channel:options.currentChannel}),channel:options.currentChannel,currentChannelId:options.currentChannelId});if(channelActions.length>0){let allActions=new Set([`send`,...channelActions]),actionList=Array.from(allActions).toSorted().join(`, `);return`${baseDescription} Current channel (${options.currentChannel}) supports: ${actionList}.`}}if(options?.config){let actions=listChannelMessageActions(options.config);if(actions.length>0)return`${baseDescription} Supports actions: ${actions.join(`, `)}.`}return`${baseDescription} Supports actions: send, delete, react, poll, pin, threads, and more.`}function messageToolSetup(options){return{agentAccountId:resolveAgentAccountId(options?.agentAccountId),schema:options?.config?buildMessageToolSchema({cfg:options.config,currentChannelProvider:options.currentChannelProvider,currentChannelId:options.currentChannelId}):MessageToolSchema,description:buildMessageToolDescription({config:options?.config,currentChannel:options?.currentChannelProvider,currentChannelId:options?.currentChannelId})}}async function runMessage(options,agentAccountId,args,signal){{if(signal?.aborted){let err=Error(`Message send aborted`);throw err.name=`AbortError`,err}let params={...args};for(let field of[`text`,`content`,`message`,`caption`])typeof params[field]==`string`&&(params[field]=stripReasoningTagsFromText(params[field]));let cfg=options?.config??loadConfig(),action=readStringParam(params,`action`,{required:!0});if(options?.requireExplicitTarget===!0&&actionNeedsExplicitTarget(action)&&!(typeof params.target==`string`&&params.target.trim().length>0||typeof params.to==`string`&&params.to.trim().length>0||typeof params.channelId==`string`&&params.channelId.trim().length>0||Array.isArray(params.targets)&&params.targets.some(value=>typeof value==`string`&&value.trim().length>0)))throw Error(`Explicit message target required for this run. Provide target/targets (and channel when needed).`);let accountId=readStringParam(params,`accountId`)??agentAccountId;accountId&&(params.accountId=accountId);let gatewayResolved=resolveGatewayOptions$1({gatewayUrl:readStringParam(params,`gatewayUrl`,{trim:!1}),gatewayToken:readStringParam(params,`gatewayToken`,{trim:!1}),timeoutMs:readNumberParam(params,`timeoutMs`)}),gateway={url:gatewayResolved.url,token:gatewayResolved.token,timeoutMs:gatewayResolved.timeoutMs,clientName:GATEWAY_CLIENT_IDS.GATEWAY_CLIENT,clientDisplayName:`agent`,mode:GATEWAY_CLIENT_MODES.BACKEND},toolContext=options?.currentChannelId||options?.currentChannelProvider||options?.currentThreadTs||options?.replyToMode||options?.hasRepliedRef?{currentChannelId:options?.currentChannelId,currentChannelProvider:options?.currentChannelProvider,currentThreadTs:options?.currentThreadTs,replyToMode:options?.replyToMode,hasRepliedRef:options?.hasRepliedRef,skipCrossContextDecoration:!0}:void 0,result=await runMessageAction({cfg,action,params,defaultAccountId:accountId??void 0,gateway,toolContext,sessionKey:options?.agentSessionKey,agentId:options?.agentSessionKey?resolveSessionAgentId({sessionKey:options.agentSessionKey,config:cfg}):void 0,sandboxRoot:options?.sandboxRoot,abortSignal:signal});return getToolResult(result)||jsonResult(result.payload)}}function createMessageTool(options){let{agentAccountId,schema,description}=messageToolSetup(options);return{label:`Message`,name:`message`,description,parameters:schema,execute:async(_toolCallId,args,signal)=>runMessage(options,agentAccountId,args,signal)}}const NodesToolSchema=Type.Object({action:stringEnum([`status`,`describe`,`pending`,`approve`,`reject`,`notify`,`camera_snap`,`camera_list`,`camera_clip`,`screen_record`,`location_get`,`run`,`invoke`]),gatewayUrl:Type.Optional(Type.String()),gatewayToken:Type.Optional(Type.String()),timeoutMs:Type.Optional(Type.Number()),node:Type.Optional(Type.String()),requestId:Type.Optional(Type.String()),title:Type.Optional(Type.String()),body:Type.Optional(Type.String()),sound:Type.Optional(Type.String()),priority:optionalStringEnum([`passive`,`active`,`timeSensitive`]),delivery:optionalStringEnum([`system`,`overlay`,`auto`]),facing:optionalStringEnum([`front`,`back`,`both`],{description:`camera_snap: front/back/both; camera_clip: front/back only.`}),maxWidth:Type.Optional(Type.Number()),quality:Type.Optional(Type.Number()),delayMs:Type.Optional(Type.Number()),deviceId:Type.Optional(Type.String()),duration:Type.Optional(Type.String()),durationMs:Type.Optional(Type.Number()),includeAudio:Type.Optional(Type.Boolean()),fps:Type.Optional(Type.Number()),screenIndex:Type.Optional(Type.Number()),outPath:Type.Optional(Type.String()),maxAgeMs:Type.Optional(Type.Number()),locationTimeoutMs:Type.Optional(Type.Number()),desiredAccuracy:optionalStringEnum([`coarse`,`balanced`,`precise`]),command:Type.Optional(Type.Array(Type.String())),cwd:Type.Optional(Type.String()),env:Type.Optional(Type.Array(Type.String())),commandTimeoutMs:Type.Optional(Type.Number()),invokeTimeoutMs:Type.Optional(Type.Number()),needsScreenRecording:Type.Optional(Type.Boolean()),invokeCommand:Type.Optional(Type.String()),invokeParamsJson:Type.Optional(Type.String())});async function runNodes(options,args){let sessionKey=options?.agentSessionKey?.trim()||void 0,agentId=resolveSessionAgentId({sessionKey:options?.agentSessionKey,config:options?.config}),imageSanitization=resolveImageSanitizationLimits(options?.config);{let params=args,action=readStringParam(params,`action`,{required:!0}),gatewayOpts=readGatewayCallOptions(params);try{switch(action){case`status`:return jsonResult(await callGatewayTool(`node.list`,gatewayOpts,{}));case`describe`:return jsonResult(await callGatewayTool(`node.describe`,gatewayOpts,{nodeId:await resolveNodeId$1(gatewayOpts,readStringParam(params,`node`,{required:!0}))}));case`pending`:return jsonResult(await callGatewayTool(`node.pair.list`,gatewayOpts,{}));case`approve`:return jsonResult(await callGatewayTool(`node.pair.approve`,gatewayOpts,{requestId:readStringParam(params,`requestId`,{required:!0})}));case`reject`:return jsonResult(await callGatewayTool(`node.pair.reject`,gatewayOpts,{requestId:readStringParam(params,`requestId`,{required:!0})}));case`notify`:{let node=readStringParam(params,`node`,{required:!0}),title=typeof params.title==`string`?params.title:``,body=typeof params.body==`string`?params.body:``;if(!title.trim()&&!body.trim())throw Error(`title or body required`);return await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId:await resolveNodeId$1(gatewayOpts,node),command:`system.notify`,params:{title:title.trim()||void 0,body:body.trim()||void 0,sound:typeof params.sound==`string`?params.sound:void 0,priority:typeof params.priority==`string`?params.priority:void 0,delivery:typeof params.delivery==`string`?params.delivery:void 0},idempotencyKey:crypto.randomUUID()}),jsonResult({ok:!0})}case`camera_snap`:{let nodeId=await resolveNodeId$1(gatewayOpts,readStringParam(params,`node`,{required:!0})),facingRaw=typeof params.facing==`string`?params.facing.toLowerCase():`both`,facings=facingRaw===`both`?[`front`,`back`]:facingRaw===`front`||facingRaw===`back`?[facingRaw]:(()=>{throw Error(`invalid facing (front|back|both)`)})(),maxWidth=typeof params.maxWidth==`number`&&Number.isFinite(params.maxWidth)?params.maxWidth:void 0,quality=typeof params.quality==`number`&&Number.isFinite(params.quality)?params.quality:void 0,delayMs=typeof params.delayMs==`number`&&Number.isFinite(params.delayMs)?params.delayMs:void 0,deviceId=typeof params.deviceId==`string`&&params.deviceId.trim()?params.deviceId.trim():void 0,content=[],details=[];for(let facing of facings){let payload=parseCameraSnapPayload((await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId,command:`camera.snap`,params:{facing,maxWidth,quality,format:`jpg`,delayMs,deviceId},idempotencyKey:crypto.randomUUID()}))?.payload),normalizedFormat=payload.format.toLowerCase();if(normalizedFormat!==`jpg`&&normalizedFormat!==`jpeg`&&normalizedFormat!==`png`)throw Error(`unsupported camera.snap format: ${payload.format}`);let isJpeg=normalizedFormat===`jpg`||normalizedFormat===`jpeg`,filePath=cameraTempPath({kind:`snap`,facing,ext:isJpeg?`jpg`:`png`});payload.url?await writeUrlToFile(filePath,payload.url):payload.base64&&await writeBase64ToFile(filePath,payload.base64),content.push({type:`text`,text:`MEDIA:${filePath}`}),payload.base64&&content.push({type:`image`,data:payload.base64,mimeType:imageMimeFromFormat(payload.format)??(isJpeg?`image/jpeg`:`image/png`)}),details.push({facing,path:filePath,width:payload.width,height:payload.height})}return await sanitizeToolResultImages({content,details},`nodes:camera_snap`,imageSanitization)}case`camera_list`:{let raw=await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId:await resolveNodeId$1(gatewayOpts,readStringParam(params,`node`,{required:!0})),command:`camera.list`,params:{},idempotencyKey:crypto.randomUUID()});return jsonResult(raw&&typeof raw.payload==`object`&&raw.payload!==null?raw.payload:{})}case`camera_clip`:{let nodeId=await resolveNodeId$1(gatewayOpts,readStringParam(params,`node`,{required:!0})),facing=typeof params.facing==`string`?params.facing.toLowerCase():`front`;if(facing!==`front`&&facing!==`back`)throw Error(`invalid facing (front|back)`);let payload=parseCameraClipPayload((await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId,command:`camera.clip`,params:{facing,durationMs:typeof params.durationMs==`number`&&Number.isFinite(params.durationMs)?params.durationMs:typeof params.duration==`string`?parseDurationMs(params.duration):3e3,includeAudio:typeof params.includeAudio==`boolean`?params.includeAudio:!0,format:`mp4`,deviceId:typeof params.deviceId==`string`&&params.deviceId.trim()?params.deviceId.trim():void 0},idempotencyKey:crypto.randomUUID()}))?.payload),filePath=await writeCameraClipPayloadToFile({payload,facing});return{content:[{type:`text`,text:`FILE:${filePath}`}],details:{facing,path:filePath,durationMs:payload.durationMs,hasAudio:payload.hasAudio}}}case`screen_record`:{let nodeId=await resolveNodeId$1(gatewayOpts,readStringParam(params,`node`,{required:!0})),durationMs=typeof params.durationMs==`number`&&Number.isFinite(params.durationMs)?params.durationMs:typeof params.duration==`string`?parseDurationMs(params.duration):1e4,fps=typeof params.fps==`number`&&Number.isFinite(params.fps)?params.fps:10,payload=parseScreenRecordPayload((await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId,command:`screen.record`,params:{durationMs,screenIndex:typeof params.screenIndex==`number`&&Number.isFinite(params.screenIndex)?params.screenIndex:0,fps,format:`mp4`,includeAudio:typeof params.includeAudio==`boolean`?params.includeAudio:!0},idempotencyKey:crypto.randomUUID()}))?.payload),written=await writeScreenRecordToFile(typeof params.outPath==`string`&&params.outPath.trim()?params.outPath.trim():screenRecordTempPath({ext:payload.format||`mp4`}),payload.base64);return{content:[{type:`text`,text:`FILE:${written.path}`}],details:{path:written.path,durationMs:payload.durationMs,fps:payload.fps,screenIndex:payload.screenIndex,hasAudio:payload.hasAudio}}}case`location_get`:return jsonResult((await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId:await resolveNodeId$1(gatewayOpts,readStringParam(params,`node`,{required:!0})),command:`location.get`,params:{maxAgeMs:typeof params.maxAgeMs==`number`&&Number.isFinite(params.maxAgeMs)?params.maxAgeMs:void 0,desiredAccuracy:params.desiredAccuracy===`coarse`||params.desiredAccuracy===`balanced`||params.desiredAccuracy===`precise`?params.desiredAccuracy:void 0,timeoutMs:typeof params.locationTimeoutMs==`number`&&Number.isFinite(params.locationTimeoutMs)?params.locationTimeoutMs:void 0},idempotencyKey:crypto.randomUUID()}))?.payload??{});case`run`:{let node=readStringParam(params,`node`,{required:!0}),nodes=await listNodes(gatewayOpts);if(nodes.length===0)throw Error(`system.run requires a paired companion app or node host (no nodes available).`);let nodeId=resolveNodeIdFromList(nodes,node),nodeInfo=nodes.find(entry=>entry.nodeId===nodeId);if(!(Array.isArray(nodeInfo?.commands)&&nodeInfo?.commands?.includes(`system.run`)))throw Error(`system.run requires a companion app or node host; the selected node does not support system.run.`);let commandRaw=params.command;if(!commandRaw)throw Error(`command required (argv array, e.g. ['echo', 'Hello'])`);if(!Array.isArray(commandRaw))throw Error(`command must be an array of strings (argv), e.g. ['echo', 'Hello']`);let command=commandRaw.map(c=>String(c));if(command.length===0)throw Error(`command must not be empty`);let cwd=typeof params.cwd==`string`&&params.cwd.trim()?params.cwd.trim():void 0,env=parseEnvPairs(params.env),commandTimeoutMs=parseTimeoutMs(params.commandTimeoutMs),invokeTimeoutMs=parseTimeoutMs(params.invokeTimeoutMs),runParams={command,cwd,env,timeoutMs:commandTimeoutMs,needsScreenRecording:typeof params.needsScreenRecording==`boolean`?params.needsScreenRecording:void 0,agentId,sessionKey};try{return jsonResult((await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId,command:`system.run`,params:runParams,timeoutMs:invokeTimeoutMs,idempotencyKey:crypto.randomUUID()}))?.payload??{})}catch(firstErr){if(!(firstErr instanceof Error?firstErr.message:String(firstErr)).includes(`SYSTEM_RUN_DENIED: approval required`))throw firstErr}let APPROVAL_TIMEOUT_MS=12e4,cmdText=command.join(` `),approvalId=crypto.randomUUID(),approvalResult=await callGatewayTool(`exec.approval.request`,{...gatewayOpts,timeoutMs:APPROVAL_TIMEOUT_MS+5e3},{id:approvalId,command:cmdText,cwd,host:`node`,agentId,sessionKey,timeoutMs:APPROVAL_TIMEOUT_MS}),decisionRaw=approvalResult&&typeof approvalResult==`object`?approvalResult.decision:void 0,approvalDecision=decisionRaw===`allow-once`||decisionRaw===`allow-always`?decisionRaw:null;if(!approvalDecision)throw decisionRaw===`deny`?Error(`exec denied: user denied`):decisionRaw==null?Error(`exec denied: approval timed out`):Error(`exec denied: invalid approval decision`);return jsonResult((await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId,command:`system.run`,params:{...runParams,runId:approvalId,approved:!0,approvalDecision},timeoutMs:invokeTimeoutMs,idempotencyKey:crypto.randomUUID()}))?.payload??{})}case`invoke`:{let nodeId=await resolveNodeId$1(gatewayOpts,readStringParam(params,`node`,{required:!0})),invokeCommand=readStringParam(params,`invokeCommand`,{required:!0}),invokeParamsJson=typeof params.invokeParamsJson==`string`?params.invokeParamsJson.trim():``,invokeParams={};if(invokeParamsJson)try{invokeParams=JSON.parse(invokeParamsJson)}catch(err){let message=err instanceof Error?err.message:String(err);throw Error(`invokeParamsJson must be valid JSON: ${message}`,{cause:err})}let invokeTimeoutMs=parseTimeoutMs(params.invokeTimeoutMs);return jsonResult(await callGatewayTool(`node.invoke`,gatewayOpts,{nodeId,command:invokeCommand,params:invokeParams,timeoutMs:invokeTimeoutMs,idempotencyKey:crypto.randomUUID()})??{})}default:throw Error(`Unknown action: ${action}`)}}catch(err){let nodeLabel=typeof params.node==`string`&&params.node.trim()?params.node.trim():`auto`,gatewayLabel=gatewayOpts.gatewayUrl&&gatewayOpts.gatewayUrl.trim()?gatewayOpts.gatewayUrl.trim():`default`,agentLabel=agentId??`unknown`,message=err instanceof Error?err.message:String(err);throw Error(`agent=${agentLabel} node=${nodeLabel} gateway=${gatewayLabel} action=${action}: ${message}`,{cause:err})}}}function createNodesTool(options){return{label:`Nodes`,name:`nodes`,description:`Discover and control paired nodes (status/describe/pairing/notify/camera/screen/location/run/invoke).`,parameters:NodesToolSchema,execute:async(_toolCallId,args)=>runNodes(options,args)}}const AVATAR_DATA_RE=/^data:/i,AVATAR_HTTP_RE=/^https?:\/\//i,AVATAR_SCHEME_RE=/^[a-z][a-z0-9+.-]*:/i,WINDOWS_ABS_RE=/^[a-zA-Z]:[\\/]/,AVATAR_MIME_BY_EXT={".png":`image/png`,".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".webp":`image/webp`,".gif":`image/gif`,".svg":`image/svg+xml`,".bmp":`image/bmp`,".tif":`image/tiff`,".tiff":`image/tiff`};function resolveAvatarMime(filePath){return AVATAR_MIME_BY_EXT[path.extname(filePath).toLowerCase()]??`application/octet-stream`}function isWorkspaceRelativePath(value){return!(!value||value.startsWith(`~`)||AVATAR_SCHEME_RE.test(value)&&!WINDOWS_ABS_RE.test(value))}function resolveIdentityAvatarUrl(cfg,agentId,avatar){if(!avatar)return;let trimmed=avatar.trim();if(!trimmed)return;if(AVATAR_DATA_RE.test(trimmed)||AVATAR_HTTP_RE.test(trimmed))return trimmed;if(!isWorkspaceRelativePath(trimmed))return;let workspaceDir=resolveAgentWorkspaceDir(cfg,agentId),workspaceRoot=path.resolve(workspaceDir),resolved=path.resolve(workspaceRoot,trimmed),relative=path.relative(workspaceRoot,resolved);if(!(relative.startsWith(`..`)||path.isAbsolute(relative)))try{let stat=fs.statSync(resolved);if(!stat.isFile()||stat.size>2097152)return;let buffer=fs.readFileSync(resolved);return`data:${resolveAvatarMime(resolved)};base64,${buffer.toString(`base64`)}`}catch{return}}function formatSessionIdPrefix(sessionId,updatedAt){let prefix=sessionId.slice(0,8);return updatedAt&&updatedAt>0?`${prefix} (${new Date(updatedAt).toISOString().slice(0,10)})`:prefix}function truncateTitle(text,maxLen){if(text.length<=maxLen)return text;let cut=text.slice(0,maxLen-1),lastSpace=cut.lastIndexOf(` `);return lastSpace>maxLen*.6?cut.slice(0,lastSpace)+`…`:cut+`…`}function deriveSessionTitle(entry,firstUserMessage){if(entry){if(entry.displayName?.trim())return entry.displayName.trim();if(entry.subject?.trim())return entry.subject.trim();if(firstUserMessage?.trim())return truncateTitle(firstUserMessage.replace(/\s+/g,` `).trim(),60);if(entry.sessionId)return formatSessionIdPrefix(entry.sessionId,entry.updatedAt)}}function loadSessionEntry(sessionKey){let cfg=loadConfig(),sessionCfg=cfg.session,canonicalKey=resolveSessionStoreKey({cfg,sessionKey}),agentId=resolveSessionStoreAgentId(cfg,canonicalKey),storePath=resolveStorePath(sessionCfg?.store,{agentId}),store=loadSessionStore(storePath),match=findStoreMatch(store,canonicalKey,sessionKey.trim()),legacyKey=match?.key===canonicalKey?void 0:match?.key;return{cfg,storePath,store,entry:match?.entry,canonicalKey,legacyKey}}function findStoreMatch(store,...candidates){for(let candidate of candidates)if(candidate&&store[candidate])return{entry:store[candidate],key:candidate};let loweredSet=new Set(candidates.filter(Boolean).map(c=>c.toLowerCase()));for(let key of Object.keys(store))if(loweredSet.has(key.toLowerCase()))return{entry:store[key],key}}function findStoreKeysIgnoreCase(store,targetKey){let lowered=targetKey.toLowerCase(),matches=[];for(let key of Object.keys(store))key.toLowerCase()===lowered&&matches.push(key);return matches}function pruneLegacyStoreKeys(params){let keysToDelete=new Set;for(let candidate of params.candidates){let trimmed=String(candidate??``).trim();if(trimmed){trimmed!==params.canonicalKey&&keysToDelete.add(trimmed);for(let match of findStoreKeysIgnoreCase(params.store,trimmed))match!==params.canonicalKey&&keysToDelete.add(match)}}for(let key of keysToDelete)delete params.store[key]}function classifySessionKey(key,entry){return key===`global`?`global`:key===`unknown`?`unknown`:entry?.chatType===`group`||entry?.chatType===`channel`||key.includes(`:group:`)||key.includes(`:channel:`)?`group`:`direct`}function parseGroupKey(key){let parts=(parseAgentSessionKey(key)?.rest??key).split(`:`).filter(Boolean);if(parts.length>=3){let[channel,kind,...rest]=parts;if(kind===`group`||kind===`channel`)return{channel,kind,id:rest.join(`:`)}}return null}function isStorePathTemplate(store){return typeof store==`string`&&store.includes(`{agentId}`)}function listExistingAgentIdsFromDisk(){let root=resolveStateDir(),agentsDir=path.join(root,`agents`);try{return fs.readdirSync(agentsDir,{withFileTypes:!0}).filter(entry=>entry.isDirectory()).map(entry=>normalizeAgentId(entry.name)).filter(Boolean)}catch{return[]}}function listConfiguredAgentIds(cfg){let agents=cfg.agents?.list??[];if(agents.length>0){let ids=new Set;for(let entry of agents)entry?.id&&ids.add(normalizeAgentId(entry.id));let defaultId=normalizeAgentId(resolveDefaultAgentId(cfg));ids.add(defaultId);let sorted=Array.from(ids).filter(Boolean);return sorted.sort((a,b)=>a.localeCompare(b)),sorted.includes(defaultId)?[defaultId,...sorted.filter(id=>id!==defaultId)]:sorted}let ids=new Set,defaultId=normalizeAgentId(resolveDefaultAgentId(cfg));ids.add(defaultId);for(let id of listExistingAgentIdsFromDisk())ids.add(id);let sorted=Array.from(ids).filter(Boolean);return sorted.sort((a,b)=>a.localeCompare(b)),sorted.includes(defaultId)?[defaultId,...sorted.filter(id=>id!==defaultId)]:sorted}function listAgentsForGateway(cfg){let defaultId=normalizeAgentId(resolveDefaultAgentId(cfg)),mainKey=normalizeMainKey(cfg.session?.mainKey),scope=cfg.session?.scope??`per-sender`,configuredById=new Map;for(let entry of cfg.agents?.list??[]){if(!entry?.id)continue;let identity=entry.identity?{name:entry.identity.name?.trim()||void 0,theme:entry.identity.theme?.trim()||void 0,emoji:entry.identity.emoji?.trim()||void 0,avatar:entry.identity.avatar?.trim()||void 0,avatarUrl:resolveIdentityAvatarUrl(cfg,normalizeAgentId(entry.id),entry.identity.avatar?.trim())}:void 0;configuredById.set(normalizeAgentId(entry.id),{name:typeof entry.name==`string`&&entry.name.trim()?entry.name.trim():void 0,identity})}let explicitIds=new Set((cfg.agents?.list??[]).map(entry=>entry?.id?normalizeAgentId(entry.id):``).filter(Boolean)),allowedIds=explicitIds.size>0?new Set([...explicitIds,defaultId]):null,agentIds=listConfiguredAgentIds(cfg).filter(id=>allowedIds?allowedIds.has(id):!0);return mainKey&&!agentIds.includes(mainKey)&&(!allowedIds||allowedIds.has(mainKey))&&(agentIds=[...agentIds,mainKey]),{defaultId,mainKey,scope,agents:agentIds.map(id=>{let meta=configuredById.get(id);return{id,name:meta?.name,identity:meta?.identity}})}}function canonicalizeSessionKeyForAgent(agentId,key){let lowered=key.toLowerCase();return lowered===`global`||lowered===`unknown`||lowered.startsWith(`agent:`)?lowered:`agent:${normalizeAgentId(agentId)}:${lowered}`}function resolveDefaultStoreAgentId(cfg){return normalizeAgentId(resolveDefaultAgentId(cfg))}function resolveSessionStoreKey(params){let raw=params.sessionKey.trim();if(!raw)return raw;let rawLower=raw.toLowerCase();if(rawLower===`global`||rawLower===`unknown`)return rawLower;let parsed=parseAgentSessionKey(raw);if(parsed){let agentId=normalizeAgentId(parsed.agentId),lowered=raw.toLowerCase(),canonical=canonicalizeMainSessionAlias({cfg:params.cfg,agentId,sessionKey:lowered});return canonical===lowered?lowered:canonical}let lowered=raw.toLowerCase(),rawMainKey=normalizeMainKey(params.cfg.session?.mainKey);return lowered===`main`||lowered===rawMainKey?resolveMainSessionKey(params.cfg):canonicalizeSessionKeyForAgent(resolveDefaultStoreAgentId(params.cfg),lowered)}function resolveSessionStoreAgentId(cfg,canonicalKey){if(canonicalKey===`global`||canonicalKey===`unknown`)return resolveDefaultStoreAgentId(cfg);let parsed=parseAgentSessionKey(canonicalKey);return parsed?.agentId?normalizeAgentId(parsed.agentId):resolveDefaultStoreAgentId(cfg)}function canonicalizeSpawnedByForAgent(cfg,agentId,spawnedBy){let raw=spawnedBy?.trim();if(!raw)return;let lower=raw.toLowerCase();if(lower===`global`||lower===`unknown`)return lower;let result;result=raw.toLowerCase().startsWith(`agent:`)?raw.toLowerCase():`agent:${normalizeAgentId(agentId)}:${lower}`;let parsed=parseAgentSessionKey(result);return canonicalizeMainSessionAlias({cfg,agentId:parsed?.agentId?normalizeAgentId(parsed.agentId):agentId,sessionKey:result})}function resolveGatewaySessionStoreTarget(params){let key=params.key.trim(),canonicalKey=resolveSessionStoreKey({cfg:params.cfg,sessionKey:key}),agentId=resolveSessionStoreAgentId(params.cfg,canonicalKey),storeConfig=params.cfg.session?.store,storePath=resolveStorePath(storeConfig,{agentId});if(canonicalKey===`global`||canonicalKey===`unknown`)return{agentId,storePath,canonicalKey,storeKeys:key&&key!==canonicalKey?[canonicalKey,key]:[key]};let storeKeys=new Set;if(storeKeys.add(canonicalKey),key&&key!==canonicalKey&&storeKeys.add(key),params.scanLegacyKeys!==!1){let scanTargets=new Set(storeKeys);canonicalKey===resolveAgentMainSessionKey({cfg:params.cfg,agentId})&&scanTargets.add(`agent:${agentId}:main`);let store=params.store??loadSessionStore(storePath);for(let seed of scanTargets)for(let legacyKey of findStoreKeysIgnoreCase(store,seed))storeKeys.add(legacyKey)}return{agentId,storePath,canonicalKey,storeKeys:Array.from(storeKeys)}}function mergeSessionEntryIntoCombined(params){let{cfg,combined,entry,agentId,canonicalKey}=params,existing=combined[canonicalKey];existing&&(existing.updatedAt??0)>(entry.updatedAt??0)?combined[canonicalKey]={...entry,...existing,spawnedBy:canonicalizeSpawnedByForAgent(cfg,agentId,existing.spawnedBy??entry.spawnedBy)}:combined[canonicalKey]={...existing,...entry,spawnedBy:canonicalizeSpawnedByForAgent(cfg,agentId,entry.spawnedBy??existing?.spawnedBy)}}function loadCombinedSessionStoreForGateway(cfg){let storeConfig=cfg.session?.store;if(storeConfig&&!isStorePathTemplate(storeConfig)){let storePath=resolveStorePath(storeConfig),defaultAgentId=normalizeAgentId(resolveDefaultAgentId(cfg)),store=loadSessionStore(storePath),combined={};for(let[key,entry]of Object.entries(store))mergeSessionEntryIntoCombined({cfg,combined,entry,agentId:defaultAgentId,canonicalKey:canonicalizeSessionKeyForAgent(defaultAgentId,key)});return{storePath,store:combined}}let agentIds=listConfiguredAgentIds(cfg),combined={};for(let agentId of agentIds){let store=loadSessionStore(resolveStorePath(storeConfig,{agentId}));for(let[key,entry]of Object.entries(store))mergeSessionEntryIntoCombined({cfg,combined,entry,agentId,canonicalKey:canonicalizeSessionKeyForAgent(agentId,key)})}return{storePath:typeof storeConfig==`string`&&storeConfig.trim()?storeConfig.trim():`(multiple)`,store:combined}}function getSessionDefaults(cfg){let resolved=resolveConfiguredModelRef({cfg,defaultProvider:DEFAULT_PROVIDER,defaultModel:DEFAULT_MODEL}),contextTokens=cfg.agents?.defaults?.contextTokens??lookupContextTokens(resolved.model)??DEFAULT_CONTEXT_TOKENS;return{modelProvider:resolved.provider??null,model:resolved.model??null,contextTokens:contextTokens??null}}function resolveSessionModelRef(cfg,entry,agentId){let resolved=agentId?resolveDefaultModelForAgent({cfg,agentId}):resolveConfiguredModelRef({cfg,defaultProvider:DEFAULT_PROVIDER,defaultModel:DEFAULT_MODEL}),provider=resolved.provider,model=resolved.model,runtimeModel=entry?.model?.trim(),runtimeProvider=entry?.modelProvider?.trim();if(runtimeModel){let parsedRuntime=parseModelRef(runtimeModel,runtimeProvider||provider||DEFAULT_PROVIDER);return parsedRuntime?(provider=parsedRuntime.provider,model=parsedRuntime.model):(provider=runtimeProvider||provider,model=runtimeModel),{provider,model}}let storedModelOverride=entry?.modelOverride?.trim();if(storedModelOverride){let overrideProvider=entry?.providerOverride?.trim()||provider||DEFAULT_PROVIDER,parsedOverride=parseModelRef(storedModelOverride,overrideProvider);parsedOverride?(provider=parsedOverride.provider,model=parsedOverride.model):(provider=overrideProvider,model=storedModelOverride)}return{provider,model}}function listSessionsFromStore(params){let{cfg,storePath,store,opts}=params,now=Date.now(),includeGlobal=opts.includeGlobal===!0,includeUnknown=opts.includeUnknown===!0,includeDerivedTitles=opts.includeDerivedTitles===!0,includeLastMessage=opts.includeLastMessage===!0,spawnedBy=typeof opts.spawnedBy==`string`?opts.spawnedBy:``,label=typeof opts.label==`string`?opts.label.trim():``,agentId=typeof opts.agentId==`string`?normalizeAgentId(opts.agentId):``,search=typeof opts.search==`string`?opts.search.trim().toLowerCase():``,activeMinutes=typeof opts.activeMinutes==`number`&&Number.isFinite(opts.activeMinutes)?Math.max(1,Math.floor(opts.activeMinutes)):void 0,sessions=Object.entries(store).filter(([key])=>{if(isCronRunSessionKey(key)||!includeGlobal&&key===`global`||!includeUnknown&&key===`unknown`)return!1;if(agentId){if(key===`global`||key===`unknown`)return!1;let parsed=parseAgentSessionKey(key);return parsed?normalizeAgentId(parsed.agentId)===agentId:!1}return!0}).filter(([key,entry])=>spawnedBy?key===`unknown`||key===`global`?!1:entry?.spawnedBy===spawnedBy:!0).filter(([,entry])=>label?entry?.label===label:!0).map(([key,entry])=>{let updatedAt=entry?.updatedAt??null,total=resolveFreshSessionTotalTokens(entry),totalTokensFresh=typeof entry?.totalTokens==`number`?entry?.totalTokensFresh!==!1:!1,parsed=parseGroupKey(key),channel=entry?.channel??parsed?.channel,subject=entry?.subject,groupChannel=entry?.groupChannel,space=entry?.space,id=parsed?.id,origin=entry?.origin,originLabel=origin?.label,displayName=entry?.displayName??(channel?buildGroupDisplayName({provider:channel,subject,groupChannel,space,id,key}):void 0)??entry?.label??originLabel,deliveryFields=normalizeSessionDeliveryFields(entry),resolvedModel=resolveSessionModelRef(cfg,entry,normalizeAgentId(parseAgentSessionKey(key)?.agentId??resolveDefaultAgentId(cfg))),modelProvider=resolvedModel.provider??DEFAULT_PROVIDER,model=resolvedModel.model??DEFAULT_MODEL;return{key,entry,kind:classifySessionKey(key,entry),label:entry?.label,displayName,channel,subject,groupChannel,space,chatType:entry?.chatType,origin,updatedAt,sessionId:entry?.sessionId,systemSent:entry?.systemSent,abortedLastRun:entry?.abortedLastRun,thinkingLevel:entry?.thinkingLevel,verboseLevel:entry?.verboseLevel,reasoningLevel:entry?.reasoningLevel,elevatedLevel:entry?.elevatedLevel,sendPolicy:entry?.sendPolicy,inputTokens:entry?.inputTokens,outputTokens:entry?.outputTokens,totalTokens:total,totalTokensFresh,responseUsage:entry?.responseUsage,modelProvider,model,contextTokens:entry?.contextTokens,deliveryContext:deliveryFields.deliveryContext,lastChannel:deliveryFields.lastChannel??entry?.lastChannel,lastTo:deliveryFields.lastTo??entry?.lastTo,lastAccountId:deliveryFields.lastAccountId??entry?.lastAccountId}}).toSorted((a,b)=>(b.updatedAt??0)-(a.updatedAt??0));if(search&&(sessions=sessions.filter(s=>[s.displayName,s.label,s.subject,s.sessionId,s.key].some(f=>typeof f==`string`&&f.toLowerCase().includes(search)))),activeMinutes!==void 0){let cutoff=now-activeMinutes*6e4;sessions=sessions.filter(s=>(s.updatedAt??0)>=cutoff)}if(typeof opts.limit==`number`&&Number.isFinite(opts.limit)){let limit=Math.max(1,Math.floor(opts.limit));sessions=sessions.slice(0,limit)}let finalSessions=sessions.map(s=>{let{entry,...rest}=s,derivedTitle,lastMessagePreview;if(entry?.sessionId&&(includeDerivedTitles||includeLastMessage)){let parsed=parseAgentSessionKey(s.key),agentId=parsed&&parsed.agentId?normalizeAgentId(parsed.agentId):resolveDefaultAgentId(cfg),fields=readSessionTitleFieldsFromTranscript(entry.sessionId,storePath,entry.sessionFile,agentId);includeDerivedTitles&&(derivedTitle=deriveSessionTitle(entry,fields.firstUserMessage)),includeLastMessage&&fields.lastMessagePreview&&(lastMessagePreview=fields.lastMessagePreview)}return{...rest,derivedTitle,lastMessagePreview}});return{ts:now,path:storePath,count:finalSessions.length,defaults:getSessionDefaults(cfg),sessions:finalSessions}}const SessionStatusToolSchema=Type.Object({sessionKey:Type.Optional(Type.String()),model:Type.Optional(Type.String())});function resolveSessionEntry(params){let keyRaw=params.keyRaw.trim();if(!keyRaw)return null;let internal=resolveInternalSessionKey({key:keyRaw,alias:params.alias,mainKey:params.mainKey}),candidates=new Set([keyRaw,internal]);keyRaw.startsWith(`agent:`)||(candidates.add(`agent:${DEFAULT_AGENT_ID}:${keyRaw}`),candidates.add(`agent:${DEFAULT_AGENT_ID}:${internal}`)),keyRaw===`main`&&candidates.add(buildAgentMainSessionKey({agentId:DEFAULT_AGENT_ID,mainKey:params.mainKey}));for(let key of candidates){let entry=params.store[key];if(entry)return{key,entry}}return null}function resolveSessionKeyFromSessionId(params){let trimmed=params.sessionId.trim();if(!trimmed)return null;let{store}=loadCombinedSessionStoreForGateway(params.cfg);return Object.entries(store).find(([key,entry])=>entry?.sessionId===trimmed?params.agentId?resolveAgentIdFromSessionKey(key)===params.agentId:!0:!1)?.[0]??null}async function resolveModelOverride(params){let raw=params.raw.trim();if(!raw||raw.toLowerCase()===`default`)return{kind:`reset`};let configDefault=resolveDefaultModelForAgent({cfg:params.cfg,agentId:params.agentId}),currentProvider=params.sessionEntry?.providerOverride?.trim()||configDefault.provider,currentModel=params.sessionEntry?.modelOverride?.trim()||configDefault.model,aliasIndex=buildModelAliasIndex({cfg:params.cfg,defaultProvider:currentProvider}),catalog=await loadModelCatalog({config:params.cfg}),allowed=buildAllowedModelSet({cfg:params.cfg,catalog,defaultProvider:currentProvider,defaultModel:currentModel}),resolved=resolveModelRefFromString({raw,defaultProvider:currentProvider,aliasIndex});if(!resolved)throw Error(`Unrecognized model "${raw}".`);let key=modelKey(resolved.ref.provider,resolved.ref.model);if(allowed.allowedKeys.size>0&&!allowed.allowedKeys.has(key))throw Error(`Model "${key}" is not allowed.`);let isDefault=resolved.ref.provider===configDefault.provider&&resolved.ref.model===configDefault.model;return{kind:`set`,provider:resolved.ref.provider,model:resolved.ref.model,isDefault}}async function runSessionStatus(opts,args){{let params=args,cfg=opts?.config??loadConfig(),{mainKey,alias}=resolveMainSessionAlias(cfg),a2aPolicy=createAgentToAgentPolicy(cfg),requestedKeyRaw=readStringParam(params,`sessionKey`)??opts?.agentSessionKey;if(!requestedKeyRaw?.trim())throw Error(`sessionKey required`);let requesterAgentId=resolveAgentIdFromSessionKey(opts?.agentSessionKey??requestedKeyRaw),ensureAgentAccess=targetAgentId=>{if(targetAgentId!==requesterAgentId){if(!a2aPolicy.enabled)throw Error(`Agent-to-agent status is disabled. Set tools.agentToAgent.enabled=true to allow cross-agent access.`);if(!a2aPolicy.isAllowed(requesterAgentId,targetAgentId))throw Error(`Agent-to-agent session status denied by tools.agentToAgent.allow.`)}};requestedKeyRaw.startsWith(`agent:`)&&ensureAgentAccess(resolveAgentIdFromSessionKey(requestedKeyRaw));let agentId=requestedKeyRaw.startsWith(`agent:`)?resolveAgentIdFromSessionKey(requestedKeyRaw):requesterAgentId,storePath=resolveStorePath(cfg.session?.store,{agentId}),store=loadSessionStore(storePath),resolved=resolveSessionEntry({store,keyRaw:requestedKeyRaw,alias,mainKey});if(!resolved&&shouldResolveSessionIdInput(requestedKeyRaw)){let resolvedKey=resolveSessionKeyFromSessionId({cfg,sessionId:requestedKeyRaw,agentId:a2aPolicy.enabled?void 0:requesterAgentId});resolvedKey&&(ensureAgentAccess(resolveAgentIdFromSessionKey(resolvedKey)),requestedKeyRaw=resolvedKey,agentId=resolveAgentIdFromSessionKey(resolvedKey),storePath=resolveStorePath(cfg.session?.store,{agentId}),store=loadSessionStore(storePath),resolved=resolveSessionEntry({store,keyRaw:requestedKeyRaw,alias,mainKey}))}if(!resolved){let kind=shouldResolveSessionIdInput(requestedKeyRaw)?`sessionId`:`sessionKey`;throw Error(`Unknown ${kind}: ${requestedKeyRaw}`)}let configured=resolveDefaultModelForAgent({cfg,agentId}),modelRaw=readStringParam(params,`model`),changedModel=!1;if(typeof modelRaw==`string`){let selection=await resolveModelOverride({cfg,raw:modelRaw,sessionEntry:resolved.entry,agentId}),nextEntry={...resolved.entry};applyModelOverrideToSessionEntry({entry:nextEntry,selection:selection.kind===`reset`?{provider:configured.provider,model:configured.model,isDefault:!0}:{provider:selection.provider,model:selection.model,isDefault:selection.isDefault}}).updated&&(store[resolved.key]=nextEntry,await updateSessionStore(storePath,nextStore=>{nextStore[resolved.key]=nextEntry}),resolved.entry=nextEntry,changedModel=!0)}let agentDir=resolveAgentDir(cfg,agentId),providerForCard=resolved.entry.providerOverride?.trim()||configured.provider,usageProvider=resolveUsageProviderId(providerForCard),usageLine;if(usageProvider)try{let snapshot=(await loadProviderUsageSummary({timeoutMs:3500,providers:[usageProvider],agentDir})).providers.find(entry=>entry.provider===usageProvider);if(snapshot){let formatted=formatUsageWindowSummary(snapshot,{now:Date.now(),maxWindows:2,includeResets:!0});formatted&&!formatted.startsWith(`error:`)&&(usageLine=`📊 Usage: ${formatted}`)}}catch{}let groupActivation=resolved.entry.chatType===`group`||resolved.entry.chatType===`channel`||resolved.key.includes(`:group:`)||resolved.key.includes(`:channel:`)?normalizeGroupActivation(resolved.entry.groupActivation)??`mention`:void 0,queueSettings=resolveQueueSettings({cfg,channel:resolved.entry.channel??resolved.entry.lastChannel??`unknown`,sessionEntry:resolved.entry}),queueKey=resolved.key??resolved.entry.sessionId,queueDepth=queueKey?getFollowupQueueDepth(queueKey):0,queueOverrides=!!(resolved.entry.queueDebounceMs??resolved.entry.queueCap??resolved.entry.queueDrop),userTimezone=resolveUserTimezone(cfg.agents?.defaults?.userTimezone),userTimeFormat=resolveUserTimeFormat(cfg.agents?.defaults?.timeFormat),userTime=formatUserTime(new Date,userTimezone,userTimeFormat),timeLine=userTime?`🕒 Time: ${userTime} (${userTimezone})`:`🕒 Time zone: ${userTimezone}`,agentDefaults=cfg.agents?.defaults??{},defaultLabel=`${configured.provider}/${configured.model}`,agentModel=typeof agentDefaults.model==`object`&&agentDefaults.model?{...agentDefaults.model,primary:defaultLabel}:{primary:defaultLabel},statusText=await buildStatusMessage({config:cfg,agent:{...agentDefaults,model:agentModel},agentId,sessionEntry:resolved.entry,sessionKey:resolved.key,sessionStorePath:storePath,groupActivation,modelAuth:await resolveModelAuthLabel({provider:providerForCard,cfg,sessionEntry:resolved.entry,agentDir}),usageLine,timeLine,queue:{mode:queueSettings.mode,depth:queueDepth,debounceMs:queueSettings.debounceMs,cap:queueSettings.cap,dropPolicy:queueSettings.dropPolicy,showDetails:queueOverrides},includeTranscriptUsage:!1});return{content:[{type:`text`,text:statusText}],details:{ok:!0,sessionKey:resolved.key,changedModel,statusText}}}}function createSessionStatusTool(opts){return{label:`Session Status`,name:`session_status`,description:`Show a /status-equivalent session status card (usage + time + cost when available). Use for model-use questions (📊 session_status). Optional: set per-session model override (model=default resets overrides).`,parameters:SessionStatusToolSchema,execute:async(_toolCallId,args)=>runSessionStatus(opts,args)}}const SessionsHistoryToolSchema=Type.Object({sessionKey:Type.String(),limit:Type.Optional(Type.Number({minimum:1})),includeTools:Type.Optional(Type.Boolean())}),SESSIONS_HISTORY_MAX_BYTES=80*1024,SESSIONS_HISTORY_TEXT_MAX_CHARS=4e3;function truncateHistoryText(text){return text.length<=SESSIONS_HISTORY_TEXT_MAX_CHARS?{text,truncated:!1}:{text:`${truncateUtf16Safe(text,SESSIONS_HISTORY_TEXT_MAX_CHARS)}\n…(truncated)…`,truncated:!0}}function sanitizeHistoryContentBlock(block){if(!block||typeof block!=`object`)return{block,truncated:!1};let entry={...block},truncated=!1,type=typeof entry.type==`string`?entry.type:``;if(typeof entry.text==`string`){let res=truncateHistoryText(entry.text);entry.text=res.text,truncated||=res.truncated}if(type===`thinking`){if(typeof entry.thinking==`string`){let res=truncateHistoryText(entry.thinking);entry.thinking=res.text,truncated||=res.truncated}`thinkingSignature`in entry&&(delete entry.thinkingSignature,truncated=!0)}if(typeof entry.partialJson==`string`){let res=truncateHistoryText(entry.partialJson);entry.partialJson=res.text,truncated||=res.truncated}if(type===`image`){let data=typeof entry.data==`string`?entry.data:void 0,bytes=data?data.length:void 0;`data`in entry&&(delete entry.data,truncated=!0),entry.omitted=!0,bytes!==void 0&&(entry.bytes=bytes)}return{block:entry,truncated}}function sanitizeHistoryMessage(message){if(!message||typeof message!=`object`)return{message,truncated:!1};let entry={...message},truncated=!1;if(`details`in entry&&(delete entry.details,truncated=!0),`usage`in entry&&(delete entry.usage,truncated=!0),`cost`in entry&&(delete entry.cost,truncated=!0),typeof entry.content==`string`){let res=truncateHistoryText(entry.content);entry.content=res.text,truncated||=res.truncated}else if(Array.isArray(entry.content)){let updated=entry.content.map(block=>sanitizeHistoryContentBlock(block));entry.content=updated.map(item=>item.block),truncated||=updated.some(item=>item.truncated)}if(typeof entry.text==`string`){let res=truncateHistoryText(entry.text);entry.text=res.text,truncated||=res.truncated}return{message:entry,truncated}}function jsonUtf8Bytes(value){try{return Buffer.byteLength(JSON.stringify(value),`utf8`)}catch{return Buffer.byteLength(String(value),`utf8`)}}function enforceSessionsHistoryHardCap(params){if(params.bytes<=params.maxBytes)return{items:params.items,bytes:params.bytes,hardCapped:!1};let last=params.items.at(-1),lastOnly=last?[last]:[],lastBytes=jsonUtf8Bytes(lastOnly);if(lastBytes<=params.maxBytes)return{items:lastOnly,bytes:lastBytes,hardCapped:!0};let placeholder=[{role:`assistant`,content:`[sessions_history omitted: message too large]`}];return{items:placeholder,bytes:jsonUtf8Bytes(placeholder),hardCapped:!0}}async function runSessionsHistory(opts,args){{let params=args,sessionKeyParam=readStringParam(params,`sessionKey`,{required:!0}),cfg=loadConfig(),{mainKey,alias,effectiveRequesterKey,restrictToSpawned}=resolveSandboxedSessionToolContext({cfg,agentSessionKey:opts?.agentSessionKey,sandboxed:opts?.sandboxed}),resolvedSession=await resolveSessionReference({sessionKey:sessionKeyParam,alias,mainKey,requesterInternalKey:effectiveRequesterKey,restrictToSpawned});if(!resolvedSession.ok)return jsonResult({status:resolvedSession.status,error:resolvedSession.error});let resolvedKey=resolvedSession.key,displayKey=resolvedSession.displayKey,resolvedViaSessionId=resolvedSession.resolvedViaSessionId;if(restrictToSpawned&&!resolvedViaSessionId&&resolvedKey!==effectiveRequesterKey&&!await isRequesterSpawnedSessionVisible({requesterSessionKey:effectiveRequesterKey,targetSessionKey:resolvedKey}))return jsonResult({status:`forbidden`,error:`Session not visible from this sandboxed agent session: ${sessionKeyParam}`});let a2aPolicy=createAgentToAgentPolicy(cfg),access=(await createSessionVisibilityGuard({action:`history`,requesterSessionKey:effectiveRequesterKey,visibility:resolveEffectiveSessionToolsVisibility({cfg,sandboxed:opts?.sandboxed===!0}),a2aPolicy})).check(resolvedKey);if(!access.allowed)return jsonResult({status:access.status,error:access.error});let limit=typeof params.limit==`number`&&Number.isFinite(params.limit)?Math.max(1,Math.floor(params.limit)):void 0,includeTools=!!params.includeTools,result=await callGateway({method:`chat.history`,params:{sessionKey:resolvedKey,limit}}),rawMessages=Array.isArray(result?.messages)?result.messages:[],selectedMessages=includeTools?rawMessages:stripToolMessages(rawMessages),sanitizedMessages=selectedMessages.map(message=>sanitizeHistoryMessage(message)),contentTruncated=sanitizedMessages.some(entry=>entry.truncated),cappedMessages=capArrayByJsonBytes(sanitizedMessages.map(entry=>entry.message),SESSIONS_HISTORY_MAX_BYTES),droppedMessages=cappedMessages.items.length<selectedMessages.length,hardened=enforceSessionsHistoryHardCap({items:cappedMessages.items,bytes:cappedMessages.bytes,maxBytes:SESSIONS_HISTORY_MAX_BYTES});return jsonResult({sessionKey:displayKey,messages:hardened.items,truncated:droppedMessages||contentTruncated||hardened.hardCapped,droppedMessages:droppedMessages||hardened.hardCapped,contentTruncated,bytes:hardened.bytes})}}function createSessionsHistoryTool(opts){return{label:`Session History`,name:`sessions_history`,description:`Fetch message history for a session.`,parameters:SessionsHistoryToolSchema,execute:async(_toolCallId,args)=>runSessionsHistory(opts,args)}}const SessionsListToolSchema=Type.Object({kinds:Type.Optional(Type.Array(Type.String())),limit:Type.Optional(Type.Number({minimum:1})),activeMinutes:Type.Optional(Type.Number({minimum:1})),messageLimit:Type.Optional(Type.Number({minimum:0}))});async function runSessionsList(opts,args){{let params=args,cfg=loadConfig(),{mainKey,alias,requesterInternalKey,restrictToSpawned}=resolveSandboxedSessionToolContext({cfg,agentSessionKey:opts?.agentSessionKey,sandboxed:opts?.sandboxed}),effectiveRequesterKey=requesterInternalKey??alias,visibility=resolveEffectiveSessionToolsVisibility({cfg,sandboxed:opts?.sandboxed===!0}),allowedKindsList=(readStringArrayParam(params,`kinds`)?.map(value=>value.trim().toLowerCase())??[]).filter(value=>[`main`,`group`,`cron`,`hook`,`node`,`other`].includes(value)),allowedKinds=allowedKindsList.length?new Set(allowedKindsList):void 0,limit=typeof params.limit==`number`&&Number.isFinite(params.limit)?Math.max(1,Math.floor(params.limit)):void 0,activeMinutes=typeof params.activeMinutes==`number`&&Number.isFinite(params.activeMinutes)?Math.max(1,Math.floor(params.activeMinutes)):void 0,messageLimitRaw=typeof params.messageLimit==`number`&&Number.isFinite(params.messageLimit)?Math.max(0,Math.floor(params.messageLimit)):0,messageLimit=Math.min(messageLimitRaw,20),list=await callGateway({method:`sessions.list`,params:{limit,activeMinutes,includeGlobal:!restrictToSpawned,includeUnknown:!restrictToSpawned,spawnedBy:restrictToSpawned?effectiveRequesterKey:void 0}}),sessions=Array.isArray(list?.sessions)?list.sessions:[],storePath=typeof list?.path==`string`?list.path:void 0,visibilityGuard=await createSessionVisibilityGuard({action:`list`,requesterSessionKey:effectiveRequesterKey,visibility,a2aPolicy:createAgentToAgentPolicy(cfg)}),rows=[],historyTargets=[];for(let entry of sessions){if(!entry||typeof entry!=`object`)continue;let key=typeof entry.key==`string`?entry.key:``;if(!key||!visibilityGuard.check(key).allowed||key===`unknown`||key===`global`&&alias!==`global`)continue;let kind=classifySessionKind({key,gatewayKind:typeof entry.kind==`string`?entry.kind:void 0,alias,mainKey});if(allowedKinds&&!allowedKinds.has(kind))continue;let displayKey=resolveDisplaySessionKey({key,alias,mainKey}),entryChannel=typeof entry.channel==`string`?entry.channel:void 0,deliveryContext=entry.deliveryContext&&typeof entry.deliveryContext==`object`?entry.deliveryContext:void 0,deliveryChannel=typeof deliveryContext?.channel==`string`?deliveryContext.channel:void 0,deliveryTo=typeof deliveryContext?.to==`string`?deliveryContext.to:void 0,deliveryAccountId=typeof deliveryContext?.accountId==`string`?deliveryContext.accountId:void 0,lastChannel=deliveryChannel??(typeof entry.lastChannel==`string`?entry.lastChannel:void 0),lastAccountId=deliveryAccountId??(typeof entry.lastAccountId==`string`?entry.lastAccountId:void 0),derivedChannel=deriveChannel({key,kind,channel:entryChannel,lastChannel}),sessionId=typeof entry.sessionId==`string`?entry.sessionId:void 0,sessionFileRaw=entry.sessionFile,sessionFile=typeof sessionFileRaw==`string`?sessionFileRaw:void 0,transcriptPath;if(sessionId&&storePath)try{transcriptPath=resolveSessionFilePath(sessionId,sessionFile?{sessionFile}:void 0,{agentId:resolveAgentIdFromSessionKey(key),sessionsDir:path.dirname(storePath)})}catch{transcriptPath=void 0}let row={key:displayKey,kind,channel:derivedChannel,label:typeof entry.label==`string`?entry.label:void 0,displayName:typeof entry.displayName==`string`?entry.displayName:void 0,deliveryContext:deliveryChannel||deliveryTo||deliveryAccountId?{channel:deliveryChannel,to:deliveryTo,accountId:deliveryAccountId}:void 0,updatedAt:typeof entry.updatedAt==`number`?entry.updatedAt:void 0,sessionId,model:typeof entry.model==`string`?entry.model:void 0,contextTokens:typeof entry.contextTokens==`number`?entry.contextTokens:void 0,totalTokens:typeof entry.totalTokens==`number`?entry.totalTokens:void 0,thinkingLevel:typeof entry.thinkingLevel==`string`?entry.thinkingLevel:void 0,verboseLevel:typeof entry.verboseLevel==`string`?entry.verboseLevel:void 0,systemSent:typeof entry.systemSent==`boolean`?entry.systemSent:void 0,abortedLastRun:typeof entry.abortedLastRun==`boolean`?entry.abortedLastRun:void 0,sendPolicy:typeof entry.sendPolicy==`string`?entry.sendPolicy:void 0,lastChannel,lastTo:deliveryTo??(typeof entry.lastTo==`string`?entry.lastTo:void 0),lastAccountId,transcriptPath};if(messageLimit>0){let resolvedKey=resolveInternalSessionKey({key:displayKey,alias,mainKey});historyTargets.push({row,resolvedKey})}rows.push(row)}if(messageLimit>0&&historyTargets.length>0){let maxConcurrent=Math.min(4,historyTargets.length),index=0,worker=async()=>{for(;;){let next=index;if(index+=1,next>=historyTargets.length)return;let target=historyTargets[next],history=await callGateway({method:`chat.history`,params:{sessionKey:target.resolvedKey,limit:messageLimit}}),filtered=stripToolMessages(Array.isArray(history?.messages)?history.messages:[]);target.row.messages=filtered.length>messageLimit?filtered.slice(-messageLimit):filtered}};await Promise.all(Array.from({length:maxConcurrent},()=>worker()))}return jsonResult({count:rows.length,sessions:rows})}}function createSessionsListTool(opts){return{label:`Sessions`,name:`sessions_list`,description:`List sessions with optional filters and last messages.`,parameters:SessionsListToolSchema,execute:async(_toolCallId,args)=>runSessionsList(opts,args)}}const AGENT_LANE_NESTED=CommandLane.Nested,AGENT_LANE_SUBAGENT=CommandLane.Subagent,ANNOUNCE_SKIP_TOKEN=`ANNOUNCE_SKIP`,REPLY_SKIP_TOKEN=`REPLY_SKIP`;function resolveAnnounceTargetFromKey(sessionKey){let rawParts=sessionKey.split(`:`).filter(Boolean),parts=rawParts.length>=3&&rawParts[0]===`agent`?rawParts.slice(2):rawParts;if(parts.length<3)return null;let[channelRaw,kind,...rest]=parts;if(kind!==`group`&&kind!==`channel`)return null;let threadId,restJoined=rest.join(`:`),topicMatch=restJoined.match(/:topic:(\d+)$/),threadMatch=restJoined.match(/:thread:(\d+)$/),match=topicMatch||threadMatch;match&&(threadId=match[1]);let id=match?restJoined.replace(/:(topic|thread):\d+$/,``):restJoined.trim();if(!id||!channelRaw)return null;let normalizedChannel=normalizeChannelId$1(channelRaw)??normalizeChannelId(channelRaw),channel=normalizedChannel??channelRaw.toLowerCase(),kindTarget=normalizedChannel?normalizedChannel===`discord`||normalizedChannel===`slack`||kind===`channel`?`channel:${id}`:`group:${id}`:id;return{channel,to:(normalizedChannel?getChannelPlugin(normalizedChannel)?.messaging?.normalizeTarget?.(kindTarget):void 0)??kindTarget,threadId}}function buildAgentToAgentMessageContext(params){return[`Agent-to-agent message context:`,params.requesterSessionKey?`Agent 1 (requester) session: ${params.requesterSessionKey}.`:void 0,params.requesterChannel?`Agent 1 (requester) channel: ${params.requesterChannel}.`:void 0,`Agent 2 (target) session: ${params.targetSessionKey}.`].filter(Boolean).join(`
382
382
  `)}function buildAgentToAgentReplyContext(params){return[`Agent-to-agent reply step:`,`Current agent: ${params.currentRole===`requester`?`Agent 1 (requester)`:`Agent 2 (target)`}.`,`Turn ${params.turn} of ${params.maxTurns}.`,params.requesterSessionKey?`Agent 1 (requester) session: ${params.requesterSessionKey}.`:void 0,params.requesterChannel?`Agent 1 (requester) channel: ${params.requesterChannel}.`:void 0,`Agent 2 (target) session: ${params.targetSessionKey}.`,params.targetChannel?`Agent 2 (target) channel: ${params.targetChannel}.`:void 0,`If you want to stop the ping-pong, reply exactly "${REPLY_SKIP_TOKEN}".`].filter(Boolean).join(`
383
383
  `)}function buildAgentToAgentAnnounceContext(params){return[`Agent-to-agent announce step:`,params.requesterSessionKey?`Agent 1 (requester) session: ${params.requesterSessionKey}.`:void 0,params.requesterChannel?`Agent 1 (requester) channel: ${params.requesterChannel}.`:void 0,`Agent 2 (target) session: ${params.targetSessionKey}.`,params.targetChannel?`Agent 2 (target) channel: ${params.targetChannel}.`:void 0,`Original request: ${params.originalMessage}`,params.roundOneReply?`Round 1 reply: ${params.roundOneReply}`:`Round 1 reply: (not available).`,params.latestReply?`Latest reply: ${params.latestReply}`:`Latest reply: (not available).`,`If you want to remain silent, reply exactly "${ANNOUNCE_SKIP_TOKEN}".`,`Any other reply will be posted to the target channel.`,`After this reply, the agent-to-agent conversation is over.`].filter(Boolean).join(`
384
- `)}function isAnnounceSkip(text){return(text??``).trim()===ANNOUNCE_SKIP_TOKEN}function isReplySkip(text){return(text??``).trim()===REPLY_SKIP_TOKEN}function resolvePingPongTurns(cfg){let raw=cfg?.session?.agentToAgent?.maxPingPongTurns;if(typeof raw!=`number`||!Number.isFinite(raw))return 5;let rounded=Math.floor(raw);return Math.max(0,Math.min(5,rounded))}async function readLatestAssistantReply(params){let history=await callGateway({method:`chat.history`,params:{sessionKey:params.sessionKey,limit:params.limit??50}}),filtered=stripToolMessages(Array.isArray(history?.messages)?history.messages:[]);for(let i=filtered.length-1;i>=0;--i){let candidate=filtered[i];if(!candidate||typeof candidate!=`object`||candidate.role!==`assistant`)continue;let text=extractAssistantText(candidate);if(text?.trim())return text}}async function runAgentStep(params){let stepIdem=crypto.randomUUID(),response=await callGateway({method:`agent`,params:{message:params.message,sessionKey:params.sessionKey,idempotencyKey:stepIdem,deliver:!1,channel:params.channel??INTERNAL_MESSAGE_CHANNEL,lane:params.lane??AGENT_LANE_NESTED,extraSystemPrompt:params.extraSystemPrompt,inputProvenance:{kind:`inter_session`,sourceSessionKey:params.sourceSessionKey,sourceChannel:params.sourceChannel,sourceTool:params.sourceTool??`sessions_send`}},timeoutMs:1e4}),resolvedRunId=(typeof response?.runId==`string`&&response.runId?response.runId:``)||stepIdem,stepWaitMs=Math.min(params.timeoutMs,6e4);if((await callGateway({method:`agent.wait`,params:{runId:resolvedRunId,timeoutMs:stepWaitMs},timeoutMs:stepWaitMs+2e3}))?.status===`ok`)return await readLatestAssistantReply({sessionKey:params.sessionKey})}async function resolveAnnounceTarget(params){let parsed=resolveAnnounceTargetFromKey(params.sessionKey),parsedDisplay=resolveAnnounceTargetFromKey(params.displayKey),fallback=parsed??parsedDisplay??null;if(fallback){let normalized=normalizeChannelId$1(fallback.channel);if(!(normalized?getChannelPlugin(normalized):null)?.meta?.preferSessionLookupForAnnounceTarget)return fallback}try{let list=await callGateway({method:`sessions.list`,params:{includeGlobal:!0,includeUnknown:!0,limit:200}}),sessions=Array.isArray(list?.sessions)?list.sessions:[],match=sessions.find(entry=>entry?.key===params.sessionKey)??sessions.find(entry=>entry?.key===params.displayKey),deliveryContext=match?.deliveryContext&&typeof match.deliveryContext==`object`?match.deliveryContext:void 0,channel=(typeof deliveryContext?.channel==`string`?deliveryContext.channel:void 0)??(typeof match?.lastChannel==`string`?match.lastChannel:void 0),to=(typeof deliveryContext?.to==`string`?deliveryContext.to:void 0)??(typeof match?.lastTo==`string`?match.lastTo:void 0),accountId=(typeof deliveryContext?.accountId==`string`?deliveryContext.accountId:void 0)??(typeof match?.lastAccountId==`string`?match.lastAccountId:void 0);if(channel&&to)return{channel,to,accountId}}catch{}return fallback}const log$6=createSubsystemLogger(`agents/sessions-send`);async function runSessionsSendA2AFlow(params){let runContextId=params.waitRunId??`unknown`;try{let primaryReply=params.roundOneReply,latestReply=params.roundOneReply;if(!primaryReply&&params.waitRunId){let waitMs=Math.min(params.announceTimeoutMs,6e4);(await callGateway({method:`agent.wait`,params:{runId:params.waitRunId,timeoutMs:waitMs},timeoutMs:waitMs+2e3}))?.status===`ok`&&(primaryReply=await readLatestAssistantReply({sessionKey:params.targetSessionKey}),latestReply=primaryReply)}if(!latestReply)return;let announceTarget=await resolveAnnounceTarget({sessionKey:params.targetSessionKey,displayKey:params.displayKey}),targetChannel=announceTarget?.channel??`unknown`;if(params.maxPingPongTurns>0&&params.requesterSessionKey&&params.requesterSessionKey!==params.targetSessionKey){let currentSessionKey=params.requesterSessionKey,nextSessionKey=params.targetSessionKey,incomingMessage=latestReply;for(let turn=1;turn<=params.maxPingPongTurns;turn+=1){let currentRole=currentSessionKey===params.requesterSessionKey?`requester`:`target`,replyPrompt=buildAgentToAgentReplyContext({requesterSessionKey:params.requesterSessionKey,requesterChannel:params.requesterChannel,targetSessionKey:params.displayKey,targetChannel,currentRole,turn,maxTurns:params.maxPingPongTurns}),replyText=await runAgentStep({sessionKey:currentSessionKey,message:incomingMessage,extraSystemPrompt:replyPrompt,timeoutMs:params.announceTimeoutMs,lane:AGENT_LANE_NESTED,sourceSessionKey:nextSessionKey,sourceChannel:nextSessionKey===params.requesterSessionKey?params.requesterChannel:targetChannel,sourceTool:`sessions_send`});if(!replyText||isReplySkip(replyText))break;latestReply=replyText,incomingMessage=replyText;let swap=currentSessionKey;currentSessionKey=nextSessionKey,nextSessionKey=swap}}let announcePrompt=buildAgentToAgentAnnounceContext({requesterSessionKey:params.requesterSessionKey,requesterChannel:params.requesterChannel,targetSessionKey:params.displayKey,targetChannel,originalMessage:params.message,roundOneReply:primaryReply,latestReply}),announceReply=await runAgentStep({sessionKey:params.targetSessionKey,message:`Agent-to-agent announce step.`,extraSystemPrompt:announcePrompt,timeoutMs:params.announceTimeoutMs,lane:AGENT_LANE_NESTED,sourceSessionKey:params.requesterSessionKey,sourceChannel:params.requesterChannel,sourceTool:`sessions_send`});if(announceTarget&&announceReply&&announceReply.trim()&&!isAnnounceSkip(announceReply))try{await callGateway({method:`send`,params:{to:announceTarget.to,message:announceReply.trim(),channel:announceTarget.channel,accountId:announceTarget.accountId,idempotencyKey:crypto.randomUUID()},timeoutMs:1e4})}catch(err){log$6.warn(`sessions_send announce delivery failed`,{runId:runContextId,channel:announceTarget.channel,to:announceTarget.to,error:formatErrorMessage(err)})}}catch(err){log$6.warn(`sessions_send announce flow failed`,{runId:runContextId,error:formatErrorMessage(err)})}}const SessionsSendToolSchema=Type.Object({sessionKey:Type.Optional(Type.String()),label:Type.Optional(Type.String({minLength:1,maxLength:SESSION_LABEL_MAX_LENGTH})),agentId:Type.Optional(Type.String({minLength:1,maxLength:64})),message:Type.String(),timeoutSeconds:Type.Optional(Type.Number({minimum:0}))});async function runSessionsSend(opts,args){let params=args,message=readStringParam(params,`message`,{required:!0}),cfg=loadConfig(),{mainKey,alias,effectiveRequesterKey,restrictToSpawned}=resolveSandboxedSessionToolContext({cfg,agentSessionKey:opts?.agentSessionKey,sandboxed:opts?.sandboxed}),a2aPolicy=createAgentToAgentPolicy(cfg),sessionVisibility=resolveEffectiveSessionToolsVisibility({cfg,sandboxed:opts?.sandboxed===!0}),sessionKeyParam=readStringParam(params,`sessionKey`),labelParam=readStringParam(params,`label`)?.trim()||void 0,labelAgentIdParam=readStringParam(params,`agentId`)?.trim()||void 0;if(sessionKeyParam&&labelParam)return jsonResult({runId:crypto.randomUUID(),status:`error`,error:`Provide either sessionKey or label (not both).`});let sessionKey=sessionKeyParam;if(!sessionKey&&labelParam){let requesterAgentId=resolveAgentIdFromSessionKey(effectiveRequesterKey),requestedAgentId=labelAgentIdParam?normalizeAgentId(labelAgentIdParam):void 0;if(restrictToSpawned&&requestedAgentId&&requestedAgentId!==requesterAgentId)return jsonResult({runId:crypto.randomUUID(),status:`forbidden`,error:`Sandboxed sessions_send label lookup is limited to this agent`});if(requesterAgentId&&requestedAgentId&&requestedAgentId!==requesterAgentId){if(!a2aPolicy.enabled)return jsonResult({runId:crypto.randomUUID(),status:`forbidden`,error:`Agent-to-agent messaging is disabled. Set tools.agentToAgent.enabled=true to allow cross-agent sends.`});if(!a2aPolicy.isAllowed(requesterAgentId,requestedAgentId))return jsonResult({runId:crypto.randomUUID(),status:`forbidden`,error:`Agent-to-agent messaging denied by tools.agentToAgent.allow.`})}let resolveParams={label:labelParam,...requestedAgentId?{agentId:requestedAgentId}:{},...restrictToSpawned?{spawnedBy:effectiveRequesterKey}:{}},resolvedKey=``;try{let resolved=await callGateway({method:`sessions.resolve`,params:resolveParams,timeoutMs:1e4});resolvedKey=typeof resolved?.key==`string`?resolved.key.trim():``}catch(err){let msg=err instanceof Error?err.message:String(err);return jsonResult(restrictToSpawned?{runId:crypto.randomUUID(),status:`forbidden`,error:`Session not visible from this sandboxed agent session.`}:{runId:crypto.randomUUID(),status:`error`,error:msg||`No session found with label: ${labelParam}`})}if(!resolvedKey)return jsonResult(restrictToSpawned?{runId:crypto.randomUUID(),status:`forbidden`,error:`Session not visible from this sandboxed agent session.`}:{runId:crypto.randomUUID(),status:`error`,error:`No session found with label: ${labelParam}`});sessionKey=resolvedKey}if(!sessionKey)return jsonResult({runId:crypto.randomUUID(),status:`error`,error:`Either sessionKey or label is required`});let resolvedSession=await resolveSessionReference({sessionKey,alias,mainKey,requesterInternalKey:effectiveRequesterKey,restrictToSpawned});if(!resolvedSession.ok)return jsonResult({runId:crypto.randomUUID(),status:resolvedSession.status,error:resolvedSession.error});let resolvedKey=resolvedSession.key,displayKey=resolvedSession.displayKey,resolvedViaSessionId=resolvedSession.resolvedViaSessionId;if(restrictToSpawned&&!resolvedViaSessionId&&resolvedKey!==effectiveRequesterKey&&!await isRequesterSpawnedSessionVisible({requesterSessionKey:effectiveRequesterKey,targetSessionKey:resolvedKey}))return jsonResult({runId:crypto.randomUUID(),status:`forbidden`,error:`Session not visible from this sandboxed agent session: ${sessionKey}`,sessionKey:displayKey});let timeoutSeconds=typeof params.timeoutSeconds==`number`&&Number.isFinite(params.timeoutSeconds)?Math.max(0,Math.floor(params.timeoutSeconds)):30,timeoutMs=timeoutSeconds*1e3,announceTimeoutMs=timeoutSeconds===0?3e4:timeoutMs,idempotencyKey=crypto.randomUUID(),runId=idempotencyKey,access=(await createSessionVisibilityGuard({action:`send`,requesterSessionKey:effectiveRequesterKey,visibility:sessionVisibility,a2aPolicy})).check(resolvedKey);if(!access.allowed)return jsonResult({runId:crypto.randomUUID(),status:access.status,error:access.error,sessionKey:displayKey});let sendParams={message,sessionKey:resolvedKey,idempotencyKey,deliver:!1,channel:INTERNAL_MESSAGE_CHANNEL,lane:AGENT_LANE_NESTED,extraSystemPrompt:buildAgentToAgentMessageContext({requesterSessionKey:opts?.agentSessionKey,requesterChannel:opts?.agentChannel,targetSessionKey:displayKey}),inputProvenance:{kind:`inter_session`,sourceSessionKey:opts?.agentSessionKey,sourceChannel:opts?.agentChannel,sourceTool:`sessions_send`}},requesterSessionKey=opts?.agentSessionKey,requesterChannel=opts?.agentChannel,maxPingPongTurns=resolvePingPongTurns(cfg),delivery={status:`pending`,mode:`announce`},startA2AFlow=(roundOneReply,waitRunId)=>{runSessionsSendA2AFlow({targetSessionKey:resolvedKey,displayKey,message,announceTimeoutMs,maxPingPongTurns,requesterSessionKey,requesterChannel,roundOneReply,waitRunId})};if(timeoutSeconds===0)try{let response=await callGateway({method:`agent`,params:sendParams,timeoutMs:1e4});return typeof response?.runId==`string`&&response.runId&&(runId=response.runId),startA2AFlow(void 0,runId),jsonResult({runId,status:`accepted`,sessionKey:displayKey,delivery})}catch(err){let messageText=err instanceof Error?err.message:typeof err==`string`?err:`error`;return jsonResult({runId,status:`error`,error:messageText,sessionKey:displayKey})}try{let response=await callGateway({method:`agent`,params:sendParams,timeoutMs:1e4});typeof response?.runId==`string`&&response.runId&&(runId=response.runId)}catch(err){let messageText=err instanceof Error?err.message:typeof err==`string`?err:`error`;return jsonResult({runId,status:`error`,error:messageText,sessionKey:displayKey})}let waitStatus,waitError;try{let wait=await callGateway({method:`agent.wait`,params:{runId,timeoutMs},timeoutMs:timeoutMs+2e3});waitStatus=typeof wait?.status==`string`?wait.status:void 0,waitError=typeof wait?.error==`string`?wait.error:void 0}catch(err){let messageText=err instanceof Error?err.message:typeof err==`string`?err:`error`;return jsonResult({runId,status:messageText.includes(`gateway timeout`)?`timeout`:`error`,error:messageText,sessionKey:displayKey})}if(waitStatus===`timeout`)return jsonResult({runId,status:`timeout`,error:waitError,sessionKey:displayKey});if(waitStatus===`error`)return jsonResult({runId,status:`error`,error:waitError??`agent error`,sessionKey:displayKey});let history=await callGateway({method:`chat.history`,params:{sessionKey:resolvedKey,limit:50}}),filtered=stripToolMessages(Array.isArray(history?.messages)?history.messages:[]),last=filtered.length>0?filtered[filtered.length-1]:void 0,reply=last?extractAssistantText(last):void 0;return startA2AFlow(reply??void 0),jsonResult({runId,status:`ok`,reply,sessionKey:displayKey,delivery})}function createSessionsSendTool(opts){return{label:`Session Send`,name:`sessions_send`,description:`Send a message into another session. Use sessionKey or label to identify the target.`,parameters:SessionsSendToolSchema,execute:async(_toolCallId,args)=>runSessionsSend(opts,args)}}const TOKENS_PER_MILLION=1e6,LOCAL_APIS=new Set([`ollama`,`llama`,`transformers`]),LOCAL_PROVIDERS=new Set([`ollama`,`lmstudio`,`freetoken`,`synapse`,`vllm`,`llama`,`builderforcellm-local`]),LOOPBACK_HOSTS=new Set([`localhost`,`127.0.0.1`,`[::1]`,`::1`,`0.0.0.0`]),finiteNonNegative=n=>typeof n==`number`&&Number.isFinite(n)&&n>=0?n:void 0;function priceForCost(cost){let input=finiteNonNegative(cost?.input),output=finiteNonNegative(cost?.output);if(!(input===void 0||output===void 0))return{input:input/TOKENS_PER_MILLION,output:output/TOKENS_PER_MILLION}}function tierForCost(cost){let price=priceForCost(cost);if(!price)return;let outputPerMillion=price.output*TOKENS_PER_MILLION;return price.input===0&&price.output===0?`FREE`:outputPerMillion<8?`STANDARD`:outputPerMillion<20?`PREMIUM`:`ULTRA`}const FREE_POOL_PROVIDERS=new Set([`builderforcellm`]),FREE_ID_MARKER=/[:-]free$/i;function isExplicitlyFree(provider,id){return FREE_POOL_PROVIDERS.has(normalizeProviderId(provider))||FREE_ID_MARKER.test(id.trim())}const isZeroCost=cost=>cost!==void 0&&cost.input===0&&cost.output===0;function isLoopbackUrl(baseUrl){if(!baseUrl)return!1;try{return LOOPBACK_HOSTS.has(new URL(baseUrl).hostname.toLowerCase())}catch{return!1}}function isLocalModel(provider,entry){return LOCAL_PROVIDERS.has(normalizeProviderId(provider))?!0:entry?.api!=null&&LOCAL_APIS.has(entry.api)||isLoopbackUrl(entry?.baseUrl)}function vendorOfCandidateKey(key){let slash=key.indexOf(`/`);return normalizeProviderId(slash===-1?key:key.slice(0,slash))}function catalogViewFromEntries(entries){let byKey=new Map;for(let entry of entries){let provider=normalizeProviderId(entry.provider??``),id=entry.id?.trim();if(!provider||!id)continue;let key=modelKey(provider,id);byKey.has(key)||byKey.set(key,{...entry,provider,id})}let rowOf=model=>{let slash=model.indexOf(`/`);if(slash!==-1)return byKey.get(modelKey(normalizeProviderId(model.slice(0,slash)),model.slice(slash+1)))},residency=model=>isLocalModel(vendorOfCandidateKey(model),rowOf(model))?`local`:`cloud`,trustedCost=model=>{if(residency(model)===`local`)return{input:0,output:0};let row=rowOf(model);if(!(!row||isZeroCost(row.cost)&&!isExplicitlyFree(row.provider,row.id)))return row.cost};return{vendorOf:vendorOfCandidateKey,tierOf:model=>tierForCost(trustedCost(model)),priceOf:model=>priceForCost(trustedCost(model)),residencyOf:residency}}function configuredEntries(cfg){let providers=cfg?.models?.providers??{};return Object.entries(providers).flatMap(([provider,pc])=>(pc?.models??[]).map(m=>({provider,id:m.id,cost:m.cost,api:m.api??pc.api,baseUrl:pc.baseUrl})))}function registryEntries(agentDir){return discoverModels(discoverAuthStorage(agentDir),agentDir).getAll().map(m=>({provider:m.provider,id:m.id,cost:m.cost,api:m.api,baseUrl:m.baseUrl}))}function loadOnPremCatalogView(params){let entries=configuredEntries(params?.cfg);try{entries.push(...registryEntries(params?.agentDir??resolveBuilderForceAgentsAgentDir()))}catch{}return catalogViewFromEntries(entries)}async function resolveRoleRoutedModel(params){try{let resolved=resolveModelRefFromString({raw:params.lead,defaultProvider:DEFAULT_PROVIDER,aliasIndex:buildModelAliasIndex({cfg:params.cfg,defaultProvider:DEFAULT_PROVIDER})});if(!resolved)return params.lead;let winner=(await seedLearnedModel({candidates:resolveFallbackCandidates({cfg:params.cfg,provider:resolved.ref.provider,model:resolved.ref.model}),...params.prompt==null?{}:{prompt:params.prompt},routing:{role:params.role,view:params.view??loadOnPremCatalogView({cfg:params.cfg})}})).ranked[0];return winner?candidateKey(winner):params.lead}catch(err){return logDebug(`[model-routing] role routing failed, keeping ${params.lead}: ${String(err)}`),params.lead}}async function resolveSubagentSpawnModel(params){let selection=resolveSubagentSpawnModelSelection(params);return(normalizeModelSelection(params.modelOverride)??resolveSubagentConfiguredModelSelection({cfg:params.cfg,agentId:params.agentId}))||!params.role?selection:resolveRoleRoutedModel({cfg:params.cfg,lead:selection,role:params.role,prompt:params.task})}async function resolveRelayTaskModel(params){try{let cfg=params.cfg??loadConfig(),gateway=normalizeProviderId(DEFAULT_PROVIDER),candidates=resolveFallbackCandidates({cfg,provider:``,model:``}).filter(c=>normalizeProviderId(c.provider)===gateway&&c.model!==DEFAULT_MODEL);return candidates.length===0?void 0:(await seedLearnedModel({candidates,prompt:params.prompt,routing:{role:`code`,view:loadOnPremCatalogView({cfg})}})).ranked[0]?.model}catch(err){logDebug(`[model-routing] relay task routing failed, engine default stands: ${String(err)}`);return}}function splitModelRef(ref){if(!ref)return{provider:void 0,model:void 0};let trimmed=ref.trim();if(!trimmed)return{provider:void 0,model:void 0};let[provider,model]=trimmed.split(`/`,2);return model?{provider,model}:{provider:void 0,model:trimmed}}async function spawnSubagentDirect(params,ctx){let task=params.task,label=params.label?.trim()||``,requestedAgentId=params.agentId,modelOverride=params.model,thinkingOverrideRaw=params.thinking,cleanup=params.cleanup===`keep`||params.cleanup===`delete`?params.cleanup:`keep`,requesterOrigin=normalizeDeliveryContext({channel:ctx.agentChannel,accountId:ctx.agentAccountId,to:ctx.agentTo,threadId:ctx.agentThreadId}),runTimeoutSeconds=typeof params.runTimeoutSeconds==`number`&&Number.isFinite(params.runTimeoutSeconds)?Math.max(0,Math.floor(params.runTimeoutSeconds)):0,modelApplied=!1,cfg=loadConfig(),{mainKey,alias}=resolveMainSessionAlias(cfg),requesterSessionKey=ctx.agentSessionKey,requesterInternalKey=requesterSessionKey?resolveInternalSessionKey({key:requesterSessionKey,alias,mainKey}):alias,requesterDisplayKey=resolveDisplaySessionKey({key:requesterInternalKey,alias,mainKey}),callerDepth=getSubagentDepthFromSessionStore(requesterInternalKey,{cfg}),maxSpawnDepth=cfg.agents?.defaults?.subagents?.maxSpawnDepth??1;if(callerDepth>=maxSpawnDepth)return{status:`forbidden`,error:`sessions_spawn is not allowed at this depth (current depth: ${callerDepth}, max: ${maxSpawnDepth})`};let maxChildren=cfg.agents?.defaults?.subagents?.maxChildrenPerAgent??5,activeChildren=await countActiveRunsForSession(requesterInternalKey);if(activeChildren>=maxChildren)return{status:`forbidden`,error:`sessions_spawn has reached max active children for this session (${activeChildren}/${maxChildren})`};let requesterAgentId=normalizeAgentId(ctx.requesterAgentIdOverride??parseAgentSessionKey(requesterInternalKey)?.agentId),targetAgentId=requestedAgentId?normalizeAgentId(requestedAgentId):requesterAgentId;if(targetAgentId!==requesterAgentId){let allowAgents=resolveAgentConfig(cfg,requesterAgentId)?.subagents?.allowAgents??[],allowAny=allowAgents.some(value=>value.trim()===`*`),normalizedTargetId=targetAgentId.toLowerCase(),allowSet=new Set(allowAgents.filter(value=>value.trim()&&value.trim()!==`*`).map(value=>normalizeAgentId(value).toLowerCase()));if(!allowAny&&!allowSet.has(normalizedTargetId))return{status:`forbidden`,error:`agentId is not allowed for sessions_spawn (allowed: ${allowSet.size>0?Array.from(allowSet).join(`, `):`none`})`}}if(params.roleConfig){cfg.agents||={list:[]};let agentsList=cfg.agents.list??(cfg.agents.list=[]),existingIdx=agentsList.findIndex(e=>normalizeAgentId(e.id)===targetAgentId),role=params.roleConfig,newEntry={id:targetAgentId,skills:role.tools,...role.model?{model:role.model}:{}};existingIdx>=0?agentsList[existingIdx]={...agentsList[existingIdx],...newEntry}:agentsList.push(newEntry),!modelOverride&&role.model&&(modelOverride=role.model),!thinkingOverrideRaw&&role.thinking&&(thinkingOverrideRaw=role.thinking)}let childSessionKey=`agent:${targetAgentId}:subagent:${crypto.randomUUID()}`,childDepth=callerDepth+1,spawnedByKey=requesterInternalKey,targetAgentConfig=resolveAgentConfig(cfg,targetAgentId),resolvedModel=await resolveSubagentSpawnModel({cfg,agentId:targetAgentId,modelOverride,role:modelRoleForAgentRole(params.roleConfig?.name),task}),resolvedThinkingDefaultRaw=readStringParam(targetAgentConfig?.subagents??{},`thinking`)??readStringParam(cfg.agents?.defaults?.subagents??{},`thinking`),thinkingOverride,thinkingCandidateRaw=thinkingOverrideRaw||resolvedThinkingDefaultRaw;if(thinkingCandidateRaw){let normalized=normalizeThinkLevel(thinkingCandidateRaw);if(!normalized){let{provider,model}=splitModelRef(resolvedModel);return{status:`error`,error:`Invalid thinking level "${thinkingCandidateRaw}". Use one of: ${formatThinkingLevels(provider,model)}.`}}thinkingOverride=normalized}try{await callGateway({method:`sessions.patch`,params:{key:childSessionKey,spawnDepth:childDepth},timeoutMs:1e4})}catch(err){return{status:`error`,error:err instanceof Error?err.message:typeof err==`string`?err:`error`,childSessionKey}}if(resolvedModel)try{await callGateway({method:`sessions.patch`,params:{key:childSessionKey,model:resolvedModel},timeoutMs:1e4}),modelApplied=!0}catch(err){return{status:`error`,error:err instanceof Error?err.message:typeof err==`string`?err:`error`,childSessionKey}}if(thinkingOverride!==void 0)try{await callGateway({method:`sessions.patch`,params:{key:childSessionKey,thinkingLevel:thinkingOverride===`off`?null:thinkingOverride},timeoutMs:1e4})}catch(err){return{status:`error`,error:err instanceof Error?err.message:typeof err==`string`?err:`error`,childSessionKey}}let childSystemPrompt=buildSubagentSystemPrompt({requesterSessionKey,requesterOrigin,childSessionKey,label:label||void 0,task,childDepth,maxSpawnDepth});if(params.roleConfig){params.roleConfig.systemPrompt&&(childSystemPrompt+=`
384
+ `)}function isAnnounceSkip(text){return(text??``).trim()===ANNOUNCE_SKIP_TOKEN}function isReplySkip(text){return(text??``).trim()===REPLY_SKIP_TOKEN}function resolvePingPongTurns(cfg){let raw=cfg?.session?.agentToAgent?.maxPingPongTurns;if(typeof raw!=`number`||!Number.isFinite(raw))return 5;let rounded=Math.floor(raw);return Math.max(0,Math.min(5,rounded))}async function readLatestAssistantReply(params){let history=await callGateway({method:`chat.history`,params:{sessionKey:params.sessionKey,limit:params.limit??50}}),filtered=stripToolMessages(Array.isArray(history?.messages)?history.messages:[]);for(let i=filtered.length-1;i>=0;--i){let candidate=filtered[i];if(!candidate||typeof candidate!=`object`||candidate.role!==`assistant`)continue;let text=extractAssistantText(candidate);if(text?.trim())return text}}async function runAgentStep(params){let stepIdem=crypto.randomUUID(),response=await callGateway({method:`agent`,params:{message:params.message,sessionKey:params.sessionKey,idempotencyKey:stepIdem,deliver:!1,channel:params.channel??INTERNAL_MESSAGE_CHANNEL,lane:params.lane??AGENT_LANE_NESTED,extraSystemPrompt:params.extraSystemPrompt,inputProvenance:{kind:`inter_session`,sourceSessionKey:params.sourceSessionKey,sourceChannel:params.sourceChannel,sourceTool:params.sourceTool??`sessions_send`}},timeoutMs:1e4}),resolvedRunId=(typeof response?.runId==`string`&&response.runId?response.runId:``)||stepIdem,stepWaitMs=Math.min(params.timeoutMs,6e4);if((await callGateway({method:`agent.wait`,params:{runId:resolvedRunId,timeoutMs:stepWaitMs},timeoutMs:stepWaitMs+2e3}))?.status===`ok`)return await readLatestAssistantReply({sessionKey:params.sessionKey})}async function resolveAnnounceTarget(params){let parsed=resolveAnnounceTargetFromKey(params.sessionKey),parsedDisplay=resolveAnnounceTargetFromKey(params.displayKey),fallback=parsed??parsedDisplay??null;if(fallback){let normalized=normalizeChannelId$1(fallback.channel);if(!(normalized?getChannelPlugin(normalized):null)?.meta?.preferSessionLookupForAnnounceTarget)return fallback}try{let list=await callGateway({method:`sessions.list`,params:{includeGlobal:!0,includeUnknown:!0,limit:200}}),sessions=Array.isArray(list?.sessions)?list.sessions:[],match=sessions.find(entry=>entry?.key===params.sessionKey)??sessions.find(entry=>entry?.key===params.displayKey),deliveryContext=match?.deliveryContext&&typeof match.deliveryContext==`object`?match.deliveryContext:void 0,channel=(typeof deliveryContext?.channel==`string`?deliveryContext.channel:void 0)??(typeof match?.lastChannel==`string`?match.lastChannel:void 0),to=(typeof deliveryContext?.to==`string`?deliveryContext.to:void 0)??(typeof match?.lastTo==`string`?match.lastTo:void 0),accountId=(typeof deliveryContext?.accountId==`string`?deliveryContext.accountId:void 0)??(typeof match?.lastAccountId==`string`?match.lastAccountId:void 0);if(channel&&to)return{channel,to,accountId}}catch{}return fallback}const log$6=createSubsystemLogger(`agents/sessions-send`);async function runSessionsSendA2AFlow(params){let runContextId=params.waitRunId??`unknown`;try{let primaryReply=params.roundOneReply,latestReply=params.roundOneReply;if(!primaryReply&&params.waitRunId){let waitMs=Math.min(params.announceTimeoutMs,6e4);(await callGateway({method:`agent.wait`,params:{runId:params.waitRunId,timeoutMs:waitMs},timeoutMs:waitMs+2e3}))?.status===`ok`&&(primaryReply=await readLatestAssistantReply({sessionKey:params.targetSessionKey}),latestReply=primaryReply)}if(!latestReply)return;let announceTarget=await resolveAnnounceTarget({sessionKey:params.targetSessionKey,displayKey:params.displayKey}),targetChannel=announceTarget?.channel??`unknown`;if(params.maxPingPongTurns>0&&params.requesterSessionKey&&params.requesterSessionKey!==params.targetSessionKey){let currentSessionKey=params.requesterSessionKey,nextSessionKey=params.targetSessionKey,incomingMessage=latestReply;for(let turn=1;turn<=params.maxPingPongTurns;turn+=1){let currentRole=currentSessionKey===params.requesterSessionKey?`requester`:`target`,replyPrompt=buildAgentToAgentReplyContext({requesterSessionKey:params.requesterSessionKey,requesterChannel:params.requesterChannel,targetSessionKey:params.displayKey,targetChannel,currentRole,turn,maxTurns:params.maxPingPongTurns}),replyText=await runAgentStep({sessionKey:currentSessionKey,message:incomingMessage,extraSystemPrompt:replyPrompt,timeoutMs:params.announceTimeoutMs,lane:AGENT_LANE_NESTED,sourceSessionKey:nextSessionKey,sourceChannel:nextSessionKey===params.requesterSessionKey?params.requesterChannel:targetChannel,sourceTool:`sessions_send`});if(!replyText||isReplySkip(replyText))break;latestReply=replyText,incomingMessage=replyText;let swap=currentSessionKey;currentSessionKey=nextSessionKey,nextSessionKey=swap}}let announcePrompt=buildAgentToAgentAnnounceContext({requesterSessionKey:params.requesterSessionKey,requesterChannel:params.requesterChannel,targetSessionKey:params.displayKey,targetChannel,originalMessage:params.message,roundOneReply:primaryReply,latestReply}),announceReply=await runAgentStep({sessionKey:params.targetSessionKey,message:`Agent-to-agent announce step.`,extraSystemPrompt:announcePrompt,timeoutMs:params.announceTimeoutMs,lane:AGENT_LANE_NESTED,sourceSessionKey:params.requesterSessionKey,sourceChannel:params.requesterChannel,sourceTool:`sessions_send`});if(announceTarget&&announceReply&&announceReply.trim()&&!isAnnounceSkip(announceReply))try{await callGateway({method:`send`,params:{to:announceTarget.to,message:announceReply.trim(),channel:announceTarget.channel,accountId:announceTarget.accountId,idempotencyKey:crypto.randomUUID()},timeoutMs:1e4})}catch(err){log$6.warn(`sessions_send announce delivery failed`,{runId:runContextId,channel:announceTarget.channel,to:announceTarget.to,error:formatErrorMessage(err)})}}catch(err){log$6.warn(`sessions_send announce flow failed`,{runId:runContextId,error:formatErrorMessage(err)})}}const SessionsSendToolSchema=Type.Object({sessionKey:Type.Optional(Type.String()),label:Type.Optional(Type.String({minLength:1,maxLength:SESSION_LABEL_MAX_LENGTH})),agentId:Type.Optional(Type.String({minLength:1,maxLength:64})),message:Type.String(),timeoutSeconds:Type.Optional(Type.Number({minimum:0}))});async function runSessionsSend(opts,args){let params=args,message=readStringParam(params,`message`,{required:!0}),cfg=loadConfig(),{mainKey,alias,effectiveRequesterKey,restrictToSpawned}=resolveSandboxedSessionToolContext({cfg,agentSessionKey:opts?.agentSessionKey,sandboxed:opts?.sandboxed}),a2aPolicy=createAgentToAgentPolicy(cfg),sessionVisibility=resolveEffectiveSessionToolsVisibility({cfg,sandboxed:opts?.sandboxed===!0}),sessionKeyParam=readStringParam(params,`sessionKey`),labelParam=readStringParam(params,`label`)?.trim()||void 0,labelAgentIdParam=readStringParam(params,`agentId`)?.trim()||void 0;if(sessionKeyParam&&labelParam)return jsonResult({runId:crypto.randomUUID(),status:`error`,error:`Provide either sessionKey or label (not both).`});let sessionKey=sessionKeyParam;if(!sessionKey&&labelParam){let requesterAgentId=resolveAgentIdFromSessionKey(effectiveRequesterKey),requestedAgentId=labelAgentIdParam?normalizeAgentId(labelAgentIdParam):void 0;if(restrictToSpawned&&requestedAgentId&&requestedAgentId!==requesterAgentId)return jsonResult({runId:crypto.randomUUID(),status:`forbidden`,error:`Sandboxed sessions_send label lookup is limited to this agent`});if(requesterAgentId&&requestedAgentId&&requestedAgentId!==requesterAgentId){if(!a2aPolicy.enabled)return jsonResult({runId:crypto.randomUUID(),status:`forbidden`,error:`Agent-to-agent messaging is disabled. Set tools.agentToAgent.enabled=true to allow cross-agent sends.`});if(!a2aPolicy.isAllowed(requesterAgentId,requestedAgentId))return jsonResult({runId:crypto.randomUUID(),status:`forbidden`,error:`Agent-to-agent messaging denied by tools.agentToAgent.allow.`})}let resolveParams={label:labelParam,...requestedAgentId?{agentId:requestedAgentId}:{},...restrictToSpawned?{spawnedBy:effectiveRequesterKey}:{}},resolvedKey=``;try{let resolved=await callGateway({method:`sessions.resolve`,params:resolveParams,timeoutMs:1e4});resolvedKey=typeof resolved?.key==`string`?resolved.key.trim():``}catch(err){let msg=err instanceof Error?err.message:String(err);return jsonResult(restrictToSpawned?{runId:crypto.randomUUID(),status:`forbidden`,error:`Session not visible from this sandboxed agent session.`}:{runId:crypto.randomUUID(),status:`error`,error:msg||`No session found with label: ${labelParam}`})}if(!resolvedKey)return jsonResult(restrictToSpawned?{runId:crypto.randomUUID(),status:`forbidden`,error:`Session not visible from this sandboxed agent session.`}:{runId:crypto.randomUUID(),status:`error`,error:`No session found with label: ${labelParam}`});sessionKey=resolvedKey}if(!sessionKey)return jsonResult({runId:crypto.randomUUID(),status:`error`,error:`Either sessionKey or label is required`});let resolvedSession=await resolveSessionReference({sessionKey,alias,mainKey,requesterInternalKey:effectiveRequesterKey,restrictToSpawned});if(!resolvedSession.ok)return jsonResult({runId:crypto.randomUUID(),status:resolvedSession.status,error:resolvedSession.error});let resolvedKey=resolvedSession.key,displayKey=resolvedSession.displayKey,resolvedViaSessionId=resolvedSession.resolvedViaSessionId;if(restrictToSpawned&&!resolvedViaSessionId&&resolvedKey!==effectiveRequesterKey&&!await isRequesterSpawnedSessionVisible({requesterSessionKey:effectiveRequesterKey,targetSessionKey:resolvedKey}))return jsonResult({runId:crypto.randomUUID(),status:`forbidden`,error:`Session not visible from this sandboxed agent session: ${sessionKey}`,sessionKey:displayKey});let timeoutSeconds=typeof params.timeoutSeconds==`number`&&Number.isFinite(params.timeoutSeconds)?Math.max(0,Math.floor(params.timeoutSeconds)):30,timeoutMs=timeoutSeconds*1e3,announceTimeoutMs=timeoutSeconds===0?3e4:timeoutMs,idempotencyKey=crypto.randomUUID(),runId=idempotencyKey,access=(await createSessionVisibilityGuard({action:`send`,requesterSessionKey:effectiveRequesterKey,visibility:sessionVisibility,a2aPolicy})).check(resolvedKey);if(!access.allowed)return jsonResult({runId:crypto.randomUUID(),status:access.status,error:access.error,sessionKey:displayKey});let sendParams={message,sessionKey:resolvedKey,idempotencyKey,deliver:!1,channel:INTERNAL_MESSAGE_CHANNEL,lane:AGENT_LANE_NESTED,extraSystemPrompt:buildAgentToAgentMessageContext({requesterSessionKey:opts?.agentSessionKey,requesterChannel:opts?.agentChannel,targetSessionKey:displayKey}),inputProvenance:{kind:`inter_session`,sourceSessionKey:opts?.agentSessionKey,sourceChannel:opts?.agentChannel,sourceTool:`sessions_send`}},requesterSessionKey=opts?.agentSessionKey,requesterChannel=opts?.agentChannel,maxPingPongTurns=resolvePingPongTurns(cfg),delivery={status:`pending`,mode:`announce`},startA2AFlow=(roundOneReply,waitRunId)=>{runSessionsSendA2AFlow({targetSessionKey:resolvedKey,displayKey,message,announceTimeoutMs,maxPingPongTurns,requesterSessionKey,requesterChannel,roundOneReply,waitRunId})};if(timeoutSeconds===0)try{let response=await callGateway({method:`agent`,params:sendParams,timeoutMs:1e4});return typeof response?.runId==`string`&&response.runId&&(runId=response.runId),startA2AFlow(void 0,runId),jsonResult({runId,status:`accepted`,sessionKey:displayKey,delivery})}catch(err){let messageText=err instanceof Error?err.message:typeof err==`string`?err:`error`;return jsonResult({runId,status:`error`,error:messageText,sessionKey:displayKey})}try{let response=await callGateway({method:`agent`,params:sendParams,timeoutMs:1e4});typeof response?.runId==`string`&&response.runId&&(runId=response.runId)}catch(err){let messageText=err instanceof Error?err.message:typeof err==`string`?err:`error`;return jsonResult({runId,status:`error`,error:messageText,sessionKey:displayKey})}let waitStatus,waitError;try{let wait=await callGateway({method:`agent.wait`,params:{runId,timeoutMs},timeoutMs:timeoutMs+2e3});waitStatus=typeof wait?.status==`string`?wait.status:void 0,waitError=typeof wait?.error==`string`?wait.error:void 0}catch(err){let messageText=err instanceof Error?err.message:typeof err==`string`?err:`error`;return jsonResult({runId,status:messageText.includes(`gateway timeout`)?`timeout`:`error`,error:messageText,sessionKey:displayKey})}if(waitStatus===`timeout`)return jsonResult({runId,status:`timeout`,error:waitError,sessionKey:displayKey});if(waitStatus===`error`)return jsonResult({runId,status:`error`,error:waitError??`agent error`,sessionKey:displayKey});let history=await callGateway({method:`chat.history`,params:{sessionKey:resolvedKey,limit:50}}),filtered=stripToolMessages(Array.isArray(history?.messages)?history.messages:[]),last=filtered.length>0?filtered[filtered.length-1]:void 0,reply=last?extractAssistantText(last):void 0;return startA2AFlow(reply??void 0),jsonResult({runId,status:`ok`,reply,sessionKey:displayKey,delivery})}function createSessionsSendTool(opts){return{label:`Session Send`,name:`sessions_send`,description:`Send a message into another session. Use sessionKey or label to identify the target.`,parameters:SessionsSendToolSchema,execute:async(_toolCallId,args)=>runSessionsSend(opts,args)}}const TOKENS_PER_MILLION=1e6,LOCAL_APIS=new Set([`ollama`,`llama`,`transformers`]),LOCAL_PROVIDERS=new Set([`ollama`,`lmstudio`,`freetoken`,`synapse`,`vllm`,`llama`,`builderforcellm-local`]),LOOPBACK_HOSTS=new Set([`localhost`,`127.0.0.1`,`[::1]`,`::1`,`0.0.0.0`]),finiteNonNegative=n=>typeof n==`number`&&Number.isFinite(n)&&n>=0?n:void 0;function priceForCost(cost){let input=finiteNonNegative(cost?.input),output=finiteNonNegative(cost?.output);if(!(input===void 0||output===void 0))return{input:input/TOKENS_PER_MILLION,output:output/TOKENS_PER_MILLION}}function tierForCost(cost){let price=priceForCost(cost);if(!price)return;let outputPerMillion=price.output*TOKENS_PER_MILLION;return price.input===0&&price.output===0?`FREE`:outputPerMillion<8?`STANDARD`:outputPerMillion<20?`PREMIUM`:`ULTRA`}const FREE_POOL_PROVIDERS=new Set([`builderforcellm`]),FREE_ID_MARKER=/[:-]free$/i;function isExplicitlyFree(provider,id){return FREE_POOL_PROVIDERS.has(normalizeProviderId(provider))||FREE_ID_MARKER.test(id.trim())}const isZeroCost=cost=>cost!==void 0&&cost.input===0&&cost.output===0;function isLoopbackUrl(baseUrl){if(!baseUrl)return!1;try{return LOOPBACK_HOSTS.has(new URL(baseUrl).hostname.toLowerCase())}catch{return!1}}function isLocalModel(provider,entry){return LOCAL_PROVIDERS.has(normalizeProviderId(provider))?!0:entry?.api!=null&&LOCAL_APIS.has(entry.api)||isLoopbackUrl(entry?.baseUrl)}function vendorOfCandidateKey(key){let slash=key.indexOf(`/`);return normalizeProviderId(slash===-1?key:key.slice(0,slash))}function catalogViewFromEntries(entries){let byKey=new Map;for(let entry of entries){let provider=normalizeProviderId(entry.provider??``),id=entry.id?.trim();if(!provider||!id)continue;let key=modelKey(provider,id);byKey.has(key)||byKey.set(key,{...entry,provider,id})}let rowOf=model=>{let slash=model.indexOf(`/`);if(slash!==-1)return byKey.get(modelKey(normalizeProviderId(model.slice(0,slash)),model.slice(slash+1)))},residency=model=>isLocalModel(vendorOfCandidateKey(model),rowOf(model))?`local`:`cloud`,trustedCost=model=>{if(residency(model)===`local`)return{input:0,output:0};let row=rowOf(model);if(!(!row||isZeroCost(row.cost)&&!isExplicitlyFree(row.provider,row.id)))return row.cost};return{vendorOf:vendorOfCandidateKey,tierOf:model=>tierForCost(trustedCost(model)),priceOf:model=>priceForCost(trustedCost(model)),residencyOf:residency}}function configuredEntries(cfg){let providers=cfg?.models?.providers??{};return Object.entries(providers).flatMap(([provider,pc])=>(pc?.models??[]).map(m=>({provider,id:m.id,cost:m.cost,api:m.api??pc.api,baseUrl:pc.baseUrl})))}function registryEntries(agentDir){return discoverModels(discoverAuthStorage(agentDir),agentDir).getAll().map(m=>({provider:m.provider,id:m.id,cost:m.cost,api:m.api,baseUrl:m.baseUrl}))}function loadOnPremCatalogView(params){let entries=configuredEntries(params?.cfg);try{entries.push(...registryEntries(params?.agentDir??resolveBuilderForceAgentsAgentDir()))}catch(err){logDebug(`[model-catalog-view] models.json unreadable, configured rows only: ${String(err)}`)}return catalogViewFromEntries(entries)}async function resolveRoleRoutedModel(params){try{let resolved=resolveModelRefFromString({raw:params.lead,defaultProvider:DEFAULT_PROVIDER,aliasIndex:buildModelAliasIndex({cfg:params.cfg,defaultProvider:DEFAULT_PROVIDER})});if(!resolved)return params.lead;let winner=(await seedLearnedModel({candidates:resolveFallbackCandidates({cfg:params.cfg,provider:resolved.ref.provider,model:resolved.ref.model}),...params.prompt==null?{}:{prompt:params.prompt},routing:{role:params.role,view:params.view??loadOnPremCatalogView({cfg:params.cfg})}})).ranked[0];return winner?candidateKey(winner):params.lead}catch(err){return logDebug(`[model-routing] role routing failed, keeping ${params.lead}: ${String(err)}`),params.lead}}async function resolveSubagentSpawnModel(params){let selection=resolveSubagentSpawnModelSelection(params);return(normalizeModelSelection(params.modelOverride)??resolveSubagentConfiguredModelSelection({cfg:params.cfg,agentId:params.agentId}))||!params.role?selection:resolveRoleRoutedModel({cfg:params.cfg,lead:selection,role:params.role,prompt:params.task})}async function resolveRelayTaskModel(params){try{let cfg=params.cfg??loadConfig(),gateway=normalizeProviderId(DEFAULT_PROVIDER),candidates=resolveFallbackCandidates({cfg,provider:``,model:``}).filter(c=>normalizeProviderId(c.provider)===gateway&&c.model!==DEFAULT_MODEL);return candidates.length===0?void 0:(await seedLearnedModel({candidates,prompt:params.prompt,routing:{role:`code`,view:loadOnPremCatalogView({cfg})}})).ranked[0]?.model}catch(err){logDebug(`[model-routing] relay task routing failed, engine default stands: ${String(err)}`);return}}function splitModelRef(ref){if(!ref)return{provider:void 0,model:void 0};let trimmed=ref.trim();if(!trimmed)return{provider:void 0,model:void 0};let[provider,model]=trimmed.split(`/`,2);return model?{provider,model}:{provider:void 0,model:trimmed}}async function spawnSubagentDirect(params,ctx){let task=params.task,label=params.label?.trim()||``,requestedAgentId=params.agentId,modelOverride=params.model,thinkingOverrideRaw=params.thinking,cleanup=params.cleanup===`keep`||params.cleanup===`delete`?params.cleanup:`keep`,requesterOrigin=normalizeDeliveryContext({channel:ctx.agentChannel,accountId:ctx.agentAccountId,to:ctx.agentTo,threadId:ctx.agentThreadId}),runTimeoutSeconds=typeof params.runTimeoutSeconds==`number`&&Number.isFinite(params.runTimeoutSeconds)?Math.max(0,Math.floor(params.runTimeoutSeconds)):0,modelApplied=!1,cfg=loadConfig(),{mainKey,alias}=resolveMainSessionAlias(cfg),requesterSessionKey=ctx.agentSessionKey,requesterInternalKey=requesterSessionKey?resolveInternalSessionKey({key:requesterSessionKey,alias,mainKey}):alias,requesterDisplayKey=resolveDisplaySessionKey({key:requesterInternalKey,alias,mainKey}),callerDepth=getSubagentDepthFromSessionStore(requesterInternalKey,{cfg}),maxSpawnDepth=cfg.agents?.defaults?.subagents?.maxSpawnDepth??1;if(callerDepth>=maxSpawnDepth)return{status:`forbidden`,error:`sessions_spawn is not allowed at this depth (current depth: ${callerDepth}, max: ${maxSpawnDepth})`};let maxChildren=cfg.agents?.defaults?.subagents?.maxChildrenPerAgent??5,activeChildren=await countActiveRunsForSession(requesterInternalKey);if(activeChildren>=maxChildren)return{status:`forbidden`,error:`sessions_spawn has reached max active children for this session (${activeChildren}/${maxChildren})`};let requesterAgentId=normalizeAgentId(ctx.requesterAgentIdOverride??parseAgentSessionKey(requesterInternalKey)?.agentId),targetAgentId=requestedAgentId?normalizeAgentId(requestedAgentId):requesterAgentId;if(targetAgentId!==requesterAgentId){let allowAgents=resolveAgentConfig(cfg,requesterAgentId)?.subagents?.allowAgents??[],allowAny=allowAgents.some(value=>value.trim()===`*`),normalizedTargetId=targetAgentId.toLowerCase(),allowSet=new Set(allowAgents.filter(value=>value.trim()&&value.trim()!==`*`).map(value=>normalizeAgentId(value).toLowerCase()));if(!allowAny&&!allowSet.has(normalizedTargetId))return{status:`forbidden`,error:`agentId is not allowed for sessions_spawn (allowed: ${allowSet.size>0?Array.from(allowSet).join(`, `):`none`})`}}if(params.roleConfig){cfg.agents||={list:[]};let agentsList=cfg.agents.list??(cfg.agents.list=[]),existingIdx=agentsList.findIndex(e=>normalizeAgentId(e.id)===targetAgentId),role=params.roleConfig,newEntry={id:targetAgentId,skills:role.tools,...role.model?{model:role.model}:{}};existingIdx>=0?agentsList[existingIdx]={...agentsList[existingIdx],...newEntry}:agentsList.push(newEntry),!modelOverride&&role.model&&(modelOverride=role.model),!thinkingOverrideRaw&&role.thinking&&(thinkingOverrideRaw=role.thinking)}let childSessionKey=`agent:${targetAgentId}:subagent:${crypto.randomUUID()}`,childDepth=callerDepth+1,spawnedByKey=requesterInternalKey,targetAgentConfig=resolveAgentConfig(cfg,targetAgentId),resolvedModel=await resolveSubagentSpawnModel({cfg,agentId:targetAgentId,modelOverride,role:modelRoleForAgentRole(params.roleConfig?.name),task}),resolvedThinkingDefaultRaw=readStringParam(targetAgentConfig?.subagents??{},`thinking`)??readStringParam(cfg.agents?.defaults?.subagents??{},`thinking`),thinkingOverride,thinkingCandidateRaw=thinkingOverrideRaw||resolvedThinkingDefaultRaw;if(thinkingCandidateRaw){let normalized=normalizeThinkLevel(thinkingCandidateRaw);if(!normalized){let{provider,model}=splitModelRef(resolvedModel);return{status:`error`,error:`Invalid thinking level "${thinkingCandidateRaw}". Use one of: ${formatThinkingLevels(provider,model)}.`}}thinkingOverride=normalized}try{await callGateway({method:`sessions.patch`,params:{key:childSessionKey,spawnDepth:childDepth},timeoutMs:1e4})}catch(err){return{status:`error`,error:err instanceof Error?err.message:typeof err==`string`?err:`error`,childSessionKey}}if(resolvedModel)try{await callGateway({method:`sessions.patch`,params:{key:childSessionKey,model:resolvedModel},timeoutMs:1e4}),modelApplied=!0}catch(err){return{status:`error`,error:err instanceof Error?err.message:typeof err==`string`?err:`error`,childSessionKey}}if(thinkingOverride!==void 0)try{await callGateway({method:`sessions.patch`,params:{key:childSessionKey,thinkingLevel:thinkingOverride===`off`?null:thinkingOverride},timeoutMs:1e4})}catch(err){return{status:`error`,error:err instanceof Error?err.message:typeof err==`string`?err:`error`,childSessionKey}}let childSystemPrompt=buildSubagentSystemPrompt({requesterSessionKey,requesterOrigin,childSessionKey,label:label||void 0,task,childDepth,maxSpawnDepth});if(params.roleConfig){params.roleConfig.systemPrompt&&(childSystemPrompt+=`
385
385
 
386
386
  --- Role Guidance ---
387
387
  `+params.roleConfig.systemPrompt);let personaBlock=buildPersonaSystemBlock(params.roleConfig);personaBlock&&(childSystemPrompt+=`