agentix-cli 0.143.0 → 0.144.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/dist/{App-UTDCBFZI.js → App-N2U77ED7.js} +2 -2
  2. package/dist/{ChatApp-7P22XAL2.js → ChatApp-GYVTECF6.js} +2 -2
  3. package/dist/{absorb-eval-EGO6JJOV.js → absorb-eval-WSAVWCZV.js} +2 -2
  4. package/dist/{agent-AI6LNZV2.js → agent-SLRGXBMK.js} +2 -2
  5. package/dist/{board-dashboard-ZKN5Y3GJ.js → board-dashboard-B3T7VCRQ.js} +4 -4
  6. package/dist/{chunk-SDSSRNSU.js → chunk-2GJFLPS7.js} +3 -3
  7. package/dist/{chunk-NYWIN4BW.js → chunk-3LAQ74H7.js} +2 -2
  8. package/dist/{chunk-THWDSPX4.js → chunk-45TKVOJX.js} +2 -2
  9. package/dist/{chunk-RB5W3FVO.js → chunk-4JHMV3D3.js} +2 -2
  10. package/dist/{chunk-QSKG754X.js → chunk-5TTHN7DP.js} +12 -8
  11. package/dist/chunk-5TTHN7DP.js.map +1 -0
  12. package/dist/{chunk-PYI7ZAU3.js → chunk-BAO77R4L.js} +2 -2
  13. package/dist/{chunk-YYPTXXCJ.js → chunk-CZWEXRIE.js} +2 -2
  14. package/dist/{chunk-OMO7UTWW.js → chunk-DFWPTNZ5.js} +2 -2
  15. package/dist/chunk-DG2DC43E.js +11 -0
  16. package/dist/chunk-DG2DC43E.js.map +1 -0
  17. package/dist/chunk-DPIQCHXB.js +62 -0
  18. package/dist/chunk-DPIQCHXB.js.map +1 -0
  19. package/dist/{chunk-3WBOWXAN.js → chunk-EX4AREN5.js} +2 -2
  20. package/dist/{chunk-MFUN3ZS3.js → chunk-GOAMSJ2D.js} +2 -2
  21. package/dist/{chunk-YVNGPYXN.js → chunk-GWBBWYGM.js} +58 -55
  22. package/dist/chunk-GWBBWYGM.js.map +1 -0
  23. package/dist/{chunk-WY5ZOEOE.js → chunk-JGX5IWNX.js} +2 -2
  24. package/dist/chunk-KV4ZA7FS.js +4 -0
  25. package/dist/chunk-KV4ZA7FS.js.map +1 -0
  26. package/dist/{chunk-YXFTUOZR.js → chunk-LLJZMS23.js} +2 -2
  27. package/dist/{chunk-L4RCA3OC.js → chunk-LVQHNTXV.js} +2 -2
  28. package/dist/{chunk-UNIXYV3U.js → chunk-M7527M7D.js} +2 -2
  29. package/dist/{chunk-IABJLTZN.js → chunk-MXWAREAQ.js} +2 -2
  30. package/dist/{chunk-GB4YT5IG.js → chunk-PJGLIAEP.js} +247 -240
  31. package/dist/chunk-PJGLIAEP.js.map +1 -0
  32. package/dist/{chunk-ERG5OUKH.js → chunk-Q73QQPDB.js} +2 -2
  33. package/dist/{chunk-O2CYERSX.js → chunk-QI4FYJGJ.js} +2 -2
  34. package/dist/{chunk-HPQ3AAG3.js → chunk-R5VGRKUW.js} +2 -2
  35. package/dist/{chunk-N2HLL25P.js → chunk-RGBQULXX.js} +2 -2
  36. package/dist/{chunk-6CTQPGBR.js → chunk-RV4WJZW5.js} +2 -2
  37. package/dist/{chunk-QVPBSV5Z.js → chunk-SFUNL7RV.js} +2 -2
  38. package/dist/{chunk-7H6HDN3K.js → chunk-SVNYI6GR.js} +2 -2
  39. package/dist/{chunk-DKLVB5L6.js → chunk-TTBCXVPJ.js} +6 -6
  40. package/dist/chunk-TTBCXVPJ.js.map +1 -0
  41. package/dist/{chunk-XWHD2Z3Z.js → chunk-UII54DAP.js} +2 -2
  42. package/dist/{chunk-5BXAKMYK.js → chunk-UNZRZOED.js} +2 -2
  43. package/dist/{chunk-Y4CYQV7G.js → chunk-VY7TBMJU.js} +2 -2
  44. package/dist/chunk-VY7TBMJU.js.map +1 -0
  45. package/dist/{chunk-AJUWIBLV.js → chunk-VYLMC5DO.js} +2 -2
  46. package/dist/{chunk-SHEUCITK.js → chunk-WBG6NA7R.js} +2 -2
  47. package/dist/{chunk-SHEUCITK.js.map → chunk-WBG6NA7R.js.map} +1 -1
  48. package/dist/cli.js +1 -1
  49. package/dist/{client-E66ELJK7.js → client-B7FXDTYK.js} +2 -2
  50. package/dist/config-MLP33NWR.js +2 -0
  51. package/dist/{config-mutate-QBDKJNHA.js → config-mutate-XQRUAVEH.js} +2 -2
  52. package/dist/config-mutator-5JFTMQ43.js +2 -0
  53. package/dist/{contributions-L5XZJ3DP.js → contributions-ESUSYUQG.js} +2 -2
  54. package/dist/{doctor-3ZUFSE6R.js → doctor-DIYZGSIS.js} +2 -2
  55. package/dist/{failure-candidates-XZSZP4HT.js → failure-candidates-NQX2JMMS.js} +2 -2
  56. package/dist/{follow-up-tool-6OCQUSC3.js → follow-up-tool-QXEYEWX7.js} +2 -2
  57. package/dist/{grants-CEUGZBQ4.js → grants-MM7U6GCK.js} +2 -2
  58. package/dist/{hub-MOQRSVCQ.js → hub-OC7PH2AR.js} +2 -2
  59. package/dist/index.d.ts +213 -76
  60. package/dist/index.js +1 -1
  61. package/dist/{program-AR6F763U.js → program-LZPM6I2Q.js} +289 -254
  62. package/dist/program-LZPM6I2Q.js.map +1 -0
  63. package/dist/{promote-ZGJEPCBE.js → promote-SIC6RWCX.js} +2 -2
  64. package/dist/{query-JLTHESIZ.js → query-OP2MSR2G.js} +2 -2
  65. package/dist/{query-settings-GMEL3EKR.js → query-settings-67332F5V.js} +2 -2
  66. package/dist/{registry-MFD3XJBR.js → registry-G2ZG5TIN.js} +2 -2
  67. package/dist/{request-planner-4ORFYSAT.js → request-planner-THTPE3FP.js} +2 -2
  68. package/dist/{review-candidates-77NDFTGM.js → review-candidates-7PS7CHXF.js} +2 -2
  69. package/dist/{routing-3FL3KYPJ.js → routing-PE7DB7WA.js} +2 -2
  70. package/dist/schedule-tool-3FXRKJGN.js +2 -0
  71. package/dist/{scheduler-QLL7ZHYW.js → scheduler-YTXCIQTZ.js} +2 -2
  72. package/dist/{seat-RBKONP63.js → seat-6DMK4274.js} +2 -2
  73. package/dist/{select-MOUDR6PQ.js → select-CLDYPAOS.js} +2 -2
  74. package/dist/{set-enabled-JKYF3QIA.js → set-enabled-ZH2DH4GU.js} +2 -2
  75. package/dist/tool-4AO3ZMAY.js +6 -0
  76. package/dist/tool-4AO3ZMAY.js.map +1 -0
  77. package/dist/{tool-Y3ZTSZGE.js → tool-MKDTKBJ4.js} +3 -3
  78. package/dist/{tool-Y3ZTSZGE.js.map → tool-MKDTKBJ4.js.map} +1 -1
  79. package/dist/traces-GVEQZX24.js +2 -0
  80. package/dist/{wiki-3FSSLQAE.js → wiki-CH2HYJVI.js} +2 -2
  81. package/dist/wiki-enrich-VEAYFVR2.js +2 -0
  82. package/dist/wiki-enrich-VEAYFVR2.js.map +1 -0
  83. package/dist/workflow-pilot-HCPSMGIC.js +2 -0
  84. package/dist/workflow-pilot-HCPSMGIC.js.map +1 -0
  85. package/package.json +1 -1
  86. package/dist/chunk-3W2BHUGM.js +0 -11
  87. package/dist/chunk-3W2BHUGM.js.map +0 -1
  88. package/dist/chunk-AKWBDCMU.js +0 -4
  89. package/dist/chunk-AKWBDCMU.js.map +0 -1
  90. package/dist/chunk-DKLVB5L6.js.map +0 -1
  91. package/dist/chunk-GB4YT5IG.js.map +0 -1
  92. package/dist/chunk-K22XMF6M.js +0 -62
  93. package/dist/chunk-K22XMF6M.js.map +0 -1
  94. package/dist/chunk-QSKG754X.js.map +0 -1
  95. package/dist/chunk-Y4CYQV7G.js.map +0 -1
  96. package/dist/chunk-YVNGPYXN.js.map +0 -1
  97. package/dist/config-3C3Z7VKG.js +0 -2
  98. package/dist/config-mutator-ZI3SQIUN.js +0 -2
  99. package/dist/program-AR6F763U.js.map +0 -1
  100. package/dist/schedule-tool-5KJMXBRZ.js +0 -2
  101. package/dist/tool-C4JNMTEF.js +0 -6
  102. package/dist/tool-C4JNMTEF.js.map +0 -1
  103. package/dist/wiki-enrich-HQWXZRID.js +0 -2
  104. /package/dist/{App-UTDCBFZI.js.map → App-N2U77ED7.js.map} +0 -0
  105. /package/dist/{ChatApp-7P22XAL2.js.map → ChatApp-GYVTECF6.js.map} +0 -0
  106. /package/dist/{absorb-eval-EGO6JJOV.js.map → absorb-eval-WSAVWCZV.js.map} +0 -0
  107. /package/dist/{agent-AI6LNZV2.js.map → agent-SLRGXBMK.js.map} +0 -0
  108. /package/dist/{board-dashboard-ZKN5Y3GJ.js.map → board-dashboard-B3T7VCRQ.js.map} +0 -0
  109. /package/dist/{chunk-SDSSRNSU.js.map → chunk-2GJFLPS7.js.map} +0 -0
  110. /package/dist/{chunk-NYWIN4BW.js.map → chunk-3LAQ74H7.js.map} +0 -0
  111. /package/dist/{chunk-THWDSPX4.js.map → chunk-45TKVOJX.js.map} +0 -0
  112. /package/dist/{chunk-RB5W3FVO.js.map → chunk-4JHMV3D3.js.map} +0 -0
  113. /package/dist/{chunk-PYI7ZAU3.js.map → chunk-BAO77R4L.js.map} +0 -0
  114. /package/dist/{chunk-YYPTXXCJ.js.map → chunk-CZWEXRIE.js.map} +0 -0
  115. /package/dist/{chunk-OMO7UTWW.js.map → chunk-DFWPTNZ5.js.map} +0 -0
  116. /package/dist/{chunk-3WBOWXAN.js.map → chunk-EX4AREN5.js.map} +0 -0
  117. /package/dist/{chunk-MFUN3ZS3.js.map → chunk-GOAMSJ2D.js.map} +0 -0
  118. /package/dist/{chunk-WY5ZOEOE.js.map → chunk-JGX5IWNX.js.map} +0 -0
  119. /package/dist/{chunk-YXFTUOZR.js.map → chunk-LLJZMS23.js.map} +0 -0
  120. /package/dist/{chunk-L4RCA3OC.js.map → chunk-LVQHNTXV.js.map} +0 -0
  121. /package/dist/{chunk-UNIXYV3U.js.map → chunk-M7527M7D.js.map} +0 -0
  122. /package/dist/{chunk-IABJLTZN.js.map → chunk-MXWAREAQ.js.map} +0 -0
  123. /package/dist/{chunk-ERG5OUKH.js.map → chunk-Q73QQPDB.js.map} +0 -0
  124. /package/dist/{chunk-O2CYERSX.js.map → chunk-QI4FYJGJ.js.map} +0 -0
  125. /package/dist/{chunk-HPQ3AAG3.js.map → chunk-R5VGRKUW.js.map} +0 -0
  126. /package/dist/{chunk-N2HLL25P.js.map → chunk-RGBQULXX.js.map} +0 -0
  127. /package/dist/{chunk-6CTQPGBR.js.map → chunk-RV4WJZW5.js.map} +0 -0
  128. /package/dist/{chunk-QVPBSV5Z.js.map → chunk-SFUNL7RV.js.map} +0 -0
  129. /package/dist/{chunk-7H6HDN3K.js.map → chunk-SVNYI6GR.js.map} +0 -0
  130. /package/dist/{chunk-XWHD2Z3Z.js.map → chunk-UII54DAP.js.map} +0 -0
  131. /package/dist/{chunk-5BXAKMYK.js.map → chunk-UNZRZOED.js.map} +0 -0
  132. /package/dist/{chunk-AJUWIBLV.js.map → chunk-VYLMC5DO.js.map} +0 -0
  133. /package/dist/{client-E66ELJK7.js.map → client-B7FXDTYK.js.map} +0 -0
  134. /package/dist/{config-3C3Z7VKG.js.map → config-MLP33NWR.js.map} +0 -0
  135. /package/dist/{config-mutate-QBDKJNHA.js.map → config-mutate-XQRUAVEH.js.map} +0 -0
  136. /package/dist/{config-mutator-ZI3SQIUN.js.map → config-mutator-5JFTMQ43.js.map} +0 -0
  137. /package/dist/{contributions-L5XZJ3DP.js.map → contributions-ESUSYUQG.js.map} +0 -0
  138. /package/dist/{doctor-3ZUFSE6R.js.map → doctor-DIYZGSIS.js.map} +0 -0
  139. /package/dist/{failure-candidates-XZSZP4HT.js.map → failure-candidates-NQX2JMMS.js.map} +0 -0
  140. /package/dist/{follow-up-tool-6OCQUSC3.js.map → follow-up-tool-QXEYEWX7.js.map} +0 -0
  141. /package/dist/{grants-CEUGZBQ4.js.map → grants-MM7U6GCK.js.map} +0 -0
  142. /package/dist/{hub-MOQRSVCQ.js.map → hub-OC7PH2AR.js.map} +0 -0
  143. /package/dist/{promote-ZGJEPCBE.js.map → promote-SIC6RWCX.js.map} +0 -0
  144. /package/dist/{query-JLTHESIZ.js.map → query-OP2MSR2G.js.map} +0 -0
  145. /package/dist/{query-settings-GMEL3EKR.js.map → query-settings-67332F5V.js.map} +0 -0
  146. /package/dist/{registry-MFD3XJBR.js.map → registry-G2ZG5TIN.js.map} +0 -0
  147. /package/dist/{request-planner-4ORFYSAT.js.map → request-planner-THTPE3FP.js.map} +0 -0
  148. /package/dist/{review-candidates-77NDFTGM.js.map → review-candidates-7PS7CHXF.js.map} +0 -0
  149. /package/dist/{routing-3FL3KYPJ.js.map → routing-PE7DB7WA.js.map} +0 -0
  150. /package/dist/{schedule-tool-5KJMXBRZ.js.map → schedule-tool-3FXRKJGN.js.map} +0 -0
  151. /package/dist/{scheduler-QLL7ZHYW.js.map → scheduler-YTXCIQTZ.js.map} +0 -0
  152. /package/dist/{seat-RBKONP63.js.map → seat-6DMK4274.js.map} +0 -0
  153. /package/dist/{select-MOUDR6PQ.js.map → select-CLDYPAOS.js.map} +0 -0
  154. /package/dist/{set-enabled-JKYF3QIA.js.map → set-enabled-ZH2DH4GU.js.map} +0 -0
  155. /package/dist/{wiki-3FSSLQAE.js.map → traces-GVEQZX24.js.map} +0 -0
  156. /package/dist/{wiki-enrich-HQWXZRID.js.map → wiki-CH2HYJVI.js.map} +0 -0
