@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.
- package/dist/{agent-CxhUn-aN.js → agent-Cu57zjv6.js} +1 -1
- package/dist/{agent-CiEaiH-p.js → agent-LoZ_09Jv.js} +1 -1
- package/dist/{agents-DkKFDcYq.js → agents-Dgrr6E7S.js} +1 -1
- package/dist/{agents-IZrPoZIi.js → agents-DiRof4zA.js} +1 -1
- package/dist/{audio-preflight-COZAlqnx.js → audio-preflight-Cg4vjX8I.js} +1 -1
- package/dist/{auth-choice-CrYQF7zX.js → auth-choice-BJmosINc.js} +1 -1
- package/dist/{auth-choice-DhUBmu6y.js → auth-choice-CDoW8QDy.js} +1 -1
- package/dist/{auth-choice.apply-Botyf6Sg.js → auth-choice.apply-25j_lhua.js} +1 -1
- package/dist/{auth-choice.apply-k9tk1hGj.js → auth-choice.apply-CE1TC_Ts.js} +1 -1
- package/dist/{auth-choice.apply-Cch5UXis.js → auth-choice.apply-DSHzvYNu.js} +1 -1
- package/dist/{auth-choice.apply-CXRcLO-h.js → auth-choice.apply-ND2C2oSe.js} +1 -1
- package/dist/{auth-choice.apply.transformers-BkN8HlZJ.js → auth-choice.apply.transformers-BF-qyu2L.js} +1 -1
- package/dist/{auth-choice.apply.transformers-B9SieNNk.js → auth-choice.apply.transformers-CBQbUAwr.js} +1 -1
- package/dist/{auth-choice.apply.transformers-D02W3zy7.js → auth-choice.apply.transformers-DE9QrzbX.js} +1 -1
- package/dist/{auth-choice.apply.transformers-Dnr7Izx1.js → auth-choice.apply.transformers-vr05ATPq.js} +1 -1
- package/dist/{banner-Bd45EXyp.js → banner-Bx4c92N8.js} +1 -1
- package/dist/build-info.json +3 -3
- package/dist/{builderforce-BxVfTQsc.js → builderforce-DHU87PJG.js} +1 -1
- package/dist/{builderforce-C86noipf.js → builderforce-DgYCZ3Up.js} +1 -1
- package/dist/bundled/boot-md/handler.js +1 -1
- package/dist/bundled/session-memory/handler.js +1 -1
- package/dist/{channel-options-BHetVK54.js → channel-options-BZoCW2EZ.js} +1 -1
- package/dist/{channel-options-D5PmuxT-.js → channel-options-DAkHvC-x.js} +1 -1
- package/dist/{channel-web-B5QgCj6B.js → channel-web-BWEX1FnI.js} +1 -1
- package/dist/{channels-cli-sHtDH37K.js → channels-cli-DHFIXbTT.js} +1 -1
- package/dist/{channels-cli-CgZqXqUm.js → channels-cli-DvkQEBwz.js} +1 -1
- package/dist/chrome-CbBg1ngA.js +4 -0
- package/dist/{cli-DKoe6Ywl.js → cli-C9bsC2UP.js} +1 -1
- package/dist/{cli-DlaHihmr.js → cli-DnMFuBeA.js} +1 -1
- package/dist/{command-registry-FQIQbQAx.js → command-registry-DUOpdtcT.js} +1 -1
- package/dist/{command-registry-BhyY4aXy.js → command-registry-DrRz6Wgg.js} +1 -1
- package/dist/{completion-cli-D86ydD3X.js → completion-cli-BtLeKqh_.js} +1 -1
- package/dist/{completion-cli-H4iKy2_f.js → completion-cli-Cq33pQdJ.js} +1 -1
- package/dist/{completion-cli-CoFRiwNp.js → completion-cli-EbyCUnCP.js} +1 -1
- package/dist/{completion-cli-DF6vmGRs.js → completion-cli-mzQa8oTd.js} +1 -1
- package/dist/{config-cli-D6KAk3vw.js → config-cli-BIQl_nrn.js} +1 -1
- package/dist/{config-cli-9HoPtGDR.js → config-cli-Dw1pr9MW.js} +1 -1
- package/dist/{configure-B_FvthXy.js → configure-B1HJIRSM.js} +1 -1
- package/dist/{configure-CYwCU0Hw.js → configure-BPX5i4at.js} +1 -1
- package/dist/{configure-BgZGeNXf.js → configure-CKm9_xkS.js} +1 -1
- package/dist/{configure-6QCgecON.js → configure-CQPFd8N9.js} +1 -1
- package/dist/{deps-jUQM2eq1.js → deps-DN7fhGiB.js} +1 -1
- package/dist/{doctor-completion-CZrfkBfj.js → doctor-completion-B7JXY8EJ.js} +1 -1
- package/dist/{doctor-completion-BSbAN5p1.js → doctor-completion-BEVC1EV7.js} +1 -1
- package/dist/{embedded-CA0n2tyG.js → embedded-BBM-usEa.js} +7 -7
- package/dist/{embedded-SSuKQ6Yc.js → embedded-CIuP-6Ex.js} +2 -2
- package/dist/entry.js +1 -1
- package/dist/extensionAPI.js +1 -1
- package/dist/{gateway-cli-8SuDvuCq.js → gateway-cli-CvdguqNO.js} +2 -2
- package/dist/{gateway-cli-D5pW1jLs.js → gateway-cli-DvMzpFIF.js} +2 -2
- package/dist/{health-BLW40WUJ.js → health-Bd0YvHPq.js} +1 -1
- package/dist/{health-DqZB_jd8.js → health-CcUquV5P.js} +1 -1
- package/dist/{health-Cggr6c-2.js → health-CoTbsx1p.js} +1 -1
- package/dist/{hooks-cli-BQZjt-Fk.js → hooks-cli-D1mx0_F_.js} +1 -1
- package/dist/{hooks-cli-D5Zt0sN4.js → hooks-cli-Dr0hMOiz.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/llm-slug-generator.js +1 -1
- package/dist/{models-DH9Vrv7O.js → models-D3MukbTO.js} +1 -1
- package/dist/{models-cli-DLZZwy_m.js → models-cli-CBUEjJ_T.js} +1 -1
- package/dist/{models-cli-CAaWi4TX.js → models-cli-nD2MyRO3.js} +1 -1
- package/dist/{models-bp562zNz.js → models-px2EtCBB.js} +1 -1
- package/dist/{onboard-pzmSj6MG.js → onboard-CelRLEbD.js} +1 -1
- package/dist/{onboard-CpFQ-bpz.js → onboard-D_Ja6cJL.js} +1 -1
- package/dist/{onboard-channels-BsMS0Ehd.js → onboard-channels-C5v3gxTE.js} +1 -1
- package/dist/{onboard-channels-D1FMu5M8.js → onboard-channels-CEMtoVzX.js} +1 -1
- package/dist/{onboard-channels-CKWKLbTn.js → onboard-channels-DIvxrZLb.js} +1 -1
- package/dist/{onboard-channels-CqXCWPaQ.js → onboard-channels-pPjt4AF5.js} +1 -1
- package/dist/{onboard-interactive-BAcb1Yd8.js → onboard-interactive-BIVMtUaZ.js} +1 -1
- package/dist/{onboard-interactive-COTt-hGf.js → onboard-interactive-CeQp6fAt.js} +1 -1
- package/dist/{onboard-interactive-B_YG0JwA.js → onboard-interactive-D3YgFz9n.js} +1 -1
- package/dist/{onboard-interactive-BdwTeKJ2.js → onboard-interactive-tVpsWM3V.js} +1 -1
- package/dist/{onboarding-C8IDtM8O.js → onboarding-B9P9Rocf.js} +2 -2
- package/dist/{onboarding-BhMZqtBx.js → onboarding-DXxufSuN.js} +2 -2
- package/dist/{onboarding.finalize-DpyMh92r.js → onboarding.finalize-BJbv33Sa.js} +1 -1
- package/dist/{onboarding.finalize-DEhEHZPV.js → onboarding.finalize-CiIdxWgH.js} +1 -1
- package/dist/{outbound-send-deps-CKOfRpqk.js → outbound-send-deps-DL5n0r7v.js} +1 -1
- package/dist/{plugin-registry-Bi-9AQMd.js → plugin-registry-B5gTbK3m.js} +1 -1
- package/dist/{plugin-registry-nxUQWv6l.js → plugin-registry-CBXZbshG.js} +1 -1
- package/dist/{plugin-registry-BlKyKAq2.js → plugin-registry-DEWbh_9i.js} +1 -1
- package/dist/{plugin-registry-CqGq9jzk.js → plugin-registry-Glc-xriO.js} +1 -1
- package/dist/plugin-sdk/{channel-web-C3UtHX6b.js → channel-web-CW5s6vEZ.js} +1 -1
- package/dist/plugin-sdk/index.js +1 -1
- package/dist/plugin-sdk/{reply-BTKDKB2t.js → reply-pngAtrhW.js} +2 -2
- package/dist/plugin-sdk/{web-CsPSK9U2.js → web-DfrDkFj_.js} +1 -1
- package/dist/{plugins-CUhWH9-E.js → plugins-BJNBD6Si.js} +1 -1
- package/dist/{plugins-B8Lge-oB.js → plugins-BZnMash4.js} +1 -1
- package/dist/{plugins-cli-c36MSKiX.js → plugins-cli-Cv_bwpr4.js} +1 -1
- package/dist/{plugins-cli-CgjC_YvF.js → plugins-cli-DkFN_JgK.js} +1 -1
- package/dist/{program-QMtnfrM_.js → program-DYU1raxm.js} +2 -2
- package/dist/{program-context-BgCNjcCh.js → program-context-D4S-3zNt.js} +1 -1
- package/dist/{prompt-select-styled-CWG9o2CX.js → prompt-select-styled-BhKY5Oj4.js} +1 -1
- package/dist/{prompt-select-styled-m1_NXutn.js → prompt-select-styled-D1StbM6j.js} +1 -1
- package/dist/{provider-auth-helpers-BFCTgzr_.js → provider-auth-helpers-5ZQb3SEz.js} +1 -1
- package/dist/{provider-auth-helpers-D0eiRpeb.js → provider-auth-helpers-Cibq8oDi.js} +1 -1
- package/dist/{provider-dispatcher-Djomkp5i.js → provider-dispatcher-Bwaplzm8.js} +1 -1
- package/dist/{provider-dispatcher-B6kumPDM.js → provider-dispatcher-kL8Yl9XU.js} +1 -1
- package/dist/{push-apns-DalSFp-6.js → push-apns-BXmSvfvx.js} +1 -1
- package/dist/{push-apns-DwSjHMuA.js → push-apns-C9hsLIBU.js} +1 -1
- package/dist/{pw-ai-1DyAPekE.js → pw-ai-BLyUwyRC.js} +1 -1
- package/dist/{register.agent-BZn434eF.js → register.agent-C4x77WJe.js} +1 -1
- package/dist/{register.agent-DNaHcARI.js → register.agent-CbP_v3k5.js} +1 -1
- package/dist/{register.configure-GTH7BPIx.js → register.configure-B-j2lVkz.js} +1 -1
- package/dist/{register.configure-Bflad790.js → register.configure-BsBerk8U.js} +1 -1
- package/dist/{register.maintenance-Dl7P66Jm.js → register.maintenance-B83yzc-P.js} +1 -1
- package/dist/{register.maintenance-B1XK1zeY.js → register.maintenance-WLPWJ7vr.js} +1 -1
- package/dist/{register.message-CJS3PPCy.js → register.message-BVo8xLbS.js} +1 -1
- package/dist/{register.message-CA5LiG16.js → register.message-DZ9zcORn.js} +1 -1
- package/dist/{register.onboard-Bj6wFSzC.js → register.onboard-CWCqKyU7.js} +1 -1
- package/dist/{register.onboard-4y1mzgCn.js → register.onboard-D9mB9MLj.js} +1 -1
- package/dist/{register.setup-Cvk8SB1q.js → register.setup-BMFb9IC4.js} +1 -1
- package/dist/{register.setup-zLIWO_nF.js → register.setup-C22fWTFR.js} +1 -1
- package/dist/{register.status-health-sessions-CjxA4ATI.js → register.status-health-sessions-BqMqFeMA.js} +1 -1
- package/dist/{register.status-health-sessions-CIYKmgKO.js → register.status-health-sessions-C-jqKRZ5.js} +1 -1
- package/dist/{register.subclis-Ua7PkPpv.js → register.subclis-Ceyv8kgc.js} +1 -1
- package/dist/{register.subclis-Ct4QBaKi.js → register.subclis-DxcQwaQg.js} +1 -1
- package/dist/{reply-gZ_yr2mJ.js → reply-BeKidf2F.js} +4 -4
- package/dist/{run-main-Cyc_C0B-.js → run-main-EhlBxGJB.js} +1 -1
- package/dist/{runner-C1sy_uJN.js → runner-P3IfAnSL.js} +3 -3
- package/dist/{server-node-events-CSsH-eIF.js → server-node-events-BZuSkcbo.js} +1 -1
- package/dist/{server-node-events-Bz_Qo5BV.js → server-node-events-CIsEZSfR.js} +1 -1
- package/dist/{session-dirs-fh5kvbyH.js → session-dirs-DH7k5ehu.js} +1 -1
- package/dist/{session-dirs-DVL9vHmq.js → session-dirs-DgwMogyJ.js} +1 -1
- package/dist/{status-sAc6yoa3.js → status-BY0kS_wo.js} +1 -1
- package/dist/{status-SPonEO1J.js → status-B_SXw9W4.js} +1 -1
- package/dist/{status-DZYF4S6_.js → status-BqEzSHhZ.js} +1 -1
- package/dist/{status-ChEjU5un.js → status-Ca-hgLW_.js} +1 -1
- package/dist/{status-CpxCM8BO.js → status-_KIJcQH-.js} +1 -1
- package/dist/{subagent-registry-BHP3_ka8.js → subagent-registry-98yia-RN.js} +4 -4
- package/dist/{subagent-registry-BYK0Wq_w.js → subagent-registry-Ch9dN-TR.js} +1 -1
- package/dist/{subagent-registry-DR5M5QUP.js → subagent-registry-CiYeuaym.js} +1 -1
- package/dist/{tui-Ujq2bTco.js → tui-BIpdEy5i.js} +2 -2
- package/dist/{tui-BsMw6I4Y.js → tui-DeG1am8h.js} +2 -2
- package/dist/{tui-cli-CLYxMYyC.js → tui-cli-3mxSu-O0.js} +1 -1
- package/dist/{tui-cli-BBKMdwDt.js → tui-cli-CXRFHYWv.js} +1 -1
- package/dist/{update-cli-uQLI7RCN.js → update-cli-BYhJHTZ0.js} +1 -1
- package/dist/{update-cli-BKcCNOzz.js → update-cli-DkgHl95y.js} +1 -1
- package/dist/{web-Bkk568P6.js → web--D7qJmx6.js} +1 -1
- package/dist/{web-wR7gzEVJ.js → web-CgypI7gs.js} +1 -1
- package/dist/{web-CGo9DnE4.js → web-DKmwaw7q.js} +1 -1
- package/dist/{web-DktK5vCb.js → web-Dvcfg5Kd.js} +1 -1
- package/extensions/memory-lancedb/package.json +2 -2
- package/package.json +1 -1
- package/dist/chrome-CAuboFG7.js +0 -4
|
@@ -200,7 +200,7 @@ TOOLS.md does not control tool availability; it is user guidance for how to use
|
|
|
200
200
|
`)?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]===`
|
|
201
201
|
`;)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$3(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&¤tPreviewText.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(`
|
|
202
202
|
|
|
203
|
-
`):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 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-DyyTWlTW.js`).then(n=>n.t),webOutboundPromise}function loadWebLogin(){return webLoginPromise??=import(`./login-BndqfkoL.js`).then(n=>n.n),webLoginPromise}function loadWebLoginQr(){return webLoginQrPromise??=import(`./login-qr-COCYcwsl.js`),webLoginQrPromise}function loadWebChannel(){return webChannelPromise??=import(`./web-CsPSK9U2.js`),webChannelPromise}function loadWhatsAppActions(){return whatsappActionsPromise??=import(`./whatsapp-actions-D6fn4up7.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&®istry.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&®istry.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`&®istry.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&®istry.diagnostics.push({level:`warn`,message:`memory slot plugin not found or not marked as memory: ${memorySlot}`}),cacheEnabled&®istryCache.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$9=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$9)}),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$9.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$9.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$9.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(`
|
|
203
|
+
`):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 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-DyyTWlTW.js`).then(n=>n.t),webOutboundPromise}function loadWebLogin(){return webLoginPromise??=import(`./login-BndqfkoL.js`).then(n=>n.n),webLoginPromise}function loadWebLoginQr(){return webLoginQrPromise??=import(`./login-qr-COCYcwsl.js`),webLoginQrPromise}function loadWebChannel(){return webChannelPromise??=import(`./web-DfrDkFj_.js`),webChannelPromise}function loadWhatsAppActions(){return whatsappActionsPromise??=import(`./whatsapp-actions-D6fn4up7.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&®istry.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&®istry.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`&®istry.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&®istry.diagnostics.push({level:`warn`,message:`memory slot plugin not found or not marked as memory: ${memorySlot}`}),cacheEnabled&®istryCache.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$9=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$9)}),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$9.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$9.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$9.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(`
|
|
204
204
|
`);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(`
|
|
205
205
|
`)}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(`
|
|
206
206
|
`)}`);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$1(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$1(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(`
|
|
@@ -422,7 +422,7 @@ Use jobId as the canonical identifier; id is accepted for compatibility. Use con
|
|
|
422
422
|
`)),!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`&¶ms.to.trim().length>0||typeof params.channelId==`string`&¶ms.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`&¶ms.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$3(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`&¶ms.target.trim().length>0||typeof params.to==`string`&¶ms.to.trim().length>0||typeof params.channelId==`string`&¶ms.channelId.trim().length>0||Array.isArray(params.targets)&¶ms.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)}}function parseTimeoutMs(raw){if(raw==null)return;let value=NaN;if(typeof raw==`number`)value=raw;else if(typeof raw==`bigint`)value=Number(raw);else if(typeof raw==`string`){let trimmed=raw.trim();if(!trimmed)return;value=Number.parseInt(trimmed,10)}return Number.isFinite(value)?value:void 0}function parseEnvPairs(pairs){if(!Array.isArray(pairs)||pairs.length===0)return;let env={};for(let pair of pairs){if(typeof pair!=`string`)continue;let idx=pair.indexOf(`=`);if(idx<=0)continue;let key=pair.slice(0,idx).trim();key&&(env[key]=pair.slice(idx+1))}return Object.keys(env).length>0?env:void 0}function parseScreenRecordPayload(value){let obj=asRecord$1(value),format=asString(obj.format),base64=asString(obj.base64);if(!format||!base64)throw Error(`invalid screen.record payload`);return{format,base64,durationMs:typeof obj.durationMs==`number`?obj.durationMs:void 0,fps:typeof obj.fps==`number`?obj.fps:void 0,screenIndex:typeof obj.screenIndex==`number`?obj.screenIndex:void 0,hasAudio:typeof obj.hasAudio==`boolean`?obj.hasAudio:void 0}}function screenRecordTempPath(opts){let{tmpDir,id,ext}=resolveTempPathParts(opts);return path$1.join(tmpDir,`builderforce-screen-record-${id}${ext}`)}async function writeScreenRecordToFile(filePath,base64){return writeBase64ToFile(filePath,base64)}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`&¶ms.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`&¶ms.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`&¶ms.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`&¶ms.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`&¶ms.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)}}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 canonicalizeSessionKeyForAgent(agentId,key){let lowered=key.toLowerCase();return lowered===`global`||lowered===`unknown`||lowered.startsWith(`agent:`)?lowered:`agent:${normalizeAgentId(agentId)}:${lowered}`}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 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}}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(`
|
|
423
423
|
`)}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(`
|
|
424
424
|
`)}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(`
|
|
425
|
-
`)}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$7=createSubsystemLogger(`agents/sessions-send`);async function runSessionsSendA2AFlow(params){let runContextId=params.waitRunId??`unknown`;try{let primaryReply=params.roundOneReply,latestReply=params.roundOneReply;if(!primaryReply&¶ms.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&¶ms.requesterSessionKey&¶ms.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$7.warn(`sessions_send announce delivery failed`,{runId:runContextId,channel:announceTarget.channel,to:announceTarget.to,error:formatErrorMessage(err)})}}catch(err){log$7.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:64})),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})}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+=`
|
|
425
|
+
`)}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$7=createSubsystemLogger(`agents/sessions-send`);async function runSessionsSendA2AFlow(params){let runContextId=params.waitRunId??`unknown`;try{let primaryReply=params.roundOneReply,latestReply=params.roundOneReply;if(!primaryReply&¶ms.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&¶ms.requesterSessionKey&¶ms.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$7.warn(`sessions_send announce delivery failed`,{runId:runContextId,channel:announceTarget.channel,to:announceTarget.to,error:formatErrorMessage(err)})}}catch(err){log$7.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:64})),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})}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+=`
|
|
426
426
|
|
|
427
427
|
--- Role Guidance ---
|
|
428
428
|
`+params.roleConfig.systemPrompt);let personaBlock=buildPersonaSystemBlock(params.roleConfig);personaBlock&&(childSystemPrompt+=`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./session-key-5J69DULS.js";import{a as WA_WEB_AUTH_DIR,g as webAuthExists,s as logWebSelfId,u as pickWebChannel}from"./accounts-Cy3WCbWg.js";import"./reply-
|
|
1
|
+
import"./session-key-5J69DULS.js";import{a as WA_WEB_AUTH_DIR,g as webAuthExists,s as logWebSelfId,u as pickWebChannel}from"./accounts-Cy3WCbWg.js";import"./reply-pngAtrhW.js";import"./registry-CZHRcH-q.js";import"./paths-Cb8zTlyG.js";import"./model-selection-CZTzMko9.js";import"./config-83FqPOpG.js";import"./fetch-B-GxSYRO.js";import"./subsystem-D0Ril4rt.js";import"./agent-scope-DgKN27hJ.js";import"./tool-images-WRTP95FT.js";import"./common-n0l_XN-S.js";import"./replies-CwuTDT2n.js";import"./reply-prefix-w7kAvH11.js";import"./runner-DTZjhAWQ.js";import"./redact-Bv8wnIZm.js";import"./errors-L3rugjUL.js";import"./chrome-VjYB3Ggh.js";import"./command-format-B3XMq_73.js";import"./plugins-BdkC9v5E.js";import"./bindings-CH-YLOLC.js";import"./message-channel-CuZ2xOAM.js";import"./src-BcDibXPq.js";import"./paths-DtbnCdO7.js";import"./api-key-rotation-kniXHBq0.js";import"./active-listener-DVWVNlT9.js";import"./render-CuA_WRX5.js";import"./chunk-C94IAOuf.js";import"./manager-LU1VIiKP.js";import"./markdown-tables-BUfhHgfs.js";import{n as monitorWebInbox,t as monitorWebChannel}from"./channel-web-CW5s6vEZ.js";import"./model-catalog-DGFbGHmf.js";import"./sqlite-JjFgDV-H.js";import"./resolve-route-0sbvl4ZN.js";import{n as sendMessageWhatsApp}from"./outbound-DyyTWlTW.js";import{i as waitForWaConnection,t as createWaSocket}from"./session-BYkspIs0.js";import{t as loginWeb}from"./login-BndqfkoL.js";export{WA_WEB_AUTH_DIR,createWaSocket,logWebSelfId,loginWeb,monitorWebChannel,monitorWebInbox,pickWebChannel,sendMessageWhatsApp,waitForWaConnection,webAuthExists};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./paths-BHg-VHB4.js";import"./registry-Cv7CoWAs.js";import"./utils-BP60e80M.js";import"./subsystem-C4b1Von0.js";import"./boolean-ssGoaBPk.js";import"./env-BoE8QSib.js";import"./logger-AbH8mdkv.js";import"./session-key-D--2AEus.js";import"./builderforce-root-D3-p8W2n.js";import"./exec-CGuYALEs.js";import"./agent-scope-BcoQBOwz.js";import"./subagent-registry-
|
|
1
|
+
import"./paths-BHg-VHB4.js";import"./registry-Cv7CoWAs.js";import"./utils-BP60e80M.js";import"./subsystem-C4b1Von0.js";import"./boolean-ssGoaBPk.js";import"./env-BoE8QSib.js";import"./logger-AbH8mdkv.js";import"./session-key-D--2AEus.js";import"./builderforce-root-D3-p8W2n.js";import"./exec-CGuYALEs.js";import"./agent-scope-BcoQBOwz.js";import"./subagent-registry-98yia-RN.js";import{n as listChannelPlugins}from"./plugins-DJGW_fnS.js";import"./accounts-Z5bJpNrG.js";import"./bindings-D0uket3l.js";import"./send-DfpZ9T_M.js";export{listChannelPlugins};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./paths-5FcIFMsj.js";import"./utils-DbaBVFaK.js";import"./reply-
|
|
1
|
+
import"./paths-5FcIFMsj.js";import"./utils-DbaBVFaK.js";import"./reply-BeKidf2F.js";import"./session-key-EoB0qaG9.js";import"./builderforce-root-D64_sXEi.js";import"./subsystem-B3TqcCrZ.js";import"./registry-TdK-aV05.js";import"./logger-Bch0bx9c.js";import"./exec-DdcIjeyn.js";import"./agent-scope-DPtjOxzp.js";import"./boolean-Cn4K2fc9.js";import"./env-BHP32i7Q.js";import{n as listChannelPlugins}from"./plugins-C0lu7LGS.js";import"./accounts-2InvZDx2.js";import"./bindings-qYFdqpJ3.js";import"./send-BGZYkspG.js";export{listChannelPlugins};
|