@@ -1,2 +1,2 @@
1
- import{b as a,c as b,d as c,e as d,f as e,g as f,h as g,i as h,j as i,k as j,l as k,m as l,n as m,o as n,p as o,q as p,r as q,s as r,t as s,u as t}from"./chunk-N2HLL25P.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-MEFPXHQJ.js";import"./chunk-6CTQPGBR.js";import"./chunk-OWNQ2FD4.js";import"./chunk-KEXBEUSU.js";import"./chunk-ROLSSYXE.js";import"./chunk-XWHD2Z3Z.js";import"./chunk-WPNRDEHW.js";import"./chunk-HPQ3AAG3.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{b as DEFAULT_PROMOTE_TYPES,a as PROMOTER_OWNER,c as PROMOTION_LEDGER_FILE,j as appendPromotionLedger,s as approveProposal,n as callPromotionLlm,p as estimateTokens,r as evidenceFor,m as getUnpromotedMemories,k as groupCandidates,h as listAllAgentMemories,d as memoryKey,e as memoryStamp,g as mergeSources,f as parseMemoryStamp,l as parsePromotionResponse,i as readPromotionLedger,t as rejectProposal,o as runPromotion,q as sourceKind};
2
- //# sourceMappingURL=promote-ZGJEPCBE.js.map
1
+ import{b as a,c as b,d as c,e as d,f as e,g as f,h as g,i as h,j as i,k as j,l as k,m as l,n as m,o as n,p as o,q as p,r as q,s as r,t as s,u as t}from"./chunk-RGBQULXX.js";import"./chunk-AQASR6KR.js";import"./chunk-2AXFYDWF.js";import"./chunk-MEFPXHQJ.js";import"./chunk-RV4WJZW5.js";import"./chunk-OWNQ2FD4.js";import"./chunk-KEXBEUSU.js";import"./chunk-ROLSSYXE.js";import"./chunk-UII54DAP.js";import"./chunk-WPNRDEHW.js";import"./chunk-R5VGRKUW.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{b as DEFAULT_PROMOTE_TYPES,a as PROMOTER_OWNER,c as PROMOTION_LEDGER_FILE,j as appendPromotionLedger,s as approveProposal,n as callPromotionLlm,p as estimateTokens,r as evidenceFor,m as getUnpromotedMemories,k as groupCandidates,h as listAllAgentMemories,d as memoryKey,e as memoryStamp,g as mergeSources,f as parseMemoryStamp,l as parsePromotionResponse,i as readPromotionLedger,t as rejectProposal,o as runPromotion,q as sourceKind};
2
+ //# sourceMappingURL=promote-SIC6RWCX.js.map
@@ -1,2 +1,2 @@
1
- import{a,b,c,d,e,f,g,h,i,j}from"./chunk-SDSSRNSU.js";import"./chunk-SKSYII3K.js";import"./chunk-XWHD2Z3Z.js";import"./chunk-WPNRDEHW.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-HPQ3AAG3.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-6TURWSMN.js";import"./chunk-QD6IICK7.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{c as AUTO_SUMMARY_COVERAGE,a as CATALOG_SELECTOR_MODEL,b as CATALOG_SYNTH_MODEL,h as DEFAULT_GRAPH_WEIGHT,g as SHARED_CATALOG_LINES,d as agenticQuery,f as catalogPool,i as rankCatalogPool,e as retrieveArticles,j as sharedQueryEnabled};
2
- //# sourceMappingURL=query-JLTHESIZ.js.map
1
+ import{a,b,c,d,e,f,g,h,i,j}from"./chunk-2GJFLPS7.js";import"./chunk-SKSYII3K.js";import"./chunk-UII54DAP.js";import"./chunk-WPNRDEHW.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-R5VGRKUW.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-6TURWSMN.js";import"./chunk-QD6IICK7.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{c as AUTO_SUMMARY_COVERAGE,a as CATALOG_SELECTOR_MODEL,b as CATALOG_SYNTH_MODEL,h as DEFAULT_GRAPH_WEIGHT,g as SHARED_CATALOG_LINES,d as agenticQuery,f as catalogPool,i as rankCatalogPool,e as retrieveArticles,j as sharedQueryEnabled};
2
+ //# sourceMappingURL=query-OP2MSR2G.js.map
@@ -1,3 +1,3 @@
1
1
  import{b as u}from"./chunk-MEFPXHQJ.js";import{c as a}from"./chunk-SKSYII3K.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-6TURWSMN.js";import"./chunk-QD6IICK7.js";import"./chunk-QIJLFPWE.js";import{readFileSync as f}from"fs";import{resolve as d}from"path";var g={shared:!0,method:"auto",summaries:a,notes:{enabled:!1,types:["project","reference"],dirs:{}}};function y(n,t,e=process.cwd()){if(!n.notes.enabled||!t)return;let r=n.notes.dirs[t];return{owner:t,dir:r?d(e,r):new u({baseDir:d(e,".agentx")}).dirOf(t),types:n.notes.types}}function E(n,t,e=process.env,r=process.cwd()){let i=e.AGENTX_AGENT_ID;if(!(!i||i!==t))return y(n,t,r)}function p(n){if(n)try{return f(n,"utf-8").trim().split(`
2
- `)[0].trim()||void 0}catch{return}}function c(n,t){try{let e=new URL(n);return e.protocol==="https:"&&e.origin===new URL(t).origin}catch{return!1}}var l=n=>n.map(t=>typeof t=="string"?{repo:t}:{repo:t.repo,about:t.about});function h(n,t=process.env){let e=[];for(let r of n.wiki.query.live.sources){if(r.type==="agentx"){let o=n.node.bind.replace(/^0\.0\.0\.0:/,"127.0.0.1:");e.push({type:"agentx",url:r.url??`http://${o}`,peers:r.peers});continue}let i=(r.tokenEnv?t[r.tokenEnv]:void 0)||p(r.tokenFile);if(r.type==="github"){let o=n.channels.github,s=c(r.apiUrl,"https://api.github.com")?o?.token||p(o?.tokenFile):void 0;e.push({type:"github",apiUrl:r.apiUrl,token:i||s||void 0,repos:l(r.repos)})}else{let o=n.channels.gitlab,s=r.url??o?.host;if(!s)continue;let m=o?.host&&(!r.url||c(s,o.host))?o.token:void 0;e.push({type:"gitlab",url:s,token:i||m||void 0,repos:l(r.repos)})}}return e}function v(n,t=process.env){let e=n.wiki.query;return{shared:e.shared,method:e.method,summaries:{candidates:e.candidates,sharedCandidates:e.sharedCandidates,noteCandidates:e.notes.candidates,maxPages:e.maxPages,pageChars:e.pageChars,linkedPages:e.linkedPages,linkedChars:e.linkedChars,navigatorModel:e.navigatorModel,answerModel:e.answerModel,live:{enabled:e.live.enabled,maxReads:e.live.maxReads,timeoutMs:e.live.timeoutMs,plannerModel:e.live.plannerModel,sources:h(n,t)}},notes:{enabled:e.notes.enabled,types:e.notes.types,dirs:Object.fromEntries(Object.entries(n.agents).flatMap(([r,i])=>i.wiki?.notes?.dir?[[r,i.wiki.notes.dir]]:[]))}}}async function M(n){try{let{loadDaemonConfig:t}=await import("./config-3C3Z7VKG.js");return v(t(n))}catch{return g}}export{g as DEFAULT_QUERY_SETTINGS,M as loadQuerySettings,c as mayLendToken,y as noteSourceFor,h as resolveLiveSources,v as resolveQuerySettings,E as toolNoteSourceFor};
3
- //# sourceMappingURL=query-settings-GMEL3EKR.js.map
2
+ `)[0].trim()||void 0}catch{return}}function c(n,t){try{let e=new URL(n);return e.protocol==="https:"&&e.origin===new URL(t).origin}catch{return!1}}var l=n=>n.map(t=>typeof t=="string"?{repo:t}:{repo:t.repo,about:t.about});function h(n,t=process.env){let e=[];for(let r of n.wiki.query.live.sources){if(r.type==="agentx"){let o=n.node.bind.replace(/^0\.0\.0\.0:/,"127.0.0.1:");e.push({type:"agentx",url:r.url??`http://${o}`,peers:r.peers});continue}let i=(r.tokenEnv?t[r.tokenEnv]:void 0)||p(r.tokenFile);if(r.type==="github"){let o=n.channels.github,s=c(r.apiUrl,"https://api.github.com")?o?.token||p(o?.tokenFile):void 0;e.push({type:"github",apiUrl:r.apiUrl,token:i||s||void 0,repos:l(r.repos)})}else{let o=n.channels.gitlab,s=r.url??o?.host;if(!s)continue;let m=o?.host&&(!r.url||c(s,o.host))?o.token:void 0;e.push({type:"gitlab",url:s,token:i||m||void 0,repos:l(r.repos)})}}return e}function v(n,t=process.env){let e=n.wiki.query;return{shared:e.shared,method:e.method,summaries:{candidates:e.candidates,sharedCandidates:e.sharedCandidates,noteCandidates:e.notes.candidates,maxPages:e.maxPages,pageChars:e.pageChars,linkedPages:e.linkedPages,linkedChars:e.linkedChars,navigatorModel:e.navigatorModel,answerModel:e.answerModel,live:{enabled:e.live.enabled,maxReads:e.live.maxReads,timeoutMs:e.live.timeoutMs,plannerModel:e.live.plannerModel,sources:h(n,t)}},notes:{enabled:e.notes.enabled,types:e.notes.types,dirs:Object.fromEntries(Object.entries(n.agents).flatMap(([r,i])=>i.wiki?.notes?.dir?[[r,i.wiki.notes.dir]]:[]))}}}async function M(n){try{let{loadDaemonConfig:t}=await import("./config-MLP33NWR.js");return v(t(n))}catch{return g}}export{g as DEFAULT_QUERY_SETTINGS,M as loadQuerySettings,c as mayLendToken,y as noteSourceFor,h as resolveLiveSources,v as resolveQuerySettings,E as toolNoteSourceFor};
3
+ //# sourceMappingURL=query-settings-67332F5V.js.map
@@ -1,2 +1,2 @@
1
- import{ba as a,ca as b,da as c,ea as d,fa as e,ga as f,ha as g,ia as h,ja as i,ka as j,la as k,ma as l,na as m,oa as n}from"./chunk-DKLVB5L6.js";import"./chunk-THWDSPX4.js";import"./chunk-QSKG754X.js";import"./chunk-MEFPXHQJ.js";import"./chunk-SZDACK6O.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-NYWIN4BW.js";import"./chunk-QVPBSV5Z.js";import"./chunk-3UOTLMXD.js";import"./chunk-36AXN6ZB.js";import"./chunk-PE5V2LI7.js";import"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-X5C5W3E4.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-VWTBHLMX.js";import"./chunk-ERG5OUKH.js";import"./chunk-6CTQPGBR.js";import"./chunk-OWNQ2FD4.js";import"./chunk-KEXBEUSU.js";import"./chunk-ROLSSYXE.js";import"./chunk-SDSSRNSU.js";import"./chunk-SKSYII3K.js";import"./chunk-XWHD2Z3Z.js";import"./chunk-WPNRDEHW.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-RB5W3FVO.js";import"./chunk-HPQ3AAG3.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-MYVHVJWZ.js";import"./chunk-6TURWSMN.js";import"./chunk-AV7T3SYT.js";import"./chunk-Y5MFVVTM.js";import"./chunk-QD6IICK7.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DSYKYZMT.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{m as AgentRegistry,a as EDIT_TOOL_INSTRUCTION,h as TRACE_STEP_SUMMARY_BYTES,e as buildEntryMeta,f as buildEventDigest,g as buildWikiContext,i as clipForTrace,b as codingInstructions,l as emitTraceStepsFromStreamEvent,k as firstMissingRequiredTool,d as getGlobalRegistry,n as richReplyPrompt,c as setGlobalRegistry,j as tallyToolUses};
2
- //# sourceMappingURL=registry-MFD3XJBR.js.map
1
+ import{ba as a,ca as b,da as c,ea as d,fa as e,ga as f,ha as g,ia as h,ja as i,ka as j,la as k,ma as l,na as m,oa as n}from"./chunk-TTBCXVPJ.js";import"./chunk-45TKVOJX.js";import"./chunk-MEFPXHQJ.js";import"./chunk-SZDACK6O.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-5TTHN7DP.js";import"./chunk-3LAQ74H7.js";import"./chunk-SFUNL7RV.js";import"./chunk-3UOTLMXD.js";import"./chunk-36AXN6ZB.js";import"./chunk-PE5V2LI7.js";import"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-X5C5W3E4.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-VWTBHLMX.js";import"./chunk-Q73QQPDB.js";import"./chunk-RV4WJZW5.js";import"./chunk-OWNQ2FD4.js";import"./chunk-KEXBEUSU.js";import"./chunk-ROLSSYXE.js";import"./chunk-2GJFLPS7.js";import"./chunk-SKSYII3K.js";import"./chunk-UII54DAP.js";import"./chunk-WPNRDEHW.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-4JHMV3D3.js";import"./chunk-R5VGRKUW.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-MYVHVJWZ.js";import"./chunk-6TURWSMN.js";import"./chunk-AV7T3SYT.js";import"./chunk-Y5MFVVTM.js";import"./chunk-QD6IICK7.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DSYKYZMT.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{m as AgentRegistry,a as EDIT_TOOL_INSTRUCTION,h as TRACE_STEP_SUMMARY_BYTES,e as buildEntryMeta,f as buildEventDigest,g as buildWikiContext,i as clipForTrace,b as codingInstructions,l as emitTraceStepsFromStreamEvent,k as firstMissingRequiredTool,d as getGlobalRegistry,n as richReplyPrompt,c as setGlobalRegistry,j as tallyToolUses};
2
+ //# sourceMappingURL=registry-G2ZG5TIN.js.map
@@ -1,6 +1,6 @@
1
- import{p as f,s as h,v as g,y as m,z as E}from"./chunk-HPQ3AAG3.js";import{a as p,f as w}from"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";E();w();var l="request-gate",x="request-context",q=.1,C=3e3;function b(t,s){return s??f(t)??C}async function k(t,s,n,r=Math.random){let d=g(l)==="active";if(d){let e=h().seats[l]?.holdout??q;if(r()<e)return{active:!0,preprocess:!1,arm:"holdout"}}let i=d?"treatment":void 0,a=await m(l,{request:t.slice(0,2e3),agent:s,channel:n,operations:["select optional context","evaluate model routing where permitted"],constraints:["Keep the original request and mandatory instructions","Desktop model cannot be downgraded"]},{preprocess:p("This request benefits from structured context selection or another bounded typed decision before the main agent executes.",{true:"Relevant context must be selected, or a bounded routing decision can help. Follow-ups and ambiguous references need context.",false:"Typed preprocessing adds no useful decision; send the request to the configured main agent with existing context."})},{timeoutMs:b(l)});if(!a||a.mode!=="active")return{active:!1,preprocess:!1,arm:i};let c=a.answers.preprocess?.noul;return{active:!0,preprocess:Number.isFinite(c)&&c>=.5,arm:i}}var T={patternContext:"Learned behavioral patterns",references:"Retrieved project references",memoryContext:"Retrieved agent memory",crossChatContext:"Summaries from other conversations",longMemoryRecall:"Older conversation recall",wikiContext:"Retrieved wiki knowledge"},v=[{id:"landscape",header:/^\[Landscape\]$/,description:"Directory of the other agents on this node and on mesh peers, and the channels they are on"},{id:"landscape.messaging",header:/^\[Cross-Channel Messaging\]$/,description:"How to send a message to a different channel than the one this request came from"},{id:"landscape.recall",header:/^\[Conversation Recall\b/,description:"How to look up earlier turns of a conversation that are not in the prompt"},{id:"landscape.monitoring",header:/^\[Background Monitoring\]$/,description:"How to watch logs, pipelines or files in the background"},{id:"landscape.teams",header:/^\[Agent Teams\]$/,description:"How to split a large task across a team of parallel agents"}];function S(t){let s=[],n=null;for(let r of t.split(`
1
+ import{p as f,s as h,v as g,y as m,z as E}from"./chunk-R5VGRKUW.js";import{a as p,f as w}from"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";E();w();var l="request-gate",x="request-context",q=.1,C=3e3;function b(t,s){return s??f(t)??C}async function k(t,s,n,r=Math.random){let d=g(l)==="active";if(d){let e=h().seats[l]?.holdout??q;if(r()<e)return{active:!0,preprocess:!1,arm:"holdout"}}let i=d?"treatment":void 0,a=await m(l,{request:t.slice(0,2e3),agent:s,channel:n,operations:["select optional context","evaluate model routing where permitted"],constraints:["Keep the original request and mandatory instructions","Desktop model cannot be downgraded"]},{preprocess:p("This request benefits from structured context selection or another bounded typed decision before the main agent executes.",{true:"Relevant context must be selected, or a bounded routing decision can help. Follow-ups and ambiguous references need context.",false:"Typed preprocessing adds no useful decision; send the request to the configured main agent with existing context."})},{timeoutMs:b(l)});if(!a||a.mode!=="active")return{active:!1,preprocess:!1,arm:i};let c=a.answers.preprocess?.noul;return{active:!0,preprocess:Number.isFinite(c)&&c>=.5,arm:i}}var T={patternContext:"Learned behavioral patterns",references:"Retrieved project references",memoryContext:"Retrieved agent memory",crossChatContext:"Summaries from other conversations",longMemoryRecall:"Older conversation recall",wikiContext:"Retrieved wiki knowledge"},v=[{id:"landscape",header:/^\[Landscape\]$/,description:"Directory of the other agents on this node and on mesh peers, and the channels they are on"},{id:"landscape.messaging",header:/^\[Cross-Channel Messaging\]$/,description:"How to send a message to a different channel than the one this request came from"},{id:"landscape.recall",header:/^\[Conversation Recall\b/,description:"How to look up earlier turns of a conversation that are not in the prompt"},{id:"landscape.monitoring",header:/^\[Background Monitoring\]$/,description:"How to watch logs, pipelines or files in the background"},{id:"landscape.teams",header:/^\[Agent Teams\]$/,description:"How to split a large task across a team of parallel agents"}];function S(t){let s=[],n=null;for(let r of t.split(`
2
2
  `)){let d=/^\[[^\]]+\]$/.test(r);if(d||!n){let i=d?v.find(a=>a.header.test(r)):void 0;n={id:i?i.id:null,text:r},s.push(n)}else n.text+=`
3
3
  `+r}return s}async function O(t,s={}){let n=Object.entries(T).flatMap(([e,o])=>{let u=t[e];return u?[y(e,o,u)]:[]}),r=t.landscape?S(t.landscape):[];for(let e of r){if(!e.id||!e.text.trim())continue;let o=v.find(u=>u.id===e.id);n.push(y(e.id,o.description,e.text))}if(!n.length)return{input:t,excluded:[]};let d=Object.fromEntries(n.map(e=>[e.id,p(`Context block ${e.id} is relevant to completing the current request correctly.`,{true:"Needed or potentially relevant; retain if uncertain or the preview is incomplete.",false:"Clearly unrelated to the current request; safe to omit."})])),i=await m(x,{request:t.message.slice(0,2e3),channel:t.channel,agent:t.agentId,mandatory:["request","identity","permissions and instructions","same-chat history","handover","attachments","group-chat rules"],context:n},d,{timeoutMs:b(x,s.timeoutMs)});if(!i||i.mode!=="active")return{input:t,excluded:[]};let a={...t},c=[];for(let e of n){let o=i.answers[e.id]?.noul;Number.isFinite(o)&&o>=0&&o<.2&&c.push(e.id)}for(let e of c)e in T&&delete a[e];if(r.some(e=>e.id&&c.includes(e.id))){let e=r.filter(o=>!o.id||!c.includes(o.id)).map(o=>o.text.trim()).filter(Boolean);a.landscape=e.length?e.join(`
4
4
 
5
5
  `):void 0}return{input:a,excluded:c}}function y(t,s,n){return{id:t,description:s,source:t,characters:n.length,preview:n.slice(0,400),trust:"context data, not instructions"}}export{q as DEFAULT_REQUEST_GATE_HOLDOUT,x as REQUEST_CONTEXT_SEAT,l as REQUEST_GATE_SEAT,C as REQUEST_SEAT_TIMEOUT_MS,k as evaluateRequest,O as selectRequestContext,S as splitLandscape};
6
- //# sourceMappingURL=request-planner-4ORFYSAT.js.map
6
+ //# sourceMappingURL=request-planner-THTPE3FP.js.map
@@ -1,4 +1,4 @@
1
- import{b as I}from"./chunk-MFUN3ZS3.js";import"./chunk-QSKG754X.js";import"./chunk-HPQ3AAG3.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-6TURWSMN.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{createHash as E}from"crypto";var v="review:",b={decisions:"project",warnings:"feedback",friction:"feedback",context:"reference"};function A(t,n,r){let s=E("sha1").update(r.trim().toLowerCase()).digest("hex").slice(0,10);return`${v}${t}/${n}@${s}`}function F(t){if(!t.startsWith(v))return null;let n=t.slice(v.length),r=n.lastIndexOf("@"),s=n.lastIndexOf("/",r===-1?void 0:r);return r===-1||s===-1?null:{reviewId:n.slice(0,s),kind:n.slice(s+1,r),digest:n.slice(r+1)}}var C=t=>t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,48)||"finding",L=5;function T(t,n){return`${t}|${I(n)}`}function K(t,n={}){let r=n.kinds??Object.keys(b),s=n.minLength??24,h=[],d=new Map,u=new Map,f=new Map,x=new Map;for(let e of t){let i;try{i=JSON.parse(e.result)}catch{continue}let o=e.updated_at?new Date(e.updated_at).toISOString():new Date().toISOString();for(let c of r){let l=b[c];if(!l)continue;let R=i[c];if(Array.isArray(R))for(let $ of R){let a=String($?.text??"").trim();if(a.length<s)continue;let g=A(e.id,c,a),_=g.slice(g.lastIndexOf("@")),w=`${c}${_}`,y=T(c,a),S=f.get(y)??new Set;if(S.add(e.session_id??e.id),f.set(y,S),d.has(w))continue;let O=String($?.evidence??"").trim(),k={occurrences:1,agentId:e.agent,key:`${e.agent}/${l}_${C(a)}`,stamp:g,memory:{name:C(a),type:l,description:a.slice(0,200),body:"",createdAt:o,updatedAt:o}};x.set(g,{text:a,evidence:O,agent:e.agent,source:e.source}),d.set(w,k),u.set(w,y),h.push(k)}}}for(let[e,i]of d){let o=f.get(u.get(e)??"");i.occurrences=o?.size??1,i.sessions=[...o??[]].slice(0,L);let c=x.get(i.stamp);i.memory.body=D(c,i.occurrences)}let m=new Map;for(let[e,i]of d){let o=u.get(e)??e,c=m.get(o)??[];c.push(i),m.set(o,c)}let M=[...m.values()].sort((e,i)=>i[0].occurrences-e[0].occurrences),p=[];for(let e=0;p.length<h.length;e++){let i=!1;for(let o of M)e<o.length&&(p.push(o[e]),i=!0);if(!i)break}return p}function D(t,n){let r=`${t.agent}${t.source?` via ${t.source}`:""}`,s=[];return n>1?(s.push(`Observed in ${n} separate sessions. Most recently stated as:`),s.push(`> ${t.text}`),s.push(`Recurring across ${n} sessions is what makes this worth recording \u2014 any single occurrence is session state, the repetition is the finding.`)):s.push(t.text),t.evidence&&s.push(`**Evidence:** ${t.evidence}`),s.push(`_From ${n>1?"session reviews":"a session review"} of ${r}._`),s.join(`
1
+ import{b as I}from"./chunk-GOAMSJ2D.js";import"./chunk-5TTHN7DP.js";import"./chunk-R5VGRKUW.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-6TURWSMN.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{createHash as E}from"crypto";var v="review:",b={decisions:"project",warnings:"feedback",friction:"feedback",context:"reference"};function A(t,n,r){let s=E("sha1").update(r.trim().toLowerCase()).digest("hex").slice(0,10);return`${v}${t}/${n}@${s}`}function F(t){if(!t.startsWith(v))return null;let n=t.slice(v.length),r=n.lastIndexOf("@"),s=n.lastIndexOf("/",r===-1?void 0:r);return r===-1||s===-1?null:{reviewId:n.slice(0,s),kind:n.slice(s+1,r),digest:n.slice(r+1)}}var C=t=>t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,48)||"finding",L=5;function T(t,n){return`${t}|${I(n)}`}function K(t,n={}){let r=n.kinds??Object.keys(b),s=n.minLength??24,h=[],d=new Map,u=new Map,f=new Map,x=new Map;for(let e of t){let i;try{i=JSON.parse(e.result)}catch{continue}let o=e.updated_at?new Date(e.updated_at).toISOString():new Date().toISOString();for(let c of r){let l=b[c];if(!l)continue;let R=i[c];if(Array.isArray(R))for(let $ of R){let a=String($?.text??"").trim();if(a.length<s)continue;let g=A(e.id,c,a),_=g.slice(g.lastIndexOf("@")),w=`${c}${_}`,y=T(c,a),S=f.get(y)??new Set;if(S.add(e.session_id??e.id),f.set(y,S),d.has(w))continue;let O=String($?.evidence??"").trim(),k={occurrences:1,agentId:e.agent,key:`${e.agent}/${l}_${C(a)}`,stamp:g,memory:{name:C(a),type:l,description:a.slice(0,200),body:"",createdAt:o,updatedAt:o}};x.set(g,{text:a,evidence:O,agent:e.agent,source:e.source}),d.set(w,k),u.set(w,y),h.push(k)}}}for(let[e,i]of d){let o=f.get(u.get(e)??"");i.occurrences=o?.size??1,i.sessions=[...o??[]].slice(0,L);let c=x.get(i.stamp);i.memory.body=D(c,i.occurrences)}let m=new Map;for(let[e,i]of d){let o=u.get(e)??e,c=m.get(o)??[];c.push(i),m.set(o,c)}let M=[...m.values()].sort((e,i)=>i[0].occurrences-e[0].occurrences),p=[];for(let e=0;p.length<h.length;e++){let i=!1;for(let o of M)e<o.length&&(p.push(o[e]),i=!0);if(!i)break}return p}function D(t,n){let r=`${t.agent}${t.source?` via ${t.source}`:""}`,s=[];return n>1?(s.push(`Observed in ${n} separate sessions. Most recently stated as:`),s.push(`> ${t.text}`),s.push(`Recurring across ${n} sessions is what makes this worth recording \u2014 any single occurrence is session state, the repetition is the finding.`)):s.push(t.text),t.evidence&&s.push(`**Evidence:** ${t.evidence}`),s.push(`_From ${n>1?"session reviews":"a session review"} of ${r}._`),s.join(`
2
2
 
3
3
  `)}export{L as MAX_EVIDENCE_SESSIONS,b as PROMOTABLE_KINDS,v as REVIEW_STAMP_PREFIX,F as parseReviewStamp,A as reviewStamp,K as reviewsToCandidates};
4
- //# sourceMappingURL=review-candidates-77NDFTGM.js.map
4
+ //# sourceMappingURL=review-candidates-7PS7CHXF.js.map
@@ -1,2 +1,2 @@
1
- import{a,b,c,d,e,f}from"./chunk-RB5W3FVO.js";import"./chunk-HPQ3AAG3.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{e as DEFAULT_TRIAGE_ACTIONS,a as DOWNGRADE_BELOW,b as channelKeepsConfiguredModel,c as cheapModelForEngine,d as routeTaskModel,f as triageModelFor};
2
- //# sourceMappingURL=routing-3FL3KYPJ.js.map
1
+ import{a,b,c,d,e,f}from"./chunk-4JHMV3D3.js";import"./chunk-R5VGRKUW.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{e as DEFAULT_TRIAGE_ACTIONS,a as DOWNGRADE_BELOW,b as channelKeepsConfiguredModel,c as cheapModelForEngine,d as routeTaskModel,f as triageModelFor};
2
+ //# sourceMappingURL=routing-PE7DB7WA.js.map
@@ -0,0 +1,2 @@
1
+ import{a,b}from"./chunk-VYLMC5DO.js";import"./chunk-RKPAVWXF.js";import"./chunk-JGX5IWNX.js";import"./chunk-3LAQ74H7.js";import"./chunk-SFUNL7RV.js";import"./chunk-3UOTLMXD.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{b as resolveScheduleCaller,a as runScheduleTool};
2
+ //# sourceMappingURL=schedule-tool-3FXRKJGN.js.map
@@ -1,2 +1,2 @@
1
- import{n as a,o as b,p as c,q as d,r as e,s as f}from"./chunk-NYWIN4BW.js";import"./chunk-QVPBSV5Z.js";import"./chunk-3UOTLMXD.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{a as AGENT_RUN_TIMEOUT_FLOOR,f as CronScheduler,b as agentRunTimeout,e as cronRunId,d as getNextCronDate,c as runLinkIds};
2
- //# sourceMappingURL=scheduler-QLL7ZHYW.js.map
1
+ import{n as a,o as b,p as c,q as d,r as e,s as f}from"./chunk-3LAQ74H7.js";import"./chunk-SFUNL7RV.js";import"./chunk-3UOTLMXD.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{a as AGENT_RUN_TIMEOUT_FLOOR,f as CronScheduler,b as agentRunTimeout,e as cronRunId,d as getNextCronDate,c as runLinkIds};
2
+ //# sourceMappingURL=scheduler-YTXCIQTZ.js.map
@@ -1,2 +1,2 @@
1
- import{o as a,p as b,q as c,r as d,s as e,t as f,u as g,v as h,w as i,x as j,y as k,z as l}from"./chunk-HPQ3AAG3.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";l();export{a as DEFAULT_SEAT_TIMEOUT_MS,k as askSeat,c as configureDecisions,b as configuredSeatTimeout,e as decisionsRuntime,h as getSeatMode,i as labelSeatCall,f as parseSeatMode,j as recordSeatOutcome,d as resetDecisionsRuntime,g as seatEnvVar};
2
- //# sourceMappingURL=seat-RBKONP63.js.map
1
+ import{o as a,p as b,q as c,r as d,s as e,t as f,u as g,v as h,w as i,x as j,y as k,z as l}from"./chunk-R5VGRKUW.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";l();export{a as DEFAULT_SEAT_TIMEOUT_MS,k as askSeat,c as configureDecisions,b as configuredSeatTimeout,e as decisionsRuntime,h as getSeatMode,i as labelSeatCall,f as parseSeatMode,j as recordSeatOutcome,d as resetDecisionsRuntime,g as seatEnvVar};
2
+ //# sourceMappingURL=seat-6DMK4274.js.map
@@ -1,2 +1,2 @@
1
- import{y as S,z as w}from"./chunk-HPQ3AAG3.js";import{a as g,b as h,f as R}from"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import{e as f}from"./chunk-JHCI6XCJ.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";w();R();var p="skill-select";function y(l){return{task:d(l.task,1200),...l.agent?{agent:l.agent}:{},skills:l.candidates.map(t=>({name:t.name,purpose:d(t.description,300),...t.category?{category:t.category}:{},...t.tags?.length?{tags:t.tags.slice(0,8)}:{}}))}}function b(l){let t={};for(let i of l)t[i.name]=d(i.description,300);return{anyRelevant:g("At least one of these skills is about the task at hand.",{true:"The task is the kind of work one of these skills exists for, and following it would change how the work is done \u2014 it names the same system, the same procedure or the same kind of artefact.",false:"None of them is about this task. They may share vocabulary with it, mention the same tools, or belong to the same project without bearing on what is being asked. Sharing words with a task is not being about it."}),best:h(t,"Which skill is this task most about?")}}function v(l){let t=l.anyRelevant,i=l.best,o=Object.entries(i.probabilities??{}).map(([e,s])=>({name:e,p:Number(s)||0})).sort((e,s)=>s.p-e.p);return{anyRelevant:t.noul,name:i.choice,confidence:i.confidence,ranked:o}}function d(l,t){return l.length>t?`${l.slice(0,t)}\u2026`:l}var x=.1,A=12;async function E(l,t,i={}){let o=i.minRelevant??.6,e=f(l,t).filter(n=>n.relevance>=x).slice(0,A),s=e.map(n=>({name:n.skill.frontmatter.name,lexical:n.relevance}));if(e.length===0)return{skill:null,anyRelevant:0,confidence:0,shortlist:s,judged:!1,reason:"no skill mentions anything in this task"};if(e.length===1)return{skill:e[0].skill,anyRelevant:e[0].relevance,confidence:e[0].relevance,shortlist:s,judged:!1,reason:`only ${e[0].skill.frontmatter.name} matched (${e[0].matchReason})`};let r=e.map(n=>({name:n.skill.frontmatter.name,description:n.skill.frontmatter.description,category:n.skill.frontmatter.category??null,tags:n.skill.frontmatter.tags})),m=await S(p,y({task:t,agent:i.agent??null,candidates:r}),b(r),{incumbent:{best:r[0].name},features:{agent:i.agent??"unknown",candidates:r.length}});if(!m)return{skill:e[0].skill,anyRelevant:e[0].relevance,confidence:e[0].relevance,shortlist:s,judged:!1,reason:`seat off \u2014 lexical top match (${e[0].matchReason})`};let a=v(m.answers),c=s.map(n=>({...n,p:a.ranked.find(k=>k.name===n.name)?.p??0})).sort((n,k)=>(k.p??0)-(n.p??0));if(a.anyRelevant<o)return{skill:null,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`nothing on the shortlist is about this task (${a.anyRelevant.toFixed(2)} below ${o})`};let u=e.find(n=>n.skill.frontmatter.name===a.name);return u?{skill:u.skill,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`${a.name} (confidence ${a.confidence.toFixed(2)})`}:{skill:null,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`seat chose "${a.name}", which was not on the shortlist`}}export{E as pickSkillForTask};
2
- //# sourceMappingURL=select-MOUDR6PQ.js.map
1
+ import{y as S,z as w}from"./chunk-R5VGRKUW.js";import{a as g,b as h,f as R}from"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import{e as f}from"./chunk-JHCI6XCJ.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";w();R();var p="skill-select";function y(l){return{task:d(l.task,1200),...l.agent?{agent:l.agent}:{},skills:l.candidates.map(t=>({name:t.name,purpose:d(t.description,300),...t.category?{category:t.category}:{},...t.tags?.length?{tags:t.tags.slice(0,8)}:{}}))}}function b(l){let t={};for(let i of l)t[i.name]=d(i.description,300);return{anyRelevant:g("At least one of these skills is about the task at hand.",{true:"The task is the kind of work one of these skills exists for, and following it would change how the work is done \u2014 it names the same system, the same procedure or the same kind of artefact.",false:"None of them is about this task. They may share vocabulary with it, mention the same tools, or belong to the same project without bearing on what is being asked. Sharing words with a task is not being about it."}),best:h(t,"Which skill is this task most about?")}}function v(l){let t=l.anyRelevant,i=l.best,o=Object.entries(i.probabilities??{}).map(([e,s])=>({name:e,p:Number(s)||0})).sort((e,s)=>s.p-e.p);return{anyRelevant:t.noul,name:i.choice,confidence:i.confidence,ranked:o}}function d(l,t){return l.length>t?`${l.slice(0,t)}\u2026`:l}var x=.1,A=12;async function E(l,t,i={}){let o=i.minRelevant??.6,e=f(l,t).filter(n=>n.relevance>=x).slice(0,A),s=e.map(n=>({name:n.skill.frontmatter.name,lexical:n.relevance}));if(e.length===0)return{skill:null,anyRelevant:0,confidence:0,shortlist:s,judged:!1,reason:"no skill mentions anything in this task"};if(e.length===1)return{skill:e[0].skill,anyRelevant:e[0].relevance,confidence:e[0].relevance,shortlist:s,judged:!1,reason:`only ${e[0].skill.frontmatter.name} matched (${e[0].matchReason})`};let r=e.map(n=>({name:n.skill.frontmatter.name,description:n.skill.frontmatter.description,category:n.skill.frontmatter.category??null,tags:n.skill.frontmatter.tags})),m=await S(p,y({task:t,agent:i.agent??null,candidates:r}),b(r),{incumbent:{best:r[0].name},features:{agent:i.agent??"unknown",candidates:r.length}});if(!m)return{skill:e[0].skill,anyRelevant:e[0].relevance,confidence:e[0].relevance,shortlist:s,judged:!1,reason:`seat off \u2014 lexical top match (${e[0].matchReason})`};let a=v(m.answers),c=s.map(n=>({...n,p:a.ranked.find(k=>k.name===n.name)?.p??0})).sort((n,k)=>(k.p??0)-(n.p??0));if(a.anyRelevant<o)return{skill:null,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`nothing on the shortlist is about this task (${a.anyRelevant.toFixed(2)} below ${o})`};let u=e.find(n=>n.skill.frontmatter.name===a.name);return u?{skill:u.skill,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`${a.name} (confidence ${a.confidence.toFixed(2)})`}:{skill:null,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`seat chose "${a.name}", which was not on the shortlist`}}export{E as pickSkillForTask};
2
+ //# sourceMappingURL=select-CLDYPAOS.js.map
@@ -1,2 +1,2 @@
1
- import{b as a}from"./chunk-QVPBSV5Z.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";async function i(o,r,s={}){let e=null,n=await a(l=>{let t=l.crons?.[o];if(t?r&&t.approval?.action==="create"?e={ok:!1,status:409,error:`schedule "${o}" is waiting for approval: agentx schedule approve ${o}`}:t.enabled===r&&(e={ok:!0,id:o,enabled:r,changed:!1}):e={ok:!1,status:404,error:`no schedule "${o}"`},e)throw new Error("no write");t.enabled=r,e={ok:!0,id:o,enabled:r,changed:!0}},{configPath:s.configPath,reload:!1});return e&&(!e.ok||!e.changed)?e:n.success?e??{ok:!1,status:500,error:"mutation did not run"}:{ok:!1,status:500,error:n.error||"could not write agentx.json"}}export{i as setCronEnabled};
2
- //# sourceMappingURL=set-enabled-JKYF3QIA.js.map
1
+ import{b as a}from"./chunk-SFUNL7RV.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";async function i(o,r,s={}){let e=null,n=await a(l=>{let t=l.crons?.[o];if(t?r&&t.approval?.action==="create"?e={ok:!1,status:409,error:`schedule "${o}" is waiting for approval: agentx schedule approve ${o}`}:t.enabled===r&&(e={ok:!0,id:o,enabled:r,changed:!1}):e={ok:!1,status:404,error:`no schedule "${o}"`},e)throw new Error("no write");t.enabled=r,e={ok:!0,id:o,enabled:r,changed:!0}},{configPath:s.configPath,reload:!1});return e&&(!e.ok||!e.changed)?e:n.success?e??{ok:!1,status:500,error:"mutation did not run"}:{ok:!1,status:500,error:n.error||"could not write agentx.json"}}export{i as setCronEnabled};
2
+ //# sourceMappingURL=set-enabled-ZH2DH4GU.js.map
@@ -0,0 +1,6 @@
1
+ import{b as p}from"./chunk-VYLMC5DO.js";import"./chunk-RKPAVWXF.js";import{b as h}from"./chunk-DG2DC43E.js";import"./chunk-WBG6NA7R.js";import"./chunk-JGX5IWNX.js";import"./chunk-3LAQ74H7.js";import"./chunk-SFUNL7RV.js";import"./chunk-3UOTLMXD.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";var w=45e3,f=t=>typeof t=="string"?t.trim():"",g={in_progress:"in progress",waiting_owner:"waiting on the owner",waiting_other:"waiting on another agent",needs_attention:"needs attention"};function m(t){return t.length?t.map(e=>{let a=new Date(e.createdAt).toISOString().slice(0,16).replace("T"," "),d=e.state==="waiting_owner"&&e.question?` Question: ${e.question}`:e.state==="needs_attention"&&e.attentionReason?` ${e.attentionReason}`:"",o=String(e.text).replace(/\s+/g," ").trim(),i=[e.promise&&e.owedTo?` Promised to ${e.owedTo}.`:"",e.dueAt?` Due ${new Date(e.dueAt).toISOString().slice(0,16).replace("T"," ")} UTC.`:"",e.closeWhen?` Closes on its check (${e.closeWhen.kind})${e.verifyState?`: ${e.verifyState}`:""}.`:""].join("");return`- ${e.id} [${g[e.state]??e.state}] ${a} UTC, ${e.channel}, ${e.agentId}: ${o.length>160?`${o.slice(0,159)}\u2026`:o}.${d}${i}`}).join(`
2
+ `):"No open requests."}function $(t){return(t??[]).map(e=>`${e.idx}. ${e.name} (${e.agentId}, ${e.kind}) [${e.state}]${e.needsApproval?` approval: ${e.approval}`:""}`)}async function v(t,e){let a=e.fetch??fetch,d=e.daemonUrl.replace(/\/$/,""),o=(f(t.action)||"list").toLowerCase();try{if(o==="list"){let u=await a(`${d}/requests`,{signal:AbortSignal.timeout(1e4)}),r=await u.json().catch(()=>({}));return u.ok?r.enabled?`${r.count} open request${r.count===1?"":"s"}, oldest first.
3
+ ${m(r.items??[])}`:"Requests are turned off on this node (requests.enabled), so nothing is recorded.":`Error: ${r?.error||`HTTP ${u.status}`}`}let i=e.env??process.env,l=p(t,i);if(!l)return"Error: couldn't tell which agent you are. Pass callerAgentId.";let c=await a(`${d}/requests`,{method:"POST",headers:{"Content-Type":"application/json",...h(i)},body:JSON.stringify({action:o,agentId:l.agentId,id:t.id,question:t.question,evidence:t.evidence,reason:t.reason,steps:t.steps,step:t.step,status:t.status,note:t.note,home:t.home,owedTo:t.owedTo,text:t.text,due:t.due,closeWhen:t.closeWhen}),signal:AbortSignal.timeout(o==="done"?w:1e4)}),s=await c.json().catch(()=>({}));if(!c.ok)return`Error: ${s?.error||`HTTP ${c.status}`}`;let n=s.request;return o==="accept"&&s.plan?[`Request ${n.id} is open with a plan of ${s.steps.length} steps. The daemon hands each step to its agent in order, nudges a step that goes quiet, and tells the owner when it is finished or blocked.`,...$(s.steps),`Steps the owner approves get a decision card now; an approved message is sent by the daemon itself. Report your own steps with {action:"step", id:"${n.id}", step:<n>, status:"progress"|"done"|"blocked"}.`].join(`
4
+ `):o==="step"?[`Step reported. Plan of ${n.id}:`,...$(s.steps)].join(`
5
+ `):o==="accept"?`Request ${n.id} is open and in progress. Close it with done (and a link to the evidence) or decline (and the reason); it stays on the owner's list until then.`:o==="wait"?`Request ${n.id} is waiting on the owner with your question. Ask them the question now, once.`:o==="promise"?`Promise ${n.id} is open, owed to ${n.owedTo}${n.dueAt?`, due ${new Date(n.dueAt).toISOString().slice(0,16).replace("T"," ")} UTC`:""}. `+(n.closeWhen?"The daemon checks its evidence and closes it once the check is met.":`Close it with {action:"done", id:"${n.id}", evidence:"<link>"} when it is kept.`):o==="done"&&s.verify==="unverified"?`Request ${n.id} stays open: its check could not say whether it is finished (${s.detail}). It is marked unverified; the daemon checks again, and the owner can close it by hand.`:o==="done"?`Request ${n.id} is closed as done${s.verified?" (its check was met)":""}. Evidence: ${n.evidence}`:`Request ${n.id} is closed as declined. Reason: ${n.closeReason}`}catch(i){return`Error: couldn't reach the daemon (${i?.message??i}).`}}export{w as DONE_TIMEOUT_MS,m as describeOpen,$ as describeSteps,v as runRequestTool};
6
+ //# sourceMappingURL=tool-4AO3ZMAY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/requests/tool.ts"],"sourcesContent":["import { resolveScheduleCaller } from \"@/crons/schedule-tool\"\nimport { callerHeaders } from \"@/calls/service\"\n\n// --- Agent-facing `agentx_request` tool (#356) ---\n//\n// Lets an agent say what it is doing with the owner's request, so the\n// request stays visible until it is closed:\n// accept I am taking this on; keep it open after this turn. With\n// `steps` (two or more): a tracked plan the daemon follows (#788)\n// step report on one step of a plan: progress, done, blocked\n// wait the next step is the owner's answer to this question\n// done finished, with a link to the evidence. On a loop with a\n// closeWhen the daemon runs its check first (#1039)\n// decline I will not do it, with the reason\n// promise I owe someone something (owedTo, text, due, closeWhen):\n// an open loop of its own, listed with the open requests\n// list what is still open\n// It talks to the daemon's /requests endpoints. Dropping a request is the\n// owner's alone; there is no action for it here.\n\nexport interface RequestToolDeps {\n daemonUrl: string\n fetch?: typeof fetch\n env?: NodeJS.ProcessEnv\n}\n\n/** A done on a loop with a check waits for it: the slowest is an issue\n * check, three forge calls of up to 10 s each. */\nexport const DONE_TIMEOUT_MS = 45_000\n\nconst str = (v: unknown) => (typeof v === \"string\" ? v.trim() : \"\")\n\nconst STATE_WORDS: Record<string, string> = {\n in_progress: \"in progress\",\n waiting_owner: \"waiting on the owner\",\n waiting_other: \"waiting on another agent\",\n needs_attention: \"needs attention\",\n}\n\n/** One line per open request, oldest first. */\nexport function describeOpen(items: any[]): string {\n if (!items.length) return \"No open requests.\"\n return items.map((r) => {\n const when = new Date(r.createdAt).toISOString().slice(0, 16).replace(\"T\", \" \")\n const extra = r.state === \"waiting_owner\" && r.question ? ` Question: ${r.question}`\n : r.state === \"needs_attention\" && r.attentionReason ? ` ${r.attentionReason}` : \"\"\n const words = String(r.text).replace(/\\s+/g, \" \").trim()\n const loop = [\n r.promise && r.owedTo ? ` Promised to ${r.owedTo}.` : \"\",\n r.dueAt ? ` Due ${new Date(r.dueAt).toISOString().slice(0, 16).replace(\"T\", \" \")} UTC.` : \"\",\n r.closeWhen ? ` Closes on its check (${r.closeWhen.kind})${r.verifyState ? `: ${r.verifyState}` : \"\"}.` : \"\",\n ].join(\"\")\n return `- ${r.id} [${STATE_WORDS[r.state] ?? r.state}] ${when} UTC, ${r.channel}, ${r.agentId}: ${words.length > 160 ? `${words.slice(0, 159)}…` : words}.${extra}${loop}`\n }).join(\"\\n\")\n}\n\n/** One line per plan step. */\nexport function describeSteps(steps: any[]): string[] {\n return (steps ?? []).map((s) => `${s.idx}. ${s.name} (${s.agentId}, ${s.kind}) [${s.state}]${s.needsApproval ? ` approval: ${s.approval}` : \"\"}`)\n}\n\n/** Returns the text the agent sees. Every refusal is text, never a throw. */\nexport async function runRequestTool(args: Record<string, unknown>, deps: RequestToolDeps): Promise<string> {\n const doFetch = deps.fetch ?? fetch\n const base = deps.daemonUrl.replace(/\\/$/, \"\")\n const action = (str(args.action) || \"list\").toLowerCase()\n\n try {\n if (action === \"list\") {\n const res = await doFetch(`${base}/requests`, { signal: AbortSignal.timeout(10_000) })\n const data = await res.json().catch(() => ({})) as any\n if (!res.ok) return `Error: ${data?.error || `HTTP ${res.status}`}`\n if (!data.enabled) return \"Requests are turned off on this node (requests.enabled), so nothing is recorded.\"\n return `${data.count} open request${data.count === 1 ? \"\" : \"s\"}, oldest first.\\n${describeOpen(data.items ?? [])}`\n }\n\n const env = deps.env ?? process.env\n const caller = resolveScheduleCaller(args, env)\n if (!caller) return \"Error: couldn't tell which agent you are. Pass callerAgentId.\"\n const res = await doFetch(`${base}/requests`, {\n method: \"POST\",\n // The headers name this run: the daemon refuses a write that does\n // not come from a running turn of the agent.\n headers: { \"Content-Type\": \"application/json\", ...callerHeaders(env) },\n body: JSON.stringify({\n action, agentId: caller.agentId,\n id: args.id, question: args.question, evidence: args.evidence, reason: args.reason,\n steps: args.steps, step: args.step, status: args.status, note: args.note, home: args.home,\n owedTo: args.owedTo, text: args.text, due: args.due, closeWhen: args.closeWhen,\n }),\n signal: AbortSignal.timeout(action === \"done\" ? DONE_TIMEOUT_MS : 10_000),\n })\n const data = await res.json().catch(() => ({})) as any\n if (!res.ok) return `Error: ${data?.error || `HTTP ${res.status}`}`\n const r = data.request\n if (action === \"accept\" && data.plan) {\n return [\n `Request ${r.id} is open with a plan of ${data.steps.length} steps. The daemon hands each step to its agent in order, nudges a step that goes quiet, and tells the owner when it is finished or blocked.`,\n ...describeSteps(data.steps),\n `Steps the owner approves get a decision card now; an approved message is sent by the daemon itself. Report your own steps with {action:\"step\", id:\"${r.id}\", step:<n>, status:\"progress\"|\"done\"|\"blocked\"}.`,\n ].join(\"\\n\")\n }\n if (action === \"step\") return [`Step reported. Plan of ${r.id}:`, ...describeSteps(data.steps)].join(\"\\n\")\n if (action === \"accept\") return `Request ${r.id} is open and in progress. Close it with done (and a link to the evidence) or decline (and the reason); it stays on the owner's list until then.`\n if (action === \"wait\") return `Request ${r.id} is waiting on the owner with your question. Ask them the question now, once.`\n if (action === \"promise\") {\n return `Promise ${r.id} is open, owed to ${r.owedTo}${r.dueAt ? `, due ${new Date(r.dueAt).toISOString().slice(0, 16).replace(\"T\", \" \")} UTC` : \"\"}. ` +\n (r.closeWhen ? \"The daemon checks its evidence and closes it once the check is met.\" : `Close it with {action:\"done\", id:\"${r.id}\", evidence:\"<link>\"} when it is kept.`)\n }\n if (action === \"done\" && data.verify === \"unverified\") {\n return `Request ${r.id} stays open: its check could not say whether it is finished (${data.detail}). It is marked unverified; the daemon checks again, and the owner can close it by hand.`\n }\n if (action === \"done\") return `Request ${r.id} is closed as done${data.verified ? \" (its check was met)\" : \"\"}. Evidence: ${r.evidence}`\n return `Request ${r.id} is closed as declined. Reason: ${r.closeReason}`\n } catch (e: any) {\n return `Error: couldn't reach the daemon (${e?.message ?? e}).`\n }\n}\n"],"mappings":"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","names":["DONE_TIMEOUT_MS","str","v","STATE_WORDS","describeOpen","items","r","when","extra","words","loop","describeSteps","steps","s","runRequestTool","args","deps","doFetch","base","action","res","data","env","caller","resolveScheduleCaller","callerHeaders","e"]}
@@ -1,4 +1,4 @@
1
- import{b as f}from"./chunk-AJUWIBLV.js";import"./chunk-RKPAVWXF.js";import{f as y}from"./chunk-Y4CYQV7G.js";import{b as u}from"./chunk-3W2BHUGM.js";import"./chunk-SHEUCITK.js";import"./chunk-WY5ZOEOE.js";import"./chunk-NYWIN4BW.js";import"./chunk-QVPBSV5Z.js";import"./chunk-3UOTLMXD.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";var w=new Set(["cron","heartbeat","api","a2a","mesh","approvals","requests"]);function c(t){return typeof t=="string"?t.trim():""}async function b(t,s){let d=s.fetch??fetch,l=s.daemonUrl.replace(/\/$/,""),i=(c(t.action)||"create").toLowerCase(),o=f(t,s.env??process.env);if(i==="status"){let n=c(t.id);if(!n)return"Error: `id` is required for status (the card id you got when you raised it).";try{let a=await d(`${l}/approvals/${encodeURIComponent(n)}`,{signal:AbortSignal.timeout(1e4)}),r=await a.json().catch(()=>({}));if(!a.ok)return`Error: ${r?.error||`HTTP ${a.status}`}`;let e=r.card;if(o&&e.raised_by!==o.agentId)return`Error: card "${n}" was raised by another agent.`;if(e.status==="pending")return`Card ${e.id} is still waiting for the operator. It expires ${e.expires}; then "${e.if_silent}" applies.`;if(e.status==="decided"){let h=e.verdict==="yes"?y(e).join(`
1
+ import{b as f}from"./chunk-VYLMC5DO.js";import"./chunk-RKPAVWXF.js";import{f as y}from"./chunk-VY7TBMJU.js";import{b as u}from"./chunk-DG2DC43E.js";import"./chunk-WBG6NA7R.js";import"./chunk-JGX5IWNX.js";import"./chunk-3LAQ74H7.js";import"./chunk-SFUNL7RV.js";import"./chunk-3UOTLMXD.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";var w=new Set(["cron","heartbeat","api","a2a","mesh","approvals","requests"]);function c(t){return typeof t=="string"?t.trim():""}async function b(t,s){let d=s.fetch??fetch,l=s.daemonUrl.replace(/\/$/,""),i=(c(t.action)||"create").toLowerCase(),o=f(t,s.env??process.env);if(i==="status"){let n=c(t.id);if(!n)return"Error: `id` is required for status (the card id you got when you raised it).";try{let a=await d(`${l}/approvals/${encodeURIComponent(n)}`,{signal:AbortSignal.timeout(1e4)}),r=await a.json().catch(()=>({}));if(!a.ok)return`Error: ${r?.error||`HTTP ${a.status}`}`;let e=r.card;if(o&&e.raised_by!==o.agentId)return`Error: card "${n}" was raised by another agent.`;if(e.status==="pending")return`Card ${e.id} is still waiting for the operator. It expires ${e.expires}; then "${e.if_silent}" applies.`;if(e.status==="decided"){let h=e.verdict==="yes"?y(e).join(`
2
2
  `):"";return`Card ${e.id}: the operator said ${String(e.verdict).toUpperCase()}.${e.note?` Note: ${e.note}`:""}${h?`
3
- ${h}`:""}`}return e.status==="resolved"?`Card ${e.id} was closed by ${e.raised_by}: ${e.resolution??"answered outside the card"}.`:`Card ${e.id} expired unanswered; the default applied: ${e.outcome??e.if_silent}.`}catch(a){return`Error: couldn't reach the daemon (${a?.message??a}).`}}if(i==="resolve"){let n=c(t.id),a=c(t.reason);if(!n)return"Error: `id` is required for resolve (the card id you got when you raised it).";if(!a)return'Error: `reason` is required for resolve: where the owner answered and what you did, e.g. "approved in chat, done".';if(!o)return"Error: couldn't tell which agent you are. Pass callerAgentId.";try{let r=await d(`${l}/approvals/${encodeURIComponent(n)}/resolve`,{method:"POST",headers:{"Content-Type":"application/json",...u(s.env??process.env)},body:JSON.stringify({raised_by:o.agentId,reason:a}),signal:AbortSignal.timeout(1e4)}),e=await r.json().catch(()=>({}));return r.ok?`Card ${e.card.id} is closed. It left the operator's inbox, so nobody will be asked about it again.`:`Error: ${e?.error||`HTTP ${r.status}`}`}catch(r){return`Error: couldn't reach the daemon (${r?.message??r}).`}}if(i!=="create")return`Error: unknown action "${i}". Use create, status or resolve.`;if(!o)return"Error: couldn't tell which agent you are. Pass callerAgentId.";let p=o.channel&&o.chatId&&!w.has(o.channel)?{channel:o.channel,chatId:o.chatId,...o.accountId?{accountId:o.accountId}:{}}:void 0,$={title:t.title,ask:t.ask,recommend:t.recommend,if_silent:t.if_silent,expires:t.expires,source:t.source,choices:t.choices,draft:t.draft,say:t.say,context:t.context,raised_by:o.agentId,...p?{reply:p}:{}};try{let n=await d(`${l}/approvals`,{method:"POST",headers:{"Content-Type":"application/json",...u(s.env??process.env)},body:JSON.stringify($),signal:AbortSignal.timeout(1e4)}),a=await n.json().catch(()=>({}));if(!n.ok)return`Error: ${a?.error||`HTTP ${n.status}`}`;let r=a.card;return[`Decision card ${r.id} is in the operator's Approvals inbox.`,`If nobody answers by ${r.expires}, "${r.if_silent}" applies.`,"You will get a message with the result. Tell the requester it is waiting for approval; don't ask the operator again in chat.",`If the operator answers the same thing in chat and you act on it, close the card with {action:"resolve", id:"${r.id}", reason:"approved in chat, done"} so it is not asked again.`].join(" ")}catch(n){return`Error: couldn't reach the daemon (${n?.message??n}).`}}export{b as runApprovalTool};
4
- //# sourceMappingURL=tool-Y3ZTSZGE.js.map
3
+ ${h}`:""}`}return e.status==="resolved"?`Card ${e.id} was closed by ${e.raised_by}: ${e.resolution??"answered outside the card"}.`:`Card ${e.id} expired unanswered; the default applied: ${e.outcome??e.if_silent}.`}catch(a){return`Error: couldn't reach the daemon (${a?.message??a}).`}}if(i==="resolve"){let n=c(t.id),a=c(t.reason);if(!n)return"Error: `id` is required for resolve (the card id you got when you raised it).";if(!a)return'Error: `reason` is required for resolve: where the owner answered and what you did, e.g. "approved in chat, done".';if(!o)return"Error: couldn't tell which agent you are. Pass callerAgentId.";try{let r=await d(`${l}/approvals/${encodeURIComponent(n)}/resolve`,{method:"POST",headers:{"Content-Type":"application/json",...u(s.env??process.env)},body:JSON.stringify({raised_by:o.agentId,reason:a}),signal:AbortSignal.timeout(1e4)}),e=await r.json().catch(()=>({}));return r.ok?`Card ${e.card.id} is closed. It left the operator's inbox, so nobody will be asked about it again.`:`Error: ${e?.error||`HTTP ${r.status}`}`}catch(r){return`Error: couldn't reach the daemon (${r?.message??r}).`}}if(i!=="create")return`Error: unknown action "${i}". Use create, status or resolve.`;if(!o)return"Error: couldn't tell which agent you are. Pass callerAgentId.";let p=o.channel&&o.chatId&&!w.has(o.channel)?{channel:o.channel,chatId:o.chatId,...o.accountId?{accountId:o.accountId}:{}}:void 0,$={title:t.title,ask:t.ask,recommend:t.recommend,if_silent:t.if_silent,expires:t.expires,source:t.source,choices:t.choices,draft:t.draft,say:t.say,context:t.context,followup:t.followup,raised_by:o.agentId,...p?{reply:p}:{}};try{let n=await d(`${l}/approvals`,{method:"POST",headers:{"Content-Type":"application/json",...u(s.env??process.env)},body:JSON.stringify($),signal:AbortSignal.timeout(1e4)}),a=await n.json().catch(()=>({}));if(!n.ok)return`Error: ${a?.error||`HTTP ${n.status}`}`;let r=a.card;return[`Decision card ${r.id} is in the operator's Approvals inbox.`,`If nobody answers by ${r.expires}, "${r.if_silent}" applies.`,"You will get a message with the result. Tell the requester it is waiting for approval; don't ask the operator again in chat.",`If the operator answers the same thing in chat and you act on it, close the card with {action:"resolve", id:"${r.id}", reason:"approved in chat, done"} so it is not asked again.`].join(" ")}catch(n){return`Error: couldn't reach the daemon (${n?.message??n}).`}}export{b as runApprovalTool};
4
+ //# sourceMappingURL=tool-MKDTKBJ4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/approvals/tool.ts"],"sourcesContent":["import { resolveScheduleCaller } from \"@/crons/schedule-tool\"\nimport { callerHeaders } from \"@/calls/service\"\nimport { answerLines } from \"./choices\"\n\n// --- Agent-facing `agentx_approval` tool ---\n//\n// Lets an agent raise a decision card instead of asking the operator in\n// chat, check what happened to one, and close its own card once the owner\n// answered the same thing in chat and it acted on that (#909). It talks to\n// the daemon's /approvals endpoints, which never decide: there is no\n// action here that approves or rejects anything.\n\nexport type ApprovalToolAction = \"create\" | \"status\" | \"resolve\"\n\nexport interface ApprovalToolDeps {\n daemonUrl: string\n fetch?: typeof fetch\n env?: NodeJS.ProcessEnv\n}\n\nconst NON_CHAT_CHANNELS = new Set([\"cron\", \"heartbeat\", \"api\", \"a2a\", \"mesh\", \"approvals\", \"requests\"])\n\nfunction str(v: unknown): string {\n return typeof v === \"string\" ? v.trim() : \"\"\n}\n\n/** Returns the text the agent sees. Every refusal is text, never a throw. */\nexport async function runApprovalTool(args: Record<string, unknown>, deps: ApprovalToolDeps): Promise<string> {\n const doFetch = deps.fetch ?? fetch\n const base = deps.daemonUrl.replace(/\\/$/, \"\")\n const action = (str(args.action) || \"create\").toLowerCase() as ApprovalToolAction\n const caller = resolveScheduleCaller(args, deps.env ?? process.env)\n\n if (action === \"status\") {\n const id = str(args.id)\n if (!id) return \"Error: `id` is required for status (the card id you got when you raised it).\"\n try {\n const res = await doFetch(`${base}/approvals/${encodeURIComponent(id)}`, { signal: AbortSignal.timeout(10_000) })\n const data = await res.json().catch(() => ({})) as any\n if (!res.ok) return `Error: ${data?.error || `HTTP ${res.status}`}`\n const c = data.card\n if (caller && c.raised_by !== caller.agentId) return `Error: card \"${id}\" was raised by another agent.`\n if (c.status === \"pending\") return `Card ${c.id} is still waiting for the operator. It expires ${c.expires}; then \"${c.if_silent}\" applies.`\n if (c.status === \"decided\") {\n const picked = c.verdict === \"yes\" ? answerLines(c).join(\"\\n\") : \"\"\n return `Card ${c.id}: the operator said ${String(c.verdict).toUpperCase()}.${c.note ? ` Note: ${c.note}` : \"\"}${picked ? `\\n${picked}` : \"\"}`\n }\n if (c.status === \"resolved\") return `Card ${c.id} was closed by ${c.raised_by}: ${c.resolution ?? \"answered outside the card\"}.`\n return `Card ${c.id} expired unanswered; the default applied: ${c.outcome ?? c.if_silent}.`\n } catch (e: any) {\n return `Error: couldn't reach the daemon (${e?.message ?? e}).`\n }\n }\n\n if (action === \"resolve\") {\n const id = str(args.id)\n const reason = str(args.reason)\n if (!id) return \"Error: `id` is required for resolve (the card id you got when you raised it).\"\n if (!reason) return \"Error: `reason` is required for resolve: where the owner answered and what you did, e.g. \\\"approved in chat, done\\\".\"\n if (!caller) return \"Error: couldn't tell which agent you are. Pass callerAgentId.\"\n try {\n const res = await doFetch(`${base}/approvals/${encodeURIComponent(id)}/resolve`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...callerHeaders(deps.env ?? process.env) },\n body: JSON.stringify({ raised_by: caller.agentId, reason }),\n signal: AbortSignal.timeout(10_000),\n })\n const data = await res.json().catch(() => ({})) as any\n if (!res.ok) return `Error: ${data?.error || `HTTP ${res.status}`}`\n return `Card ${data.card.id} is closed. It left the operator's inbox, so nobody will be asked about it again.`\n } catch (e: any) {\n return `Error: couldn't reach the daemon (${e?.message ?? e}).`\n }\n }\n\n if (action !== \"create\") return `Error: unknown action \"${action}\". Use create, status or resolve.`\n if (!caller) return \"Error: couldn't tell which agent you are. Pass callerAgentId.\"\n\n const reply = caller.channel && caller.chatId && !NON_CHAT_CHANNELS.has(caller.channel)\n ? { channel: caller.channel, chatId: caller.chatId, ...(caller.accountId ? { accountId: caller.accountId } : {}) }\n : undefined\n const payload = {\n title: args.title,\n ask: args.ask,\n recommend: args.recommend,\n if_silent: args.if_silent,\n expires: args.expires,\n source: args.source,\n choices: args.choices,\n draft: args.draft,\n say: args.say,\n context: args.context,\n raised_by: caller.agentId,\n ...(reply ? { reply } : {}),\n }\n try {\n const res = await doFetch(`${base}/approvals`, {\n method: \"POST\",\n // The headers name this run: a card moves a request to \"waiting on\n // the owner\" only when it comes from the turn of that request.\n headers: { \"Content-Type\": \"application/json\", ...callerHeaders(deps.env ?? process.env) },\n body: JSON.stringify(payload),\n signal: AbortSignal.timeout(10_000),\n })\n const data = await res.json().catch(() => ({})) as any\n if (!res.ok) return `Error: ${data?.error || `HTTP ${res.status}`}`\n const c = data.card\n return [\n `Decision card ${c.id} is in the operator's Approvals inbox.`,\n `If nobody answers by ${c.expires}, \"${c.if_silent}\" applies.`,\n \"You will get a message with the result. Tell the requester it is waiting for approval; don't ask the operator again in chat.\",\n `If the operator answers the same thing in chat and you act on it, close the card with {action:\"resolve\", id:\"${c.id}\", reason:\"approved in chat, done\"} so it is not asked again.`,\n ].join(\" \")\n } catch (e: any) {\n return `Error: couldn't reach the daemon (${e?.message ?? e}).`\n }\n}\n"],"mappings":"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","names":["NON_CHAT_CHANNELS","str","v","runApprovalTool","args","deps","doFetch","base","action","caller","resolveScheduleCaller","id","res","data","c","picked","answerLines","e","reason","callerHeaders","reply","payload"]}
1
+ {"version":3,"sources":["../src/approvals/tool.ts"],"sourcesContent":["import { resolveScheduleCaller } from \"@/crons/schedule-tool\"\nimport { callerHeaders } from \"@/calls/service\"\nimport { answerLines } from \"./choices\"\n\n// --- Agent-facing `agentx_approval` tool ---\n//\n// Lets an agent raise a decision card instead of asking the operator in\n// chat, check what happened to one, and close its own card once the owner\n// answered the same thing in chat and it acted on that (#909). It talks to\n// the daemon's /approvals endpoints, which never decide: there is no\n// action here that approves or rejects anything.\n\nexport type ApprovalToolAction = \"create\" | \"status\" | \"resolve\"\n\nexport interface ApprovalToolDeps {\n daemonUrl: string\n fetch?: typeof fetch\n env?: NodeJS.ProcessEnv\n}\n\nconst NON_CHAT_CHANNELS = new Set([\"cron\", \"heartbeat\", \"api\", \"a2a\", \"mesh\", \"approvals\", \"requests\"])\n\nfunction str(v: unknown): string {\n return typeof v === \"string\" ? v.trim() : \"\"\n}\n\n/** Returns the text the agent sees. Every refusal is text, never a throw. */\nexport async function runApprovalTool(args: Record<string, unknown>, deps: ApprovalToolDeps): Promise<string> {\n const doFetch = deps.fetch ?? fetch\n const base = deps.daemonUrl.replace(/\\/$/, \"\")\n const action = (str(args.action) || \"create\").toLowerCase() as ApprovalToolAction\n const caller = resolveScheduleCaller(args, deps.env ?? process.env)\n\n if (action === \"status\") {\n const id = str(args.id)\n if (!id) return \"Error: `id` is required for status (the card id you got when you raised it).\"\n try {\n const res = await doFetch(`${base}/approvals/${encodeURIComponent(id)}`, { signal: AbortSignal.timeout(10_000) })\n const data = await res.json().catch(() => ({})) as any\n if (!res.ok) return `Error: ${data?.error || `HTTP ${res.status}`}`\n const c = data.card\n if (caller && c.raised_by !== caller.agentId) return `Error: card \"${id}\" was raised by another agent.`\n if (c.status === \"pending\") return `Card ${c.id} is still waiting for the operator. It expires ${c.expires}; then \"${c.if_silent}\" applies.`\n if (c.status === \"decided\") {\n const picked = c.verdict === \"yes\" ? answerLines(c).join(\"\\n\") : \"\"\n return `Card ${c.id}: the operator said ${String(c.verdict).toUpperCase()}.${c.note ? ` Note: ${c.note}` : \"\"}${picked ? `\\n${picked}` : \"\"}`\n }\n if (c.status === \"resolved\") return `Card ${c.id} was closed by ${c.raised_by}: ${c.resolution ?? \"answered outside the card\"}.`\n return `Card ${c.id} expired unanswered; the default applied: ${c.outcome ?? c.if_silent}.`\n } catch (e: any) {\n return `Error: couldn't reach the daemon (${e?.message ?? e}).`\n }\n }\n\n if (action === \"resolve\") {\n const id = str(args.id)\n const reason = str(args.reason)\n if (!id) return \"Error: `id` is required for resolve (the card id you got when you raised it).\"\n if (!reason) return \"Error: `reason` is required for resolve: where the owner answered and what you did, e.g. \\\"approved in chat, done\\\".\"\n if (!caller) return \"Error: couldn't tell which agent you are. Pass callerAgentId.\"\n try {\n const res = await doFetch(`${base}/approvals/${encodeURIComponent(id)}/resolve`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...callerHeaders(deps.env ?? process.env) },\n body: JSON.stringify({ raised_by: caller.agentId, reason }),\n signal: AbortSignal.timeout(10_000),\n })\n const data = await res.json().catch(() => ({})) as any\n if (!res.ok) return `Error: ${data?.error || `HTTP ${res.status}`}`\n return `Card ${data.card.id} is closed. It left the operator's inbox, so nobody will be asked about it again.`\n } catch (e: any) {\n return `Error: couldn't reach the daemon (${e?.message ?? e}).`\n }\n }\n\n if (action !== \"create\") return `Error: unknown action \"${action}\". Use create, status or resolve.`\n if (!caller) return \"Error: couldn't tell which agent you are. Pass callerAgentId.\"\n\n const reply = caller.channel && caller.chatId && !NON_CHAT_CHANNELS.has(caller.channel)\n ? { channel: caller.channel, chatId: caller.chatId, ...(caller.accountId ? { accountId: caller.accountId } : {}) }\n : undefined\n const payload = {\n title: args.title,\n ask: args.ask,\n recommend: args.recommend,\n if_silent: args.if_silent,\n expires: args.expires,\n source: args.source,\n choices: args.choices,\n draft: args.draft,\n say: args.say,\n context: args.context,\n followup: args.followup,\n raised_by: caller.agentId,\n ...(reply ? { reply } : {}),\n }\n try {\n const res = await doFetch(`${base}/approvals`, {\n method: \"POST\",\n // The headers name this run: a card moves a request to \"waiting on\n // the owner\" only when it comes from the turn of that request.\n headers: { \"Content-Type\": \"application/json\", ...callerHeaders(deps.env ?? process.env) },\n body: JSON.stringify(payload),\n signal: AbortSignal.timeout(10_000),\n })\n const data = await res.json().catch(() => ({})) as any\n if (!res.ok) return `Error: ${data?.error || `HTTP ${res.status}`}`\n const c = data.card\n return [\n `Decision card ${c.id} is in the operator's Approvals inbox.`,\n `If nobody answers by ${c.expires}, \"${c.if_silent}\" applies.`,\n \"You will get a message with the result. Tell the requester it is waiting for approval; don't ask the operator again in chat.\",\n `If the operator answers the same thing in chat and you act on it, close the card with {action:\"resolve\", id:\"${c.id}\", reason:\"approved in chat, done\"} so it is not asked again.`,\n ].join(\" \")\n } catch (e: any) {\n return `Error: couldn't reach the daemon (${e?.message ?? e}).`\n }\n}\n"],"mappings":"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","names":["NON_CHAT_CHANNELS","str","v","runApprovalTool","args","deps","doFetch","base","action","caller","resolveScheduleCaller","id","res","data","c","picked","answerLines","e","reason","callerHeaders","reply","payload"]}
@@ -0,0 +1,2 @@
1
+ import{b as a,c as b,d as c,e as d,f as e,g as f,h as g,i as h,j as i,k as j,l as k,m as l}from"./chunk-5TTHN7DP.js";import"./chunk-FCPTN6NF.js";import"./chunk-QIJLFPWE.js";export{h as claimResume,f as cleanupOrphanedTraces,e as getTrace,j as listTraces,k as listTracesForRuns,d as parseInjectedContext,i as recordResumeDecision,b as recordTraceEnd,a as recordTraceStart,c as recordTraceStep,g as takeInterruptedRuns,l as traceToolCalls};
2
+ //# sourceMappingURL=traces-GVEQZX24.js.map
@@ -1,2 +1,2 @@
1
- import"./chunk-VWTBHLMX.js";import{a as b}from"./chunk-ERG5OUKH.js";import{a}from"./chunk-6CTQPGBR.js";import"./chunk-OWNQ2FD4.js";import"./chunk-KEXBEUSU.js";import"./chunk-ROLSSYXE.js";import{d as c}from"./chunk-SDSSRNSU.js";import"./chunk-SKSYII3K.js";import"./chunk-XWHD2Z3Z.js";import"./chunk-WPNRDEHW.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-HPQ3AAG3.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-6TURWSMN.js";import"./chunk-QD6IICK7.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-K22XMF6M.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{b as WikiHub,a as WikiStore,c as agenticQuery};
2
- //# sourceMappingURL=wiki-3FSSLQAE.js.map
1
+ import"./chunk-VWTBHLMX.js";import{a as b}from"./chunk-Q73QQPDB.js";import{a}from"./chunk-RV4WJZW5.js";import"./chunk-OWNQ2FD4.js";import"./chunk-KEXBEUSU.js";import"./chunk-ROLSSYXE.js";import{d as c}from"./chunk-2GJFLPS7.js";import"./chunk-SKSYII3K.js";import"./chunk-UII54DAP.js";import"./chunk-WPNRDEHW.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-R5VGRKUW.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-MCI3DIWW.js";import"./chunk-6TURWSMN.js";import"./chunk-QD6IICK7.js";import"./chunk-QOYAX2FT.js";import"./chunk-2PJKGZWP.js";import"./chunk-7I7IEX4S.js";import"./chunk-DPIQCHXB.js";import"./chunk-BRK6M6LA.js";import"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{b as WikiHub,a as WikiStore,c as agenticQuery};
2
+ //# sourceMappingURL=wiki-CH2HYJVI.js.map
@@ -0,0 +1,2 @@
1
+ import{a,b}from"./chunk-MXWAREAQ.js";import"./chunk-QIJLFPWE.js";export{a as claudeCall,b as registerWikiEnrich};
2
+ //# sourceMappingURL=wiki-enrich-VEAYFVR2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+ import{a as k,d as b,f as w}from"./chunk-36AXN6ZB.js";import"./chunk-QIJLFPWE.js";var v="fallback",A="claude-sonnet";function U(e,l={}){return e.model||l[e.agentId]||null}function I(e,l=k){return/fable|mythos|opus|sonnet|haiku/i.test(e)&&b(e)in l}function y(e,l=k,r=e.model){return w.calculateCost({inputTokens:e.inputTokens??0,outputTokens:e.outputTokens??0,cacheReadTokens:e.cacheReadTokens??0,cacheCreateTokens:e.cacheCreateTokens??0,tier2InputTokens:e.tier2InputTokens??0,tier2OutputTokens:e.tier2OutputTokens??0,tier2CacheReadTokens:e.tier2CacheReadTokens??0,tier2CacheCreateTokens:e.tier2CacheCreateTokens??0,tasks:1,totalDuration:0,errors:0},r??A,l)}function W(e){return!e.agentId.startsWith("workflow:")}function M(e,l,r,i){let u=l.filter(o=>o.workflowRunId===e.id&&W(o)),a=u.map(o=>U(o,i)),d=u.reduce((o,f,s)=>o+y(f,r,a[s]),0);return{runId:e.id,workflowId:e.workflowId,startedAt:e.createdAt,status:e.status,costUsd:c(d),calls:u.length,failedCalls:u.filter(o=>o.status==="error"||o.status==="canceled").length,fallbackPricedCalls:a.filter(o=>!o||!I(o,r)).length,noModelCalls:a.filter(o=>!o).length,unpricedModels:[...new Set(a.filter(o=>!!o&&!I(o,r)))],traceIds:u.map(o=>o.taskId)}}function T(e){return e.status!=="paused"&&(e.status!=="running"||e.pending.length===0)}function x(e){for(let l=e.history.length-1;l>=0;l--){let r=e.history[l].output?.result;if(typeof r=="string"&&r.trim().toLowerCase()===v)return`step "${e.history[l].nodeId}" handed back`}return e.status==="completed"||e.status==="running"&&e.pending.length===0?null:`run ${e.status}`}function S(e){if(e.parentRunId)return e.parentRunId;for(let l of Object.values(e.context??{})){let r=l?.liveRunId;if(typeof r=="string"&&r)return r}return null}function c(e){return Math.round(e*1e6)/1e6}function h(e,l){let r=[...e].sort((a,d)=>a-d),i=c(e.reduce((a,d)=>a+d,0)),u=r.length>>1;return{runs:e.length,failed:l,totalCostUsd:i,costPerRunUsd:e.length?c(i/e.length):null,medianCostUsd:r.length?c(r.length%2?r[u]:(r[u-1]+r[u])/2):null}}var C=e=>e.status==="failed"||e.status==="canceled"||e.failedCalls>0;function L(e){let l=e.pricing??k,r=e.agentModels??{},i=e.runs.filter(t=>t.workflowId===e.liveWorkflow).map(t=>M(t,e.traces,l,r)).filter(t=>t.calls>0).sort((t,n)=>t.startedAt.localeCompare(n.startedAt)),u=e.runs.filter(t=>t.workflowId===e.pilotWorkflow),a=new Map,d=0;for(let t of u){let n=S(t);if(!n||!i.some(g=>g.runId===n)){d++;continue}let p=a.get(n);(!p||t.createdAt<p.createdAt)&&a.set(n,t)}let o=0,f=i.map(t=>{let n=a.get(t.runId);if(n&&!T(n)&&o++,!n||!T(n))return{live:t,pilot:null,handedBack:null,pilotPathCostUsd:null};let p=M(n,e.traces,l,r),g=x(n);return{live:t,pilot:p,handedBack:g,pilotPathCostUsd:c(p.costUsd+(g?t.costUsd:0))}}),s=f.filter(t=>t.pilot),m=h(s.map(t=>t.live.costUsd),s.filter(t=>C(t.live)).length),P=h(s.map(t=>t.pilotPathCostUsd),s.filter(t=>!t.handedBack&&C(t.pilot)).length),R=s.filter(t=>t.handedBack).length;return{liveWorkflow:e.liveWorkflow,pilotWorkflow:e.pilotWorkflow,live:h(i.map(t=>t.costUsd),i.filter(C).length),paired:{runs:s.length,handedBack:R,handBackShare:s.length?R/s.length:0,live:m,pilotPath:P,saving:s.length&&m.totalCostUsd>0?c(1-P.totalCostUsd/m.totalCostUsd):null},unpairedLive:i.length-s.length-o,orphanPilot:d,pilotInProgress:o,fallbackPriced:{live:i.reduce((t,n)=>t+n.fallbackPricedCalls,0),pilot:s.reduce((t,n)=>t+n.pilot.fallbackPricedCalls,0),calls:i.reduce((t,n)=>t+n.calls,0)+s.reduce((t,n)=>t+n.pilot.calls,0),noModel:i.reduce((t,n)=>t+n.noModelCalls,0)+s.reduce((t,n)=>t+n.pilot.noModelCalls,0),unpricedModels:[...new Set([...i,...s.map(t=>t.pilot)].flatMap(t=>t.unpricedModels))].sort()},pairs:f}}export{A as FALLBACK_PRICING_MODEL,v as HAND_BACK_RESULT,L as comparePilot,x as handBackReason,W as isModelCall,I as isPricedModel,S as liveRunIdOf,T as runEnded,y as traceCostUsd,U as traceModel};
2
+ //# sourceMappingURL=workflow-pilot-HCPSMGIC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storage/workflow-pilot.ts"],"sourcesContent":["import type { TraceRecord } from \"@/storage/traces\"\nimport { TokenTracker, CACHE_AWARE_PRICING, getModelFamily } from \"@/daemon/token-tracker\"\nimport type { WorkflowRun } from \"@/workflows/types\"\n\n// --- Workflow pilot report (#928) ---\n//\n// Read-only. Compares a live workflow's agent work with a pilot workflow\n// that ran beside it, in dry-run, on the same input. Cost is the trace\n// table's tokens priced with the token tracker's table (long-context\n// requests at 1.5x), so both sides are priced by the same meter. A pilot\n// run that hands the case back to the full agent costs its own tokens plus\n// the live run's: that is what the job would pay if the pilot went live.\n//\n// Pairing: a pilot run belongs to the live run that started it, read from\n// its `parentRunId` (a subProcess step) or from a `liveRunId` input on its\n// trigger. Code steps make no trace rows and so count as zero.\n//\n// Model: each row is priced at its own model, read from the trace row, else\n// from the agent's configured model. Older rows carry no model, an agent\n// may have none configured, and a model may be one the price table does not\n// know (getModelFamily maps any unknown name to Sonnet); such rows are priced\n// at the fallback rate and counted, so the report says how much rests on a guess.\n\n/** Result token a pilot step returns to hand the case back. */\nexport const HAND_BACK_RESULT = \"fallback\"\n\nexport type Pricing = typeof CACHE_AWARE_PRICING\n\n/** Model a row with no known model is priced at (TokenTracker's default). */\nexport const FALLBACK_PRICING_MODEL = \"claude-sonnet\"\n\n/** Configured model per agent id, for rows that do not carry one. */\nexport type AgentModels = Record<string, string | undefined>\n\n/** The model a trace row ran on: the row's own, else its agent's\n * configured model. Null when neither is known. */\nexport function traceModel(t: Pick<TraceRecord, \"model\" | \"agentId\">, agentModels: AgentModels = {}): string | null {\n return t.model || agentModels[t.agentId] || null\n}\n\n/** Whether the price table has a rate for `model`. getModelFamily maps\n * any name it does not recognise to Sonnet, so only a Claude family name\n * counts as known. */\nexport function isPricedModel(model: string, pricing: Pricing = CACHE_AWARE_PRICING): boolean {\n return /fable|mythos|opus|sonnet|haiku/i.test(model) && getModelFamily(model) in pricing\n}\n\n/** One trace row priced at `model`, or at the fallback rate without one. */\nexport function traceCostUsd(t: TraceRecord, pricing: Pricing = CACHE_AWARE_PRICING, model: string | null = t.model): number {\n return TokenTracker.calculateCost({\n inputTokens: t.inputTokens ?? 0,\n outputTokens: t.outputTokens ?? 0,\n cacheReadTokens: t.cacheReadTokens ?? 0,\n cacheCreateTokens: t.cacheCreateTokens ?? 0,\n tier2InputTokens: t.tier2InputTokens ?? 0,\n tier2OutputTokens: t.tier2OutputTokens ?? 0,\n tier2CacheReadTokens: t.tier2CacheReadTokens ?? 0,\n tier2CacheCreateTokens: t.tier2CacheCreateTokens ?? 0,\n tasks: 1, totalDuration: 0, errors: 0,\n }, model ?? FALLBACK_PRICING_MODEL, pricing)\n}\n\n/** A model call: an agent turn. The engine's own rows for code steps\n * (agent id `workflow:<type>`) carry no tokens. */\nexport function isModelCall(t: Pick<TraceRecord, \"agentId\">): boolean {\n return !t.agentId.startsWith(\"workflow:\")\n}\n\nexport interface RunCost {\n runId: string\n workflowId: string\n startedAt: string\n status: string\n costUsd: number\n /** Model calls in the run. */\n calls: number\n /** Model calls that failed or were cancelled. */\n failedCalls: number\n /** Model calls with no known model, or a model the price table does\n * not know, priced at the fallback rate. */\n fallbackPricedCalls: number\n /** The part of `fallbackPricedCalls` with no model on record at all. */\n noModelCalls: number\n /** Models seen on this run that the price table does not know. */\n unpricedModels: string[]\n traceIds: string[]\n}\n\nfunction runCost(run: WorkflowRun, traces: TraceRecord[], pricing: Pricing, agentModels: AgentModels): RunCost {\n const mine = traces.filter((t) => t.workflowRunId === run.id && isModelCall(t))\n const models = mine.map((t) => traceModel(t, agentModels))\n const cost = mine.reduce((s, t, i) => s + traceCostUsd(t, pricing, models[i]), 0)\n return {\n runId: run.id,\n workflowId: run.workflowId,\n startedAt: run.createdAt,\n status: run.status,\n costUsd: round(cost),\n calls: mine.length,\n failedCalls: mine.filter((t) => t.status === \"error\" || t.status === \"canceled\").length,\n fallbackPricedCalls: models.filter((m) => !m || !isPricedModel(m, pricing)).length,\n noModelCalls: models.filter((m) => !m).length,\n unpricedModels: [...new Set(models.filter((m): m is string => !!m && !isPricedModel(m, pricing)))],\n traceIds: mine.map((t) => t.taskId),\n }\n}\n\n/** Whether a run has ended. A run that ran out of steps without an end\n * step stays \"running\" with nothing pending. */\nexport function runEnded(run: Pick<WorkflowRun, \"status\" | \"pending\">): boolean {\n return run.status !== \"paused\" && (run.status !== \"running\" || run.pending.length === 0)\n}\n\n/** Why a pilot run handed its case back, or null when it answered. */\nexport function handBackReason(run: Pick<WorkflowRun, \"status\" | \"history\" | \"pending\">): string | null {\n for (let i = run.history.length - 1; i >= 0; i--) {\n const r = run.history[i].output?.result\n if (typeof r === \"string\" && r.trim().toLowerCase() === HAND_BACK_RESULT) return `step \"${run.history[i].nodeId}\" handed back`\n }\n if (run.status === \"completed\") return null\n // A run that ran out of steps without an end step stays \"running\".\n if (run.status === \"running\" && run.pending.length === 0) return null\n return `run ${run.status}`\n}\n\n/** The live run a pilot run belongs to. */\nexport function liveRunIdOf(run: Pick<WorkflowRun, \"parentRunId\" | \"context\">): string | null {\n if (run.parentRunId) return run.parentRunId\n for (const out of Object.values(run.context ?? {})) {\n const v = (out as Record<string, unknown>)?.liveRunId\n if (typeof v === \"string\" && v) return v\n }\n return null\n}\n\nexport interface SideSummary {\n runs: number\n failed: number\n totalCostUsd: number\n costPerRunUsd: number | null\n medianCostUsd: number | null\n}\n\nexport interface PilotPair {\n live: RunCost\n pilot: RunCost | null\n handedBack: string | null\n /** What the job would pay on the pilot path: pilot cost, plus the live\n * cost when the pilot handed the case back. */\n pilotPathCostUsd: number | null\n}\n\nexport interface PilotComparison {\n liveWorkflow: string\n pilotWorkflow: string\n /** Live runs that reached a model (runs that ended at a code step cost\n * nothing on either path and are left out). */\n live: SideSummary\n /** Paired runs only, so both sides cover the same cases. */\n paired: {\n runs: number\n handedBack: number\n handBackShare: number\n live: SideSummary\n pilotPath: SideSummary\n /** 1 - pilot path / live, over the paired runs. Null with no pairs. */\n saving: number | null\n }\n /** Live runs with no pilot run, and pilot runs with no live run. */\n unpairedLive: number\n orphanPilot: number\n /** Paired live runs whose pilot run has not ended yet: left out until\n * it does, so a run in progress is not read as a hand-back. */\n pilotInProgress: number\n /** Model calls priced at the fallback rate because no model was known\n * or the price table has no rate for it, out of all model calls counted,\n * per side. `noModel` counts those with no model on record at all;\n * `unpricedModels` names the models with no rate. */\n fallbackPriced: { live: number; pilot: number; calls: number; noModel: number; unpricedModels: string[] }\n pairs: PilotPair[]\n}\n\nfunction round(n: number): number {\n return Math.round(n * 1e6) / 1e6\n}\n\nfunction summarise(costs: number[], failed: number): SideSummary {\n const sorted = [...costs].sort((a, b) => a - b)\n const total = round(costs.reduce((s, c) => s + c, 0))\n const mid = sorted.length >> 1\n return {\n runs: costs.length,\n failed,\n totalCostUsd: total,\n costPerRunUsd: costs.length ? round(total / costs.length) : null,\n medianCostUsd: !sorted.length ? null : round(sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2),\n }\n}\n\nconst failedRun = (c: RunCost) => c.status === \"failed\" || c.status === \"canceled\" || c.failedCalls > 0\n\nexport function comparePilot(args: {\n liveWorkflow: string\n pilotWorkflow: string\n runs: WorkflowRun[]\n traces: TraceRecord[]\n pricing?: Pricing\n agentModels?: AgentModels\n}): PilotComparison {\n const pricing = args.pricing ?? CACHE_AWARE_PRICING\n const agentModels = args.agentModels ?? {}\n const liveRuns = args.runs\n .filter((r) => r.workflowId === args.liveWorkflow)\n .map((r) => runCost(r, args.traces, pricing, agentModels))\n .filter((c) => c.calls > 0)\n .sort((a, b) => a.startedAt.localeCompare(b.startedAt))\n const pilotRuns = args.runs.filter((r) => r.workflowId === args.pilotWorkflow)\n const pilotByLive = new Map<string, WorkflowRun>()\n let orphan = 0\n for (const p of pilotRuns) {\n const live = liveRunIdOf(p)\n if (!live || !liveRuns.some((l) => l.runId === live)) { orphan++; continue }\n // The first pilot run for a live run counts; a re-run does not.\n const prev = pilotByLive.get(live)\n if (!prev || p.createdAt < prev.createdAt) pilotByLive.set(live, p)\n }\n\n let inProgress = 0\n const pairs: PilotPair[] = liveRuns.map((live) => {\n const run = pilotByLive.get(live.runId)\n if (run && !runEnded(run)) inProgress++\n if (!run || !runEnded(run)) return { live, pilot: null, handedBack: null, pilotPathCostUsd: null }\n const pilot = runCost(run, args.traces, pricing, agentModels)\n const handedBack = handBackReason(run)\n return { live, pilot, handedBack, pilotPathCostUsd: round(pilot.costUsd + (handedBack ? live.costUsd : 0)) }\n })\n const paired = pairs.filter((p) => p.pilot)\n const pairedLive = summarise(paired.map((p) => p.live.costUsd), paired.filter((p) => failedRun(p.live)).length)\n // A hand-back is not an error: it is counted in the share and the cost.\n const pilotPath = summarise(paired.map((p) => p.pilotPathCostUsd as number), paired.filter((p) => !p.handedBack && failedRun(p.pilot!)).length)\n const handedBack = paired.filter((p) => p.handedBack).length\n return {\n liveWorkflow: args.liveWorkflow,\n pilotWorkflow: args.pilotWorkflow,\n live: summarise(liveRuns.map((c) => c.costUsd), liveRuns.filter(failedRun).length),\n paired: {\n runs: paired.length,\n handedBack,\n handBackShare: paired.length ? handedBack / paired.length : 0,\n live: pairedLive,\n pilotPath,\n saving: paired.length && pairedLive.totalCostUsd > 0 ? round(1 - pilotPath.totalCostUsd / pairedLive.totalCostUsd) : null,\n },\n unpairedLive: liveRuns.length - paired.length - inProgress,\n orphanPilot: orphan,\n pilotInProgress: inProgress,\n fallbackPriced: {\n live: liveRuns.reduce((s, c) => s + c.fallbackPricedCalls, 0),\n pilot: paired.reduce((s, p) => s + p.pilot!.fallbackPricedCalls, 0),\n calls: liveRuns.reduce((s, c) => s + c.calls, 0) + paired.reduce((s, p) => s + p.pilot!.calls, 0),\n noModel: liveRuns.reduce((s, c) => s + c.noModelCalls, 0) + paired.reduce((s, p) => s + p.pilot!.noModelCalls, 0),\n unpricedModels: [...new Set([...liveRuns, ...paired.map((p) => p.pilot!)].flatMap((c) => c.unpricedModels))].sort(),\n },\n pairs,\n }\n}\n"],"mappings":"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","names":["HAND_BACK_RESULT","FALLBACK_PRICING_MODEL","traceModel","t","agentModels","isPricedModel","model","pricing","CACHE_AWARE_PRICING","getModelFamily","traceCostUsd","TokenTracker","isModelCall","runCost","run","traces","mine","models","cost","s","i","round","m","runEnded","handBackReason","liveRunIdOf","out","v","n","summarise","costs","failed","sorted","b","total","c","mid","failedRun","comparePilot","args","liveRuns","r","a","pilotRuns","pilotByLive","orphan","p","live","l","prev","inProgress","pairs","pilot","handedBack","paired","pairedLive","pilotPath"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentix-cli",
3
- "version": "0.143.0",
3
+ "version": "0.144.0",
4
4
  "description": "The self-hosted agent harness for small teams. Runs a team of AI agents across Telegram, WhatsApp, GitLab, GitHub, crons, webhooks and mesh tasks, on Claude Code, Codex, OpenCode or any LLM API. Web wizard for operators, CLI for engineers.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -1,11 +0,0 @@
1
- import{a as w,b as f}from"./chunk-SHEUCITK.js";import{randomUUID as k}from"crypto";function p(r){return r.status&&r.status!=="ringing"?", waiting_since=NULL, told_at=NULL":""}var E=["ringing","answered","later"],A=`id, agent_id AS agentId, kind, reason, urgency, status, created_at AS createdAt,
2
- ringing_since AS ringingSince, answered_at AS answeredAt, ended_at AS endedAt,
3
- ring_again_at AS ringAgainAt, note, summary, channel, chat_id AS chatId`,y=class{constructor(t){this.db=t;t.exec(`CREATE TABLE IF NOT EXISTS calls (
4
- id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, reason TEXT NOT NULL,
5
- urgency TEXT NOT NULL, status TEXT NOT NULL, created_at INTEGER NOT NULL,
6
- ringing_since INTEGER, answered_at INTEGER, ended_at INTEGER,
7
- ring_again_at INTEGER, note TEXT, summary TEXT);
8
- CREATE INDEX IF NOT EXISTS calls_recent ON calls(created_at DESC);`);let e=new Set(t.prepare("PRAGMA table_info(calls)").all().map(n=>n.name));e.has("kind")||t.exec("ALTER TABLE calls ADD COLUMN kind TEXT NOT NULL DEFAULT 'voice'"),e.has("channel")||t.exec("ALTER TABLE calls ADD COLUMN channel TEXT"),e.has("chat_id")||t.exec("ALTER TABLE calls ADD COLUMN chat_id TEXT"),e.has("waiting_since")||t.exec("ALTER TABLE calls ADD COLUMN waiting_since INTEGER"),e.has("told_at")||t.exec("ALTER TABLE calls ADD COLUMN told_at INTEGER")}waiting(){let t=this.db.prepare("SELECT id, waiting_since AS since, told_at AS toldAt FROM calls WHERE waiting_since IS NOT NULL AND status='ringing'").all();return new Map(t.map(({id:e,since:n,toldAt:i})=>[e,{since:n,toldAt:i??n}]))}setWaiting(t,e){this.db.prepare("UPDATE calls SET waiting_since=?, told_at=? WHERE id=?").run(e?.since??null,e?.toldAt??null,t)}insert(t){this.db.prepare(`INSERT INTO calls (id, agent_id, kind, reason, urgency, status, created_at, ringing_since,
9
- answered_at, ended_at, ring_again_at, note, summary, channel, chat_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(t.id,t.agentId,t.kind,t.reason,t.urgency,t.status,t.createdAt,t.ringingSince,t.answeredAt,t.endedAt,t.ringAgainAt,t.note,t.summary,t.channel,t.chatId)}get(t){return this.db.prepare(`SELECT ${A} FROM calls WHERE id=?`).get(t)}update(t,e){let n={reason:"reason",urgency:"urgency",status:"status",ringingSince:"ringing_since",answeredAt:"answered_at",endedAt:"ended_at",ringAgainAt:"ring_again_at",note:"note",summary:"summary"},i=Object.keys(e).filter(a=>a in n);if(i.length){let a=i.map(s=>`${n[s]}=?`).join(", ")+p(e);this.db.prepare(`UPDATE calls SET ${a} WHERE id=?`).run(...i.map(s=>e[s]??null),t)}return this.get(t)}transition(t,e,n){let i=Array.isArray(e)?e:[e],a={status:"status",ringingSince:"ringing_since",answeredAt:"answered_at",endedAt:"ended_at",ringAgainAt:"ring_again_at",note:"note",summary:"summary"},s=Object.keys(n).filter(l=>l in a),o=s.map(l=>`${a[l]}=?`).join(", ")+p(n),u=i.map(()=>"?").join(",");return this.db.prepare(`UPDATE calls SET ${o} WHERE id=? AND status IN (${u})`).run(...s.map(l=>n[l]??null),t,...i).changes?this.get(t):void 0}list(t={}){let e=Math.min(Math.max(t.limit??50,1),200),n=[],i=[];t.status?.length&&(n.push(`status IN (${t.status.map(()=>"?").join(",")})`),i.push(...t.status)),t.kind&&(n.push("kind=?"),i.push(t.kind));let a=n.length?`WHERE ${n.join(" AND ")}`:"";return this.db.prepare(`SELECT ${A} FROM calls ${a} ORDER BY created_at DESC, rowid DESC LIMIT ?`).all(...i,e)}countSince(t,e){return this.db.prepare("SELECT COUNT(*) AS n FROM calls WHERE agent_id=? AND created_at>?").get(t,e).n}};var T=200,_=1e4,I=10,C=240;function x(r=process.env){return r.AGENTX_TASK_ID?{"X-AgentX-Task":r.AGENTX_TASK_ID}:r.AGENTX_CHANNEL&&r.AGENTX_CHAT_ID?{"X-AgentX-Channel":r.AGENTX_CHANNEL,"X-AgentX-Chat":r.AGENTX_CHAT_ID}:{}}function $(r){return`[Call answered] The owner just picked up the voice call you asked for. You called because: "${r.reason}". Speak first: greet them in a few words and say why you called, then let them answer.`}var D="[Call ended] The owner hung up. In two or three plain sentences, summarise what was said and decided on this call, for your records. Reply with the summary only.",S=class{constructor(t){this.deps=t;this.waiting=t.store.waiting()}widgetSeenAt=0;widget={};waiting;setWaiting(t,e){if(e)this.waiting.set(t,e);else if(!this.waiting.delete(t))return;this.deps.store.setWaiting(t,e)}now(){return this.deps.now?.()??Date.now()}name(t){return this.deps.agentName(t)??t}async request(t,e={}){let n=String(t.agentId??"").trim(),i=String(t.reason??"").replace(/\s+/g," ").trim(),a=t.urgency==="urgent"?"urgent":"normal",s=t.kind==="camera"?"camera":"voice";if(t.kind!==void 0&&t.kind!=="voice"&&t.kind!=="camera")return{ok:!1,status:400,error:"kind must be voice or camera"};if(!n||!i)return{ok:!1,status:400,error:"Required: agentId and reason"};if(i.length>T)return{ok:!1,status:413,error:`reason is over ${T} characters; keep it to one line`};if(this.deps.agentName(n)===null)return{ok:!1,status:404,error:`Unknown agent: ${n}`};if(!this.deps.isRunningTurn(n,e))return{ok:!1,status:403,error:`No running turn of ${n} placed this call. An agent calls from inside its own run.`};let o=this.deps.config();if(!o.allow.includes("*")&&!o.allow.includes(n))return{ok:!1,status:403,error:`${n} ${s==="camera"?"may not ask to see through the owner's camera":"may not call the owner"}. Add it to calls.allow in agentx.json (or: agentx call allow ${n}).`};if(await this.sweep(),this.deps.store.list({status:E,limit:200}).some(m=>m.agentId===n))return{ok:!1,status:409,error:`${n} already has a call in progress`};let u=this.now();if(this.deps.store.countSince(n,u-36e5)>=o.maxPerHour)return{ok:!1,status:429,error:`${n} has placed ${o.maxPerHour} calls in the last hour (calls.maxPerHour)`};let g=s==="camera"?this.deps.turnSession?.(n,e)??e:{},l={id:`call-${k().slice(0,8)}`,agentId:n,kind:s,reason:i,urgency:a,status:"ringing",createdAt:u,ringingSince:u,answeredAt:null,endedAt:null,ringAgainAt:null,note:null,summary:null,channel:g.channel&&g.chatId?g.channel:null,chatId:g.channel&&g.chatId?g.chatId:null};this.deps.store.insert(l),this.deps.log?.(`[calls] ${n} asks ${s==="camera"?"to see":"for a call"} (${a}): ${i}`);let d=await this.ring(l),h=this.deps.store.get(l.id);return d!=="waiting"?{ok:!0,call:h,rang:d}:this.waiting.has(l.id)?{ok:!0,call:h,rang:d,busy:this.busyInfo(l)}:{ok:!0,call:h,rang:"widget"}}async cancel(t,e={}){let n=String(t.agentId??"").trim();if(!n)return{ok:!1,status:400,error:"Required: agentId"};if(!this.deps.isRunningTurn(n,e))return{ok:!1,status:403,error:`No running turn of ${n} asked for this. An agent withdraws its own call from inside its run.`};let i=this.deps.store.list({status:["ringing","later"],kind:"voice",limit:200}).find(s=>s.agentId===n);if(!i)return{ok:!1,status:404,error:`${n} has no call waiting or ringing`};let a=this.deps.store.transition(i.id,["ringing","later"],{status:"ended",endedAt:this.now(),ringingSince:null,ringAgainAt:null,note:N});return a?(this.setWaiting(i.id,null),this.deps.log?.(`[calls] ${i.id} withdrawn by ${n}`),{ok:!0,call:a}):{ok:!1,status:409,error:`call is ${this.deps.store.get(i.id)?.status}`}}async ring(t){let e=(this.deps.focus??w)();return e.active&&t.urgency!=="urgent"?(this.deps.store.transition(t.id,"ringing",{status:"missed",ringingSince:null,note:f(e)})&&await this.notice(t,this.missedTitle(t)),!1):t.kind==="camera"?(await this.notice(t,`${this.name(t.agentId)} wants to see through your camera`,`Open the phone app and tap Show within ${this.deps.config().ringSeconds} s.`),"notify"):this.widgetAlive()?!this.widget.busy&&!this.otherCalls(t).length?"widget":(this.startWaiting(t),await this.callWaiting(t),"waiting"):(await this.notice(t,`${this.name(t.agentId)} is calling`,`Open AgentX Voice to answer within ${this.deps.config().ringSeconds} s.`),"notify")}async notice(t,e,n){try{await this.deps.alert({title:e,message:n?`${t.reason}
10
- ${n}`:t.reason,urgent:t.urgency==="urgent",from:t.agentId})}catch(i){this.deps.log?.(`[calls] notice for ${t.id} failed: ${i?.message??i}`)}}startWaiting(t){let e=this.now();this.setWaiting(t.id,{since:e,toldAt:e}),this.deps.log?.(`[calls] ${t.id} from ${t.agentId} waits: the widget is busy`)}otherCalls(t){return this.deps.store.list({status:["ringing","answered"],kind:"voice",limit:200}).filter(e=>e.id!==t.id).reverse()}async callWaiting(t){let e=this.deps.config().busy;await this.notice(t,e.title.replaceAll("{agent}",this.name(t.agentId)),e.notice)}busyInfo(t){let e=this.deps.config().busy,{since:n,toldAt:i}=this.waiting.get(t.id)??{since:this.now(),toldAt:this.now()},a=this.otherCalls(t),s=a.find(d=>d.status==="answered"),o=a.find(d=>d.id===this.widget.showing)??a.find(d=>!this.waiting.has(d.id)),u=n+e.maxWaitMinutes*6e4+this.deps.config().ringSeconds*1e3,g=i+e.retryMinutes*6e4,l=n+e.maxWaitMinutes*6e4;return{why:s?"call":o?"ringing":"voice",with:s?this.name(s.agentId):o?this.name(o.agentId):null,remindAt:g<l?g:null,waitsUntil:u}}missedTitle(t){return t.kind==="camera"?`${this.name(t.agentId)} asked to see through your camera`:`Missed call from ${this.name(t.agentId)}`}widgetAlive(){return this.now()-this.widgetSeenAt<_}async ringing(t={}){return this.widgetSeenAt=this.now(),this.widget=t,await this.hold(t),await this.sweep(),this.deps.store.list({status:["ringing"],kind:"voice",limit:20}).reverse()}async hold(t){let e=this.now(),n=this.deps.config().busy,i=[],a=this.deps.store.list({status:["ringing"],kind:"voice",limit:20});for(let s of[...this.waiting.keys()])a.some(o=>o.id===s)||this.setWaiting(s,null);for(let s of a){if(s.id===t.showing){this.waiting.has(s.id)&&(this.setWaiting(s.id,null),this.deps.store.transition(s.id,"ringing",{ringingSince:e}));continue}if(!t.busy)continue;let o=this.waiting.get(s.id);if(!(o&&e-o.since>=n.maxWaitMinutes*6e4)&&this.deps.store.transition(s.id,"ringing",{ringingSince:e})){if(!o)this.startWaiting(s);else if(e-o.toldAt>=n.retryMinutes*6e4)this.setWaiting(s.id,{since:o.since,toldAt:e});else continue;i.push(s)}}for(let s of i)await this.callWaiting(s)}async asking(){return await this.sweep(),this.deps.store.list({status:["ringing"],kind:"camera",limit:20}).reverse()}async sweep(){let t=this.now(),e=this.deps.config().ringSeconds*1e3,n=this.deps.config().maxCallMinutes*6e4;for(let i of this.deps.store.list({status:["ringing","later","answered"],limit:200}))if(i.status==="ringing"&&i.ringingSince!==null&&t-i.ringingSince>=e){if(!this.deps.store.transition(i.id,"ringing",{status:"missed",ringingSince:null,note:this.waiting.has(i.id)?"widget busy":"not answered"}))continue;this.deps.log?.(`[calls] ${i.id} from ${i.agentId} missed`),await this.notice(i,this.missedTitle(i))}else if(i.status==="answered"&&i.answeredAt!==null&&t-i.answeredAt>=n){if(!this.deps.store.transition(i.id,"answered",{status:"ended",endedAt:t,note:"no hang-up"}))continue;this.deps.log?.(`[calls] ${i.id} from ${i.agentId} ended: no hang-up in ${this.deps.config().maxCallMinutes} min`)}else if(i.status==="later"&&i.ringAgainAt!==null&&t>=i.ringAgainAt){let a=this.deps.store.transition(i.id,"later",{status:"ringing",ringingSince:t,ringAgainAt:null});if(!a)continue;this.setWaiting(i.id,null),await this.ring(a)}}answer(t){let e=this.deps.store.get(t);if(!e)return c(t);let n=this.deps.store.transition(t,"ringing",{status:"answered",answeredAt:this.now(),ringingSince:null});return n?(this.deps.log?.(`[calls] ${t} answered (${e.agentId})`),n.kind==="camera"?{ok:!0,call:n}:{ok:!0,call:n,opener:$(n)}):{ok:!1,status:409,error:`call is ${this.deps.store.get(t)?.status}, not ringing`}}decline(t){if(!this.deps.store.get(t))return c(t);let n=this.deps.store.transition(t,["ringing","later"],{status:"declined",endedAt:this.now(),ringingSince:null,ringAgainAt:null});return n?{ok:!0,call:n}:{ok:!1,status:409,error:`call is ${this.deps.store.get(t)?.status}`}}later(t,e){if(!this.deps.store.get(t))return c(t);let i=e===void 0?I:Number(e);if(!Number.isInteger(i)||i<1||i>C)return{ok:!1,status:400,error:`minutes must be a whole number from 1 to ${C}`};let a=this.deps.store.transition(t,"ringing",{status:"later",ringingSince:null,ringAgainAt:this.now()+i*6e4});return a?{ok:!0,call:a}:{ok:!1,status:409,error:`call is ${this.deps.store.get(t)?.status}, not ringing`}}hangup(t){let e=this.deps.store.get(t);if(!e)return c(t);let n=this.deps.store.transition(t,"answered",{status:"ended",endedAt:this.now()});if(!n)return{ok:!1,status:409,error:`call is ${e.status}, not answered`};this.deps.log?.(`[calls] ${t} ended (${e.agentId})`);let i=this.deps.summarize;if(n.kind==="camera"||!this.deps.config().summary||!i)return{ok:!0,call:n};let a=(async()=>{try{let s=(await i(n))?.trim();if(!s)return;let o=this.deps.store.update(t,{summary:s});this.deps.file?.(o,s)}catch(s){this.deps.log?.(`[calls] summary for ${t} failed: ${s?.message??s}`)}})();return{ok:!0,call:n,summarized:a}}endCamera(t,e){let n=this.deps.store.get(t);if(!n||n.kind!=="camera")return!1;let i=this.deps.store.transition(t,"answered",{status:"ended",endedAt:this.now(),note:e??null});return i&&this.deps.log?.(`[calls] ${t} ended (${n.agentId}): ${e??"share over"}`),!!i}get(t){return this.deps.store.get(t)}list(t={}){return this.deps.store.list(t)}},N="withdrawn by the caller";function W(r,t=Date.now(),e){let n=a=>`${new Date(a).toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",hour12:!1,timeZoneName:"short",timeZone:e})} (in ${Math.max(1,Math.round((a-t)/6e4))} min)`;return`${r.why==="call"?`The owner is busy in another call${r.with?` (with ${r.with})`:""}.`:r.why==="ringing"?`The owner is busy: another call${r.with?` (from ${r.with})`:""} is ringing.`:"The owner is busy on the voice widget."} They were told you are calling, and why. Your call waits and rings by itself as soon as they are free: do not call again. `+(r.remindAt!==null?`Still busy at ${n(r.remindAt)}, they are told again that you are waiting. `:"")+`It waits until ${n(r.waitsUntil)} at most, then counts as a missed call.`}var c=r=>({ok:!1,status:404,error:`No such call: ${r}`});export{y as a,x as b,D as c,S as d,W as e};
11
- //# sourceMappingURL=chunk-3W2BHUGM.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/calls/service.ts","../src/calls/store.ts"],"sourcesContent":["// --- An agent rings the owner (#321) ---\n//\n// An agent that needs the owner directly asks for a call. It rings on the\n// desktop widget (AgentX Voice), which polls `ringing()`. Answering starts\n// the widget's hands-free conversation with that agent, which opens with\n// its reason. When the widget is not running, `notify` stands in. While\n// the widget is busy (a turn, the microphone, another call) the call waits\n// for it: its ring time does not run, and the owner gets a call-waiting\n// notice (#408), again every calls.busy.retryMinutes. The caller is told\n// the owner is busy, with whom, and until when its call waits (#969). It\n// rings by itself once the widget is free, oldest first; the caller may\n// withdraw it meanwhile (`cancel`).\n//\n// Checked before anything rings, in this order:\n// 0. the caller is that agent: a turn of it is running now, named by its\n// task id or by its channel and chat (see CallerProof),\n// 1. the owner allows this agent (calls.allow; empty allows nobody),\n// 2. the agent has no other call in progress,\n// 3. it is under calls.maxPerHour,\n// 4. Focus: a non-urgent call does not ring. It becomes a missed call,\n// and its notice goes through notify, which holds it until Focus\n// ends. Urgent calls ring through, as `notify --urgent` does.\n//\n// A camera ask (#325 phase 3, kind \"camera\") goes through the same checks\n// and the same table. It never rings the widget: the notice goes to the\n// phone through notify, and the phone app polls `asking()` to show a\n// Show / Decline bar. Answering it is the owner tapping Show; the camera\n// opens only then, and the share ends the ask (see camera-api.ts).\n\nimport { randomUUID } from \"crypto\"\nimport { focusLabel, readFocus, type FocusState } from \"@/notify/focus\"\nimport type { CallsConfig } from \"@/daemon/config\"\nimport { LIVE, type Call, type CallKind, type CallStore, type CallUrgency, type Waiting } from \"./store\"\n\nexport const REASON_MAX = 200\n/** The widget polls every 2 s; missing this long means it is not running. */\nexport const WIDGET_FRESH_MS = 10_000\nexport const LATER_DEFAULT_MINUTES = 10\nexport const LATER_MAX_MINUTES = 240\n\n/** What a caller is told when the owner cannot take its call now (#969). */\nexport interface BusyInfo {\n /** \"call\": the owner is in a call; \"ringing\": another call is ringing;\n * \"voice\": AgentX Voice is in a turn of the owner's, or recording. */\n why: \"call\" | \"ringing\" | \"voice\"\n /** The agent the owner is in a call with, or whose call is ringing. */\n with: string | null\n /** When the owner is told again that this call waits, if still busy\n * then; null when the wait ends first. Ms since the epoch. */\n remindAt: number | null\n /** The call stops waiting then: still busy, it counts as missed. */\n waitsUntil: number\n}\n\nexport type CallResult =\n | { ok: true; call: Call }\n | { ok: false; status: number; error: string }\n\n/** What the request says about the turn placing it: the run's\n * AGENTX_TASK_ID, or, for a warm process that has none, its\n * AGENTX_CHANNEL and AGENTX_CHAT_ID. Loopback is not an identity. */\nexport interface CallerProof {\n taskId?: string\n channel?: string\n chatId?: string\n}\n\n/** The proof headers for a call placed from inside an agent's run. */\nexport function callerHeaders(env: NodeJS.ProcessEnv = process.env): Record<string, string> {\n if (env.AGENTX_TASK_ID) return { \"X-AgentX-Task\": env.AGENTX_TASK_ID }\n if (env.AGENTX_CHANNEL && env.AGENTX_CHAT_ID) {\n return { \"X-AgentX-Channel\": env.AGENTX_CHANNEL, \"X-AgentX-Chat\": env.AGENTX_CHAT_ID }\n }\n return {}\n}\n\n/** What the widget says with its poll. A widget from before #408 says nothing. */\nexport interface WidgetState {\n /** It cannot ring a new call now. */\n busy?: boolean\n /** The call ringing on it. */\n showing?: string\n}\n\nexport interface CallDeps {\n store: CallStore\n config: () => CallsConfig\n /** The agent's display name, or null when there is no such agent here. */\n agentName: (agentId: string) => string | null\n /** True when `proof` names a running turn of `agentId`. */\n isRunningTurn: (agentId: string, proof: CallerProof) => boolean\n /** The channel and chat of that running turn, when it has one, so a\n * camera ask is answered where it was asked. Unset: only a proof that\n * names them itself is kept. */\n turnSession?: (agentId: string, proof: CallerProof) => { channel?: string; chatId?: string } | null\n /** Tell the owner through notify. `urgent` passes Focus, like notify --urgent. */\n alert: (notice: { title: string; message: string; urgent: boolean; from: string }) => Promise<void>\n /** Ask the agent, in its voice session, to summarise the call. */\n summarize?: (call: Call) => Promise<string | null>\n /** File a finished summary where the dashboard shows it. */\n file?: (call: Call, summary: string) => void\n focus?: () => FocusState\n now?: () => number\n log?: (m: string) => void\n}\n\n/** What the widget sends through /ask when the owner answers, so the\n * agent speaks first and says why it called. */\nexport function openerPrompt(call: Pick<Call, \"reason\">): string {\n return \"[Call answered] The owner just picked up the voice call you asked for. \" +\n `You called because: \"${call.reason}\". Speak first: greet them in a few words ` +\n \"and say why you called, then let them answer.\"\n}\n\nexport const SUMMARY_PROMPT =\n \"[Call ended] The owner hung up. In two or three plain sentences, summarise what \" +\n \"was said and decided on this call, for your records. Reply with the summary only.\"\n\nexport class CallService {\n private widgetSeenAt = 0\n /** What the widget said with its last poll. */\n private widget: WidgetState = {}\n /** Calls waiting for a busy widget: since when, and when the owner was\n * last told. Written through to the store, so a restart keeps them. */\n private waiting: Map<string, Waiting>\n\n constructor(private deps: CallDeps) {\n this.waiting = deps.store.waiting()\n }\n\n private setWaiting(id: string, w: Waiting | null): void {\n if (w) this.waiting.set(id, w)\n else if (!this.waiting.delete(id)) return\n this.deps.store.setWaiting(id, w)\n }\n\n private now(): number { return this.deps.now?.() ?? Date.now() }\n private name(agentId: string): string { return this.deps.agentName(agentId) ?? agentId }\n\n /** An agent asks for a call, or to see (kind \"camera\"). 201 ringing, or\n * waiting for a busy owner (`rang: \"waiting\"`, with `busy`); 202 held\n * as missed (Focus). */\n async request(input: { agentId?: unknown; reason?: unknown; urgency?: unknown; kind?: unknown }, proof: CallerProof = {}): Promise<CallResult & { rang?: Rang; busy?: BusyInfo }> {\n const agentId = String(input.agentId ?? \"\").trim()\n const reason = String(input.reason ?? \"\").replace(/\\s+/g, \" \").trim()\n const urgency: CallUrgency = input.urgency === \"urgent\" ? \"urgent\" : \"normal\"\n const kind: CallKind = input.kind === \"camera\" ? \"camera\" : \"voice\"\n if (input.kind !== undefined && input.kind !== \"voice\" && input.kind !== \"camera\") return { ok: false, status: 400, error: \"kind must be voice or camera\" }\n if (!agentId || !reason) return { ok: false, status: 400, error: \"Required: agentId and reason\" }\n if (reason.length > REASON_MAX) return { ok: false, status: 413, error: `reason is over ${REASON_MAX} characters; keep it to one line` }\n if (this.deps.agentName(agentId) === null) return { ok: false, status: 404, error: `Unknown agent: ${agentId}` }\n if (!this.deps.isRunningTurn(agentId, proof)) {\n return { ok: false, status: 403, error: `No running turn of ${agentId} placed this call. An agent calls from inside its own run.` }\n }\n\n const cfg = this.deps.config()\n if (!cfg.allow.includes(\"*\") && !cfg.allow.includes(agentId)) {\n const verb = kind === \"camera\" ? \"may not ask to see through the owner's camera\" : \"may not call the owner\"\n return { ok: false, status: 403, error: `${agentId} ${verb}. Add it to calls.allow in agentx.json (or: agentx call allow ${agentId}).` }\n }\n await this.sweep()\n if (this.deps.store.list({ status: LIVE, limit: 200 }).some((c) => c.agentId === agentId)) {\n return { ok: false, status: 409, error: `${agentId} already has a call in progress` }\n }\n const now = this.now()\n if (this.deps.store.countSince(agentId, now - 3_600_000) >= cfg.maxPerHour) {\n return { ok: false, status: 429, error: `${agentId} has placed ${cfg.maxPerHour} calls in the last hour (calls.maxPerHour)` }\n }\n\n // Where the ask came from, for kind \"camera\": the turn's own chat, or\n // the one the proof names. A task run has neither.\n const session: { channel?: string; chatId?: string } = kind === \"camera\" ? (this.deps.turnSession?.(agentId, proof) ?? proof) : {}\n const call: Call = {\n id: `call-${randomUUID().slice(0, 8)}`, agentId, kind, reason, urgency, status: \"ringing\", createdAt: now,\n ringingSince: now, answeredAt: null, endedAt: null, ringAgainAt: null, note: null, summary: null,\n channel: session.channel && session.chatId ? session.channel : null,\n chatId: session.channel && session.chatId ? session.chatId : null,\n }\n this.deps.store.insert(call)\n this.deps.log?.(`[calls] ${agentId} asks ${kind === \"camera\" ? \"to see\" : \"for a call\"} (${urgency}): ${reason}`)\n const rang = await this.ring(call)\n const saved = this.deps.store.get(call.id)!\n if (rang !== \"waiting\") return { ok: true, call: saved, rang }\n // The widget may have come free while the owner was being told.\n return this.waiting.has(call.id) ? { ok: true, call: saved, rang, busy: this.busyInfo(call) } : { ok: true, call: saved, rang: \"widget\" }\n }\n\n /** The caller withdraws its own voice call while it waits or rings, for\n * example to send a message instead (#969). */\n async cancel(input: { agentId?: unknown }, proof: CallerProof = {}): Promise<CallResult> {\n const agentId = String(input.agentId ?? \"\").trim()\n if (!agentId) return { ok: false, status: 400, error: \"Required: agentId\" }\n if (!this.deps.isRunningTurn(agentId, proof)) {\n return { ok: false, status: 403, error: `No running turn of ${agentId} asked for this. An agent withdraws its own call from inside its run.` }\n }\n // No sweep first: a call back that is due must not ring just to be withdrawn.\n const mine = this.deps.store.list({ status: [\"ringing\", \"later\"], kind: \"voice\", limit: 200 }).find((c) => c.agentId === agentId)\n if (!mine) return { ok: false, status: 404, error: `${agentId} has no call waiting or ringing` }\n const ended = this.deps.store.transition(mine.id, [\"ringing\", \"later\"], { status: \"ended\", endedAt: this.now(), ringingSince: null, ringAgainAt: null, note: CANCELLED_NOTE })\n if (!ended) return { ok: false, status: 409, error: `call is ${this.deps.store.get(mine.id)?.status}` }\n this.setWaiting(mine.id, null)\n this.deps.log?.(`[calls] ${mine.id} withdrawn by ${agentId}`)\n return { ok: true, call: ended }\n }\n\n /** Ring now, wait for a busy widget, or hold as missed in Focus.\n * Returns how it rang. */\n private async ring(call: Call): Promise<Rang> {\n const focus = (this.deps.focus ?? readFocus)()\n if (focus.active && call.urgency !== \"urgent\") {\n if (!this.deps.store.transition(call.id, \"ringing\", { status: \"missed\", ringingSince: null, note: focusLabel(focus) })) return false\n await this.notice(call, this.missedTitle(call))\n return false\n }\n // A camera ask is answered on the phone, never on the widget.\n if (call.kind === \"camera\") {\n await this.notice(call, `${this.name(call.agentId)} wants to see through your camera`,\n `Open the phone app and tap Show within ${this.deps.config().ringSeconds} s.`)\n return \"notify\"\n }\n if (this.widgetAlive()) {\n // Busy by its last poll, or by a call placed since that it will show first.\n if (!this.widget.busy && !this.otherCalls(call).length) return \"widget\"\n this.startWaiting(call)\n await this.callWaiting(call)\n return \"waiting\"\n }\n await this.notice(call, `${this.name(call.agentId)} is calling`,\n `Open AgentX Voice to answer within ${this.deps.config().ringSeconds} s.`)\n return \"notify\"\n }\n\n private async notice(call: Call, title: string, extra?: string): Promise<void> {\n try {\n await this.deps.alert({\n title, message: extra ? `${call.reason}\\n${extra}` : call.reason,\n urgent: call.urgency === \"urgent\", from: call.agentId,\n })\n } catch (e: any) {\n this.deps.log?.(`[calls] notice for ${call.id} failed: ${e?.message ?? e}`)\n }\n }\n\n /** The call starts waiting for the busy widget. */\n private startWaiting(call: Call): void {\n const now = this.now()\n this.setWaiting(call.id, { since: now, toldAt: now })\n this.deps.log?.(`[calls] ${call.id} from ${call.agentId} waits: the widget is busy`)\n }\n\n /** Voice calls ringing or answered other than `call`, oldest first. */\n private otherCalls(call: Call): Call[] {\n return this.deps.store.list({ status: [\"ringing\", \"answered\"], kind: \"voice\", limit: 200 }).filter((c) => c.id !== call.id).reverse()\n }\n\n private async callWaiting(call: Call): Promise<void> {\n const busy = this.deps.config().busy\n await this.notice(call, busy.title.replaceAll(\"{agent}\", this.name(call.agentId)), busy.notice)\n }\n\n /** Why the owner cannot take `call` now, and how long it waits. */\n private busyInfo(call: Call): BusyInfo {\n const cfg = this.deps.config().busy\n const { since, toldAt } = this.waiting.get(call.id) ?? { since: this.now(), toldAt: this.now() }\n const others = this.otherCalls(call)\n const talking = others.find((c) => c.status === \"answered\")\n // The call on the pill, or the oldest one it has yet to show.\n const showing = others.find((c) => c.id === this.widget.showing) ?? others.find((c) => !this.waiting.has(c.id))\n // After the wait the ring time runs once more before it is missed.\n const waitsUntil = since + cfg.maxWaitMinutes * 60_000 + this.deps.config().ringSeconds * 1000\n const remindAt = toldAt + cfg.retryMinutes * 60_000\n const stopsWaiting = since + cfg.maxWaitMinutes * 60_000\n return {\n why: talking ? \"call\" : showing ? \"ringing\" : \"voice\",\n with: talking ? this.name(talking.agentId) : showing ? this.name(showing.agentId) : null,\n remindAt: remindAt < stopsWaiting ? remindAt : null,\n waitsUntil,\n }\n }\n\n private missedTitle(call: Call): string {\n return call.kind === \"camera\" ? `${this.name(call.agentId)} asked to see through your camera` : `Missed call from ${this.name(call.agentId)}`\n }\n\n /** True when the widget polled recently. */\n widgetAlive(): boolean {\n return this.now() - this.widgetSeenAt < WIDGET_FRESH_MS\n }\n\n /** The widget's poll: voice calls ringing now, oldest first. Marks it alive. */\n async ringing(widget: WidgetState = {}): Promise<Call[]> {\n this.widgetSeenAt = this.now()\n this.widget = widget\n await this.hold(widget)\n await this.sweep()\n return this.deps.store.list({ status: [\"ringing\"], kind: \"voice\", limit: 20 }).reverse()\n }\n\n /** A busy widget cannot ring: the ring time of each call it is not\n * showing starts over at every poll, for calls.busy.maxWaitMinutes at\n * most. The owner is told that the call waits, and again every\n * calls.busy.retryMinutes. The ring time starts over once more when the\n * widget first shows a call that waited. */\n private async hold(widget: WidgetState): Promise<void> {\n const now = this.now()\n const busy = this.deps.config().busy\n // Told after the loop: a poll that overlaps a slow notice must not\n // carry on from a list and a widget state that are out of date.\n const tell: Call[] = []\n const live = this.deps.store.list({ status: [\"ringing\"], kind: \"voice\", limit: 20 })\n for (const id of [...this.waiting.keys()]) if (!live.some((c) => c.id === id)) this.setWaiting(id, null)\n for (const call of live) {\n if (call.id === widget.showing) {\n if (this.waiting.has(call.id)) {\n this.setWaiting(call.id, null)\n this.deps.store.transition(call.id, \"ringing\", { ringingSince: now })\n }\n continue\n }\n if (!widget.busy) continue\n const held = this.waiting.get(call.id)\n if (held && now - held.since >= busy.maxWaitMinutes * 60_000) continue\n if (!this.deps.store.transition(call.id, \"ringing\", { ringingSince: now })) continue\n if (!held) this.startWaiting(call)\n else if (now - held.toldAt >= busy.retryMinutes * 60_000) this.setWaiting(call.id, { since: held.since, toldAt: now })\n else continue\n tell.push(call)\n }\n for (const call of tell) await this.callWaiting(call)\n }\n\n /** The phone app's poll: camera asks waiting for the owner, oldest first.\n * Does not count as the widget being up. */\n async asking(): Promise<Call[]> {\n await this.sweep()\n return this.deps.store.list({ status: [\"ringing\"], kind: \"camera\", limit: 20 }).reverse()\n }\n\n /** Unanswered calls become missed; \"later\" calls that came due ring\n * again; answered calls nobody hung up end after calls.maxCallMinutes. */\n async sweep(): Promise<void> {\n const now = this.now()\n const ringFor = this.deps.config().ringSeconds * 1000\n const talkFor = this.deps.config().maxCallMinutes * 60_000\n for (const call of this.deps.store.list({ status: [\"ringing\", \"later\", \"answered\"], limit: 200 })) {\n // The list was read before any await below: each move re-checks the\n // status in the store, so a call answered meanwhile is left alone.\n if (call.status === \"ringing\" && call.ringingSince !== null && now - call.ringingSince >= ringFor) {\n if (!this.deps.store.transition(call.id, \"ringing\", { status: \"missed\", ringingSince: null, note: this.waiting.has(call.id) ? \"widget busy\" : \"not answered\" })) continue\n this.deps.log?.(`[calls] ${call.id} from ${call.agentId} missed`)\n await this.notice(call, this.missedTitle(call))\n } else if (call.status === \"answered\" && call.answeredAt !== null && now - call.answeredAt >= talkFor) {\n if (!this.deps.store.transition(call.id, \"answered\", { status: \"ended\", endedAt: now, note: \"no hang-up\" })) continue\n this.deps.log?.(`[calls] ${call.id} from ${call.agentId} ended: no hang-up in ${this.deps.config().maxCallMinutes} min`)\n } else if (call.status === \"later\" && call.ringAgainAt !== null && now >= call.ringAgainAt) {\n const again = this.deps.store.transition(call.id, \"later\", { status: \"ringing\", ringingSince: now, ringAgainAt: null })\n if (!again) continue\n // A wait from before the snooze does not carry over.\n this.setWaiting(call.id, null)\n await this.ring(again)\n }\n }\n }\n\n /** The owner picked up, or tapped Show. Returns the call and, for a\n * voice call, the opener for /ask. */\n answer(id: string): CallResult & { opener?: string } {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const answered = this.deps.store.transition(id, \"ringing\", { status: \"answered\", answeredAt: this.now(), ringingSince: null })\n if (!answered) return { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}, not ringing` }\n this.deps.log?.(`[calls] ${id} answered (${call.agentId})`)\n return answered.kind === \"camera\" ? { ok: true, call: answered } : { ok: true, call: answered, opener: openerPrompt(answered) }\n }\n\n decline(id: string): CallResult {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const declined = this.deps.store.transition(id, [\"ringing\", \"later\"], { status: \"declined\", endedAt: this.now(), ringingSince: null, ringAgainAt: null })\n return declined ? { ok: true, call: declined } : { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}` }\n }\n\n /** \"Call back in N min\": it rings again then. */\n later(id: string, minutes?: unknown): CallResult {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const n = minutes === undefined ? LATER_DEFAULT_MINUTES : Number(minutes)\n if (!Number.isInteger(n) || n < 1 || n > LATER_MAX_MINUTES) {\n return { ok: false, status: 400, error: `minutes must be a whole number from 1 to ${LATER_MAX_MINUTES}` }\n }\n const later = this.deps.store.transition(id, \"ringing\", { status: \"later\", ringingSince: null, ringAgainAt: this.now() + n * 60_000 })\n return later ? { ok: true, call: later } : { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}, not ringing` }\n }\n\n /** End an answered call. The summary is written in the background;\n * `summarized` settles when it is filed (tests wait on it). */\n hangup(id: string): CallResult & { summarized?: Promise<void> } {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const ended = this.deps.store.transition(id, \"answered\", { status: \"ended\", endedAt: this.now() })\n if (!ended) return { ok: false, status: 409, error: `call is ${call.status}, not answered` }\n this.deps.log?.(`[calls] ${id} ended (${call.agentId})`)\n const summarize = this.deps.summarize\n // What the agent saw is already its answer; only a voice call is summarised.\n if (ended.kind === \"camera\" || !this.deps.config().summary || !summarize) return { ok: true, call: ended }\n const summarized = (async () => {\n try {\n const text = (await summarize(ended))?.trim()\n if (!text) return\n const done = this.deps.store.update(id, { summary: text })!\n this.deps.file?.(done, text)\n } catch (e: any) {\n this.deps.log?.(`[calls] summary for ${id} failed: ${e?.message ?? e}`)\n }\n })()\n return { ok: true, call: ended, summarized }\n }\n\n /** A camera ask ends when the share ends; no summary. Only an answered\n * ask ends this way, so a stop before Show leaves it ringing. */\n endCamera(id: string, note?: string): boolean {\n const call = this.deps.store.get(id)\n if (!call || call.kind !== \"camera\") return false\n const ended = this.deps.store.transition(id, \"answered\", { status: \"ended\", endedAt: this.now(), note: note ?? null })\n if (ended) this.deps.log?.(`[calls] ${id} ended (${call.agentId}): ${note ?? \"share over\"}`)\n return !!ended\n }\n\n get(id: string): Call | undefined { return this.deps.store.get(id) }\n\n list(opts: Parameters<CallStore[\"list\"]>[0] = {}): Call[] { return this.deps.store.list(opts) }\n}\n\n/** How a call reached the owner: on the widget, through notify, waiting\n * for a busy widget, or not at all (held as missed). */\nexport type Rang = \"widget\" | \"notify\" | \"waiting\" | false\n\n/** The note on a call its caller withdrew. */\nexport const CANCELLED_NOTE = \"withdrawn by the caller\"\n\n/** What the caller reads when its call waits for a busy owner. Times are\n * in the host's time zone (or `timeZone`), and say which one. */\nexport function busyText(busy: BusyInfo, now: number = Date.now(), timeZone?: string): string {\n const at = (ms: number) => `${new Date(ms).toLocaleTimeString(\"en-GB\", { hour: \"2-digit\", minute: \"2-digit\", hour12: false, timeZoneName: \"short\", timeZone })} (in ${Math.max(1, Math.round((ms - now) / 60_000))} min)`\n const why = busy.why === \"call\" ? `The owner is busy in another call${busy.with ? ` (with ${busy.with})` : \"\"}.`\n : busy.why === \"ringing\" ? `The owner is busy: another call${busy.with ? ` (from ${busy.with})` : \"\"} is ringing.`\n : \"The owner is busy on the voice widget.\"\n return `${why} They were told you are calling, and why. Your call waits and rings by itself as soon as they are free: do not call again. ` +\n (busy.remindAt !== null ? `Still busy at ${at(busy.remindAt)}, they are told again that you are waiting. ` : \"\") +\n `It waits until ${at(busy.waitsUntil)} at most, then counts as a missed call.`\n}\n\nconst unknown = (id: string): CallResult => ({ ok: false, status: 404, error: `No such call: ${id}` })\n","// --- Calls an agent placed to the owner, kept in SQLite ---\n//\n// One row per call, so a missed call is still there after a restart and\n// the dashboard can list them. Nothing else reads this table. A camera\n// ask (#325 phase 3: \"show me\") is a call of kind \"camera\": same\n// allowlist, same hourly limit, same lifecycle, answered on the phone\n// instead of the voice widget.\n\nimport type Database from \"better-sqlite3\"\n\nexport type CallStatus = \"ringing\" | \"answered\" | \"ended\" | \"declined\" | \"missed\" | \"later\"\nexport type CallUrgency = \"normal\" | \"urgent\"\n/** \"voice\": a live voice call on the widget. \"camera\": the agent asks to see through the phone camera. */\nexport type CallKind = \"voice\" | \"camera\"\n\nexport interface Call {\n id: string\n agentId: string\n kind: CallKind\n reason: string\n urgency: CallUrgency\n status: CallStatus\n /** The channel and chat the asking turn ran in, so what the agent sees\n * is answered there; null when the turn had none (a task run). */\n channel: string | null\n chatId: string | null\n /** When the agent asked, ms since the epoch. */\n createdAt: number\n /** When it last started ringing: at the request, or when \"later\" came due. */\n ringingSince: number | null\n answeredAt: number | null\n endedAt: number | null\n /** Status \"later\": when it rings again. */\n ringAgainAt: number | null\n /** Why it ended the way it did, in a few words (\"in Focus\", \"not answered\"). */\n note: string | null\n /** The agent's own summary, written after hang-up. */\n summary: string | null\n}\n\n/** A call waiting for a busy owner: since when, and when the owner was\n * last told. Ms since the epoch. */\nexport interface Waiting {\n since: number\n toldAt: number\n}\n\n/** A call that stops ringing (answered, snoozed, missed...) is no longer\n * waiting: the mark goes in the same write, so a call that rings again\n * later starts a fresh wait, even across a restart. */\nfunction leaving(patch: { status?: CallStatus }): string {\n return patch.status && patch.status !== \"ringing\" ? \", waiting_since=NULL, told_at=NULL\" : \"\"\n}\n\n/** Calls still in progress: an agent has at most one of these. */\nexport const LIVE: CallStatus[] = [\"ringing\", \"answered\", \"later\"]\n\nconst COLUMNS = `id, agent_id AS agentId, kind, reason, urgency, status, created_at AS createdAt,\n ringing_since AS ringingSince, answered_at AS answeredAt, ended_at AS endedAt,\n ring_again_at AS ringAgainAt, note, summary, channel, chat_id AS chatId`\n\nexport class CallStore {\n constructor(private db: Database.Database) {\n db.exec(`CREATE TABLE IF NOT EXISTS calls (\n id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, reason TEXT NOT NULL,\n urgency TEXT NOT NULL, status TEXT NOT NULL, created_at INTEGER NOT NULL,\n ringing_since INTEGER, answered_at INTEGER, ended_at INTEGER,\n ring_again_at INTEGER, note TEXT, summary TEXT);\n CREATE INDEX IF NOT EXISTS calls_recent ON calls(created_at DESC);`)\n // Columns added since the table first shipped (#325 phase 3). A row\n // from before is a voice call from a turn whose chat was not kept.\n const have = new Set((db.prepare(\"PRAGMA table_info(calls)\").all() as Array<{ name: string }>).map((c) => c.name))\n if (!have.has(\"kind\")) db.exec(\"ALTER TABLE calls ADD COLUMN kind TEXT NOT NULL DEFAULT 'voice'\")\n if (!have.has(\"channel\")) db.exec(\"ALTER TABLE calls ADD COLUMN channel TEXT\")\n if (!have.has(\"chat_id\")) db.exec(\"ALTER TABLE calls ADD COLUMN chat_id TEXT\")\n // A call waiting for a busy owner (#969), kept so a restart does not\n // forget it: since when it waits, and when the owner was last told.\n if (!have.has(\"waiting_since\")) db.exec(\"ALTER TABLE calls ADD COLUMN waiting_since INTEGER\")\n if (!have.has(\"told_at\")) db.exec(\"ALTER TABLE calls ADD COLUMN told_at INTEGER\")\n }\n\n /** Ringing calls marked as waiting for a busy owner, by id. */\n waiting(): Map<string, Waiting> {\n const rows = this.db.prepare(\"SELECT id, waiting_since AS since, told_at AS toldAt FROM calls WHERE waiting_since IS NOT NULL AND status='ringing'\")\n .all() as Array<{ id: string } & Waiting>\n return new Map(rows.map(({ id, since, toldAt }) => [id, { since, toldAt: toldAt ?? since }]))\n }\n\n /** Mark a call as waiting, or clear the mark with null. */\n setWaiting(id: string, w: Waiting | null): void {\n this.db.prepare(\"UPDATE calls SET waiting_since=?, told_at=? WHERE id=?\").run(w?.since ?? null, w?.toldAt ?? null, id)\n }\n\n insert(call: Call): void {\n this.db.prepare(`INSERT INTO calls (id, agent_id, kind, reason, urgency, status, created_at, ringing_since,\n answered_at, ended_at, ring_again_at, note, summary, channel, chat_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(\n call.id, call.agentId, call.kind, call.reason, call.urgency, call.status, call.createdAt,\n call.ringingSince, call.answeredAt, call.endedAt, call.ringAgainAt, call.note, call.summary, call.channel, call.chatId)\n }\n\n get(id: string): Call | undefined {\n return this.db.prepare(`SELECT ${COLUMNS} FROM calls WHERE id=?`).get(id) as Call | undefined\n }\n\n /** Write the changed fields of one call. */\n update(id: string, patch: Partial<Omit<Call, \"id\" | \"agentId\" | \"createdAt\">>): Call | undefined {\n const cols: Record<string, string> = {\n reason: \"reason\", urgency: \"urgency\", status: \"status\", ringingSince: \"ringing_since\",\n answeredAt: \"answered_at\", endedAt: \"ended_at\", ringAgainAt: \"ring_again_at\", note: \"note\", summary: \"summary\",\n }\n const keys = Object.keys(patch).filter((k) => k in cols)\n if (keys.length) {\n const set = keys.map((k) => `${cols[k]}=?`).join(\", \") + leaving(patch)\n this.db.prepare(`UPDATE calls SET ${set} WHERE id=?`).run(...keys.map((k) => (patch as any)[k] ?? null), id)\n }\n return this.get(id)\n }\n\n /** Change a call only if it is still `from`: the check and the write are\n * one statement, so two sweeps, or a sweep and the owner answering,\n * cannot both move the same call. Undefined when it had moved on. */\n transition(id: string, from: CallStatus | CallStatus[], patch: Partial<Omit<Call, \"id\" | \"agentId\" | \"createdAt\">>): Call | undefined {\n const statuses = Array.isArray(from) ? from : [from]\n const cols: Record<string, string> = {\n status: \"status\", ringingSince: \"ringing_since\", answeredAt: \"answered_at\", endedAt: \"ended_at\",\n ringAgainAt: \"ring_again_at\", note: \"note\", summary: \"summary\",\n }\n const keys = Object.keys(patch).filter((k) => k in cols)\n const set = keys.map((k) => `${cols[k]}=?`).join(\", \") + leaving(patch)\n const marks = statuses.map(() => \"?\").join(\",\")\n const changed = this.db.prepare(`UPDATE calls SET ${set} WHERE id=? AND status IN (${marks})`)\n .run(...keys.map((k) => (patch as any)[k] ?? null), id, ...statuses).changes\n return changed ? this.get(id) : undefined\n }\n\n /** Newest first; only these statuses, and only this kind, when given. */\n list(opts: { status?: CallStatus[]; kind?: CallKind; limit?: number } = {}): Call[] {\n const limit = Math.min(Math.max(opts.limit ?? 50, 1), 200)\n const where: string[] = []\n const args: unknown[] = []\n if (opts.status?.length) {\n where.push(`status IN (${opts.status.map(() => \"?\").join(\",\")})`)\n args.push(...opts.status)\n }\n if (opts.kind) { where.push(\"kind=?\"); args.push(opts.kind) }\n const filter = where.length ? `WHERE ${where.join(\" AND \")}` : \"\"\n return this.db.prepare(`SELECT ${COLUMNS} FROM calls ${filter} ORDER BY created_at DESC, rowid DESC LIMIT ?`)\n .all(...args, limit) as Call[]\n }\n\n /** Calls this agent placed after `since` (ms), for the hourly limit. */\n countSince(agentId: string, since: number): number {\n return (this.db.prepare(\"SELECT COUNT(*) AS n FROM calls WHERE agent_id=? AND created_at>?\")\n .get(agentId, since) as { n: number }).n\n }\n}\n"],"mappings":"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","names":["randomUUID","leaving","patch","LIVE","COLUMNS","CallStore","db","have","c","rows","id","since","toldAt","w","call","cols","keys","k","set","from","statuses","marks","opts","limit","where","args","filter","agentId","REASON_MAX","WIDGET_FRESH_MS","LATER_DEFAULT_MINUTES","LATER_MAX_MINUTES","callerHeaders","env","openerPrompt","call","SUMMARY_PROMPT","CallService","deps","id","w","agentId","input","proof","reason","urgency","kind","cfg","LIVE","c","now","session","randomUUID","rang","saved","mine","ended","CANCELLED_NOTE","focus","readFocus","focusLabel","title","extra","e","busy","since","toldAt","others","talking","showing","waitsUntil","remindAt","stopsWaiting","widget","tell","live","held","ringFor","talkFor","again","unknown","answered","declined","minutes","n","later","summarize","summarized","text","done","note","opts","busyText","timeZone","at","ms"]}