shadow-claw 1.32.0 → 1.33.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 (220) hide show
  1. package/.well-known/mcp/server-card.json +1 -1
  2. package/.well-known/mcp.json +1 -1
  3. package/dist/electron/main.cjs +1 -1
  4. package/dist/lib/components/index.js +26 -26
  5. package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
  6. package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
  7. package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
  8. package/dist/lib/components/settings/shadow-claw-git.js +1 -1
  9. package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
  10. package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
  11. package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
  12. package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
  13. package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
  14. package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
  15. package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
  16. package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
  17. package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
  18. package/dist/lib/components/shadow-claw-a2ui.js +1 -1
  19. package/dist/lib/components/shadow-claw-accounts.js +1 -1
  20. package/dist/lib/components/shadow-claw-channel-config.js +1 -1
  21. package/dist/lib/components/shadow-claw-channels.js +1 -1
  22. package/dist/lib/components/shadow-claw-chat.js +1 -1
  23. package/dist/lib/components/shadow-claw-control-plane.js +1 -1
  24. package/dist/lib/components/shadow-claw-conversations.js +1 -1
  25. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  26. package/dist/lib/components/shadow-claw-files.js +1 -1
  27. package/dist/lib/components/shadow-claw-git.js +1 -1
  28. package/dist/lib/components/shadow-claw-integrations.js +1 -1
  29. package/dist/lib/components/shadow-claw-llm.js +1 -1
  30. package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
  31. package/dist/lib/components/shadow-claw-networking.js +1 -1
  32. package/dist/lib/components/shadow-claw-notifications.js +1 -1
  33. package/dist/lib/components/shadow-claw-page-header.js +1 -1
  34. package/dist/lib/components/shadow-claw-pages.js +1 -1
  35. package/dist/lib/components/shadow-claw-peerjs.js +1 -1
  36. package/dist/lib/components/shadow-claw-settings.js +1 -1
  37. package/dist/lib/components/shadow-claw-storage.js +1 -1
  38. package/dist/lib/components/shadow-claw-task-server.js +1 -1
  39. package/dist/lib/components/shadow-claw-tasks.js +1 -1
  40. package/dist/lib/components/shadow-claw-terminal.js +1 -1
  41. package/dist/lib/components/shadow-claw-tools.js +1 -1
  42. package/dist/lib/components/shadow-claw-webvm.js +1 -1
  43. package/dist/lib/components/shadow-claw.js +1 -1
  44. package/dist/lib/{config-DjZ9QWc4.js → config-BcFbkaQv.js} +21 -4
  45. package/dist/lib/config-BcFbkaQv.js.map +1 -0
  46. package/dist/lib/{configurePeerJs-DD3G3Pms.js → configurePeerJs-CBMPHbwa.js} +3 -3
  47. package/dist/lib/{configurePeerJs-DD3G3Pms.js.map → configurePeerJs-CBMPHbwa.js.map} +1 -1
  48. package/dist/lib/{connections-BURqMIUv.js → connections-PZrUDf49.js} +2 -2
  49. package/dist/lib/{connections-BURqMIUv.js.map → connections-PZrUDf49.js.map} +1 -1
  50. package/dist/lib/{downloadGroupFile-B8J4up2a.js → downloadGroupFile-DSRUa9Au.js} +2 -2
  51. package/dist/lib/{downloadGroupFile-B8J4up2a.js.map → downloadGroupFile-DSRUa9Au.js.map} +1 -1
  52. package/dist/lib/{file-viewer-DoHM75Jz.js → file-viewer-11VVOpJv.js} +5 -5
  53. package/dist/lib/{file-viewer-DoHM75Jz.js.map → file-viewer-11VVOpJv.js.map} +1 -1
  54. package/dist/lib/{getGroupDir-QrN2aTo8.js → getGroupDir-BxKMYPPm.js} +3 -3
  55. package/dist/lib/{getGroupDir-QrN2aTo8.js.map → getGroupDir-BxKMYPPm.js.map} +1 -1
  56. package/dist/lib/{git-Brr7JIbs.js → git-BppibnJW.js} +3 -3
  57. package/dist/lib/{git-Brr7JIbs.js.map → git-BppibnJW.js.map} +1 -1
  58. package/dist/lib/{iframe-sanitizer-Bujgq14T.js → iframe-sanitizer-Dp8EYffI.js} +2 -2
  59. package/dist/lib/{iframe-sanitizer-Bujgq14T.js.map → iframe-sanitizer-Dp8EYffI.js.map} +1 -1
  60. package/dist/lib/index.js +27 -27
  61. package/dist/lib/{initChatSplitResize-BjiWoqC_.js → initChatSplitResize-CE_kWaLf.js} +2 -2
  62. package/dist/lib/{initChatSplitResize-BjiWoqC_.js.map → initChatSplitResize-CE_kWaLf.js.map} +1 -1
  63. package/dist/lib/{initControlPlane-3TUdhRBM.js → initControlPlane-BRIIOzoH.js} +18 -17
  64. package/dist/lib/{initControlPlane-3TUdhRBM.js.map → initControlPlane-BRIIOzoH.js.map} +1 -1
  65. package/dist/lib/{markdown-BFUTPQoO.js → markdown-Cq4sVwUT.js} +4 -4
  66. package/dist/lib/{markdown-BFUTPQoO.js.map → markdown-Cq4sVwUT.js.map} +1 -1
  67. package/dist/lib/{mcp-reconnect-BxJ77WSb.js → mcp-reconnect-CoHDMjmY.js} +2 -2
  68. package/dist/lib/{mcp-reconnect-BxJ77WSb.js.map → mcp-reconnect-CoHDMjmY.js.map} +1 -1
  69. package/dist/lib/{memoryStorage-D3FBwO9T.js → memoryStorage-DcFWrn_y.js} +2 -2
  70. package/dist/lib/{memoryStorage-D3FBwO9T.js.map → memoryStorage-DcFWrn_y.js.map} +1 -1
  71. package/dist/lib/{orchestrator-DW5l2bbW.js → orchestrator-C3TgDZvq.js} +81 -18
  72. package/dist/lib/{orchestrator-DW5l2bbW.js.map → orchestrator-C3TgDZvq.js.map} +1 -1
  73. package/dist/lib/{orchestrator-DLnCmeTZ.js → orchestrator-Ce9_lmL2.js} +12 -12
  74. package/dist/lib/{orchestrator-DLnCmeTZ.js.map → orchestrator-Ce9_lmL2.js.map} +1 -1
  75. package/dist/lib/{peerjs-BXlMuIQn.js → peerjs-PTYQ7yEG.js} +6 -6
  76. package/dist/lib/{peerjs-BXlMuIQn.js.map → peerjs-PTYQ7yEG.js.map} +1 -1
  77. package/dist/lib/{push-client-B419nn-i.js → push-client-DDV5Rcg6.js} +3 -3
  78. package/dist/lib/{push-client-B419nn-i.js.map → push-client-DDV5Rcg6.js.map} +1 -1
  79. package/dist/lib/{readGroupFileBytes-CSA7u-nJ.js → readGroupFileBytes-7C8G-yps.js} +2 -2
  80. package/dist/lib/{readGroupFileBytes-CSA7u-nJ.js.map → readGroupFileBytes-7C8G-yps.js.map} +1 -1
  81. package/dist/lib/{shadow-claw-DmMO4vVG.js → shadow-claw-WrWoPqFx.js} +10 -10
  82. package/dist/lib/{shadow-claw-DmMO4vVG.js.map → shadow-claw-WrWoPqFx.js.map} +1 -1
  83. package/dist/lib/{shadow-claw-a2ui-2I5nffIn.js → shadow-claw-a2ui-CcmJNXQP.js} +2 -2
  84. package/dist/lib/{shadow-claw-a2ui-2I5nffIn.js.map → shadow-claw-a2ui-CcmJNXQP.js.map} +1 -1
  85. package/dist/lib/{shadow-claw-accounts-DMb0y4ca.js → shadow-claw-accounts-CcB2429E.js} +3 -3
  86. package/dist/lib/{shadow-claw-accounts-DMb0y4ca.js.map → shadow-claw-accounts-CcB2429E.js.map} +1 -1
  87. package/dist/lib/{shadow-claw-channel-config-BhxHf6wZ.js → shadow-claw-channel-config-C4v0h8oa.js} +3 -3
  88. package/dist/lib/{shadow-claw-channel-config-BhxHf6wZ.js.map → shadow-claw-channel-config-C4v0h8oa.js.map} +1 -1
  89. package/dist/lib/{shadow-claw-channels-B5vzE9Z2.js → shadow-claw-channels-CyV88k9T.js} +3 -3
  90. package/dist/lib/{shadow-claw-channels-B5vzE9Z2.js.map → shadow-claw-channels-CyV88k9T.js.map} +1 -1
  91. package/dist/lib/{shadow-claw-chat-BsYnJ4-G.js → shadow-claw-chat-DSYtuZod.js} +11 -11
  92. package/dist/lib/{shadow-claw-chat-BsYnJ4-G.js.map → shadow-claw-chat-DSYtuZod.js.map} +1 -1
  93. package/dist/lib/{shadow-claw-control-plane-DqcgQsun.js → shadow-claw-control-plane-DBSGuDT1.js} +7 -7
  94. package/dist/lib/{shadow-claw-control-plane-DqcgQsun.js.map → shadow-claw-control-plane-DBSGuDT1.js.map} +1 -1
  95. package/dist/lib/{shadow-claw-conversations-B9Pn58g3.js → shadow-claw-conversations-Cp8pK4PM.js} +5 -5
  96. package/dist/lib/{shadow-claw-conversations-B9Pn58g3.js.map → shadow-claw-conversations-Cp8pK4PM.js.map} +1 -1
  97. package/dist/lib/{shadow-claw-file-viewer-DL6c4oPK.js → shadow-claw-file-viewer-B8G8yo48.js} +8 -8
  98. package/dist/lib/{shadow-claw-file-viewer-DL6c4oPK.js.map → shadow-claw-file-viewer-B8G8yo48.js.map} +1 -1
  99. package/dist/lib/{shadow-claw-files-C_ksPb8W.js → shadow-claw-files-D1COKzuC.js} +9 -9
  100. package/dist/lib/{shadow-claw-files-C_ksPb8W.js.map → shadow-claw-files-D1COKzuC.js.map} +1 -1
  101. package/dist/lib/{shadow-claw-git-jwsY7L1N.js → shadow-claw-git-60tWU4Ee.js} +6 -6
  102. package/dist/lib/{shadow-claw-git-jwsY7L1N.js.map → shadow-claw-git-60tWU4Ee.js.map} +1 -1
  103. package/dist/lib/{shadow-claw-integrations-yT7j07TM.js → shadow-claw-integrations-Bw1cG1ze.js} +4 -4
  104. package/dist/lib/{shadow-claw-integrations-yT7j07TM.js.map → shadow-claw-integrations-Bw1cG1ze.js.map} +1 -1
  105. package/dist/lib/{shadow-claw-llm-CEPJh1Jh.js → shadow-claw-llm-By5CvsFJ.js} +6 -6
  106. package/dist/lib/{shadow-claw-llm-CEPJh1Jh.js.map → shadow-claw-llm-By5CvsFJ.js.map} +1 -1
  107. package/dist/lib/{shadow-claw-mcp-remote-DGDWjByQ.js → shadow-claw-mcp-remote-BaNODd1v.js} +4 -4
  108. package/dist/lib/{shadow-claw-mcp-remote-DGDWjByQ.js.map → shadow-claw-mcp-remote-BaNODd1v.js.map} +1 -1
  109. package/dist/lib/{shadow-claw-networking-Bi4yvc73.js → shadow-claw-networking-DtZ5bsTz.js} +2 -2
  110. package/dist/lib/{shadow-claw-networking-Bi4yvc73.js.map → shadow-claw-networking-DtZ5bsTz.js.map} +1 -1
  111. package/dist/lib/{shadow-claw-notifications-C-JgGqQx.js → shadow-claw-notifications-C3VEba_A.js} +3 -3
  112. package/dist/lib/{shadow-claw-notifications-C-JgGqQx.js.map → shadow-claw-notifications-C3VEba_A.js.map} +1 -1
  113. package/dist/lib/{shadow-claw-page-header-DrAcWCZ9.js → shadow-claw-page-header-BLowJopA.js} +2 -2
  114. package/dist/lib/{shadow-claw-page-header-DrAcWCZ9.js.map → shadow-claw-page-header-BLowJopA.js.map} +1 -1
  115. package/dist/lib/{shadow-claw-pages-OEOClgA8.js → shadow-claw-pages-CpeUV-hw.js} +9 -9
  116. package/dist/lib/{shadow-claw-pages-OEOClgA8.js.map → shadow-claw-pages-CpeUV-hw.js.map} +1 -1
  117. package/dist/lib/{shadow-claw-peerjs-DmC2CV-9.js → shadow-claw-peerjs-DYAzJbTy.js} +3 -3
  118. package/dist/lib/{shadow-claw-peerjs-DmC2CV-9.js.map → shadow-claw-peerjs-DYAzJbTy.js.map} +1 -1
  119. package/dist/lib/{shadow-claw-settings-xAtFog0T.js → shadow-claw-settings-ByxwW3WK.js} +9 -9
  120. package/dist/lib/{shadow-claw-settings-xAtFog0T.js.map → shadow-claw-settings-ByxwW3WK.js.map} +1 -1
  121. package/dist/lib/{shadow-claw-storage-B4UHl-po.js → shadow-claw-storage-CsSPYVDJ.js} +5 -5
  122. package/dist/lib/{shadow-claw-storage-B4UHl-po.js.map → shadow-claw-storage-CsSPYVDJ.js.map} +1 -1
  123. package/dist/lib/{shadow-claw-task-server-B0eWzg57.js → shadow-claw-task-server-De2WCEw4.js} +2 -2
  124. package/dist/lib/{shadow-claw-task-server-B0eWzg57.js.map → shadow-claw-task-server-De2WCEw4.js.map} +1 -1
  125. package/dist/lib/{shadow-claw-tasks-HHU_8Gyg.js → shadow-claw-tasks-zHWT4GaE.js} +7 -7
  126. package/dist/lib/{shadow-claw-tasks-HHU_8Gyg.js.map → shadow-claw-tasks-zHWT4GaE.js.map} +1 -1
  127. package/dist/lib/{shadow-claw-terminal-CdC2G6Zz.js → shadow-claw-terminal-Bpawfv4N.js} +2 -2
  128. package/dist/lib/{shadow-claw-terminal-CdC2G6Zz.js.map → shadow-claw-terminal-Bpawfv4N.js.map} +1 -1
  129. package/dist/lib/{shadow-claw-tools-2AICxVXA.js → shadow-claw-tools-BbKdWcps.js} +7 -7
  130. package/dist/lib/{shadow-claw-tools-2AICxVXA.js.map → shadow-claw-tools-BbKdWcps.js.map} +1 -1
  131. package/dist/lib/{shadow-claw-webvm-Cy-Ia2vs.js → shadow-claw-webvm-DLqK0AxW.js} +3 -3
  132. package/dist/lib/{shadow-claw-webvm-Cy-Ia2vs.js.map → shadow-claw-webvm-DLqK0AxW.js.map} +1 -1
  133. package/dist/lib/subsystems/mcp/webmcp.d.ts +37 -0
  134. package/dist/lib/subsystems/providers/model-registry.d.ts +4 -1
  135. package/dist/lib/subsystems/providers/providers.d.ts +10 -0
  136. package/dist/lib/{syncWebMcpRegistration-CaAPPg2V.js → syncWebMcpRegistration-mlbbvcdm.js} +5 -5
  137. package/dist/lib/{syncWebMcpRegistration-CaAPPg2V.js.map → syncWebMcpRegistration-mlbbvcdm.js.map} +1 -1
  138. package/dist/lib/{tools-f1WPNDSS.js → tools-Bb2ujM2E.js} +4 -4
  139. package/dist/lib/{tools-f1WPNDSS.js.map → tools-Bb2ujM2E.js.map} +1 -1
  140. package/dist/lib/utils/index.js +1 -1
  141. package/dist/lib/utils/utils.js +1 -1
  142. package/dist/lib/{utils-B99XP70b.js → utils-mpsYPfS7.js} +3 -3
  143. package/dist/lib/{utils-B99XP70b.js.map → utils-mpsYPfS7.js.map} +1 -1
  144. package/dist/lib/webmcp-BVR2lBVo.js +1544 -0
  145. package/dist/lib/webmcp-BVR2lBVo.js.map +1 -0
  146. package/dist/public/.well-known/mcp/server-card.json +1 -1
  147. package/dist/public/.well-known/mcp.json +1 -1
  148. package/dist/public/agent.worker.js +44 -44
  149. package/dist/public/config-BqecTktB.js +1 -0
  150. package/dist/public/{configurePeerJs--JGpJVti.js → configurePeerJs-BPKfWuEt.js} +1 -1
  151. package/dist/public/{connections-6575KDGE.js → connections-C_3tYsmX.js} +1 -1
  152. package/dist/public/{custom-element-security-Da_6HQ6X.js → custom-element-security-DXwU3Lae.js} +1 -1
  153. package/dist/public/docs/example/article/index.html +2 -2
  154. package/dist/public/docs/publishing/index.html +2 -2
  155. package/dist/public/docs/skill-creator/index.html +2 -2
  156. package/dist/public/docs/subsystems/tools.md +4 -3
  157. package/dist/public/docs/subsystems/webmcp.md +58 -13
  158. package/dist/public/{downloadGroupFile-Dj-AMNsd.js → downloadGroupFile-DTyf5DIC.js} +1 -1
  159. package/dist/public/{e2e-bridge-CbYqdMp-.js → e2e-bridge-DXwWCQKw.js} +1 -1
  160. package/dist/public/{file-viewer-vHJ5Zsgk.js → file-viewer-ConEyDDG.js} +1 -1
  161. package/dist/public/{getGroupDir-BwprrdrQ.js → getGroupDir-ZfZsiq6d.js} +1 -1
  162. package/dist/public/{git-8F7wvoUB.js → git-BtBaLC1-.js} +2 -2
  163. package/dist/public/{iframe-sanitizer-viROQkRn.js → iframe-sanitizer-Corkvo_d.js} +1 -1
  164. package/dist/public/index.html +2 -2
  165. package/dist/public/index.js +1 -1
  166. package/dist/public/{initChatSplitResize-BA18wLQQ.js → initChatSplitResize-CUc-TEmT.js} +1 -1
  167. package/dist/public/{initControlPlane-C5v0FtJE.js → initControlPlane-B_uYS8a4.js} +1 -1
  168. package/dist/public/main/index.html +2 -2
  169. package/dist/public/main/memory/index.html +2 -2
  170. package/dist/public/{markdown-eFKxxpVP.js → markdown-Cfa6GuJs.js} +1 -1
  171. package/dist/public/{mcp-reconnect-CBHuaYdF.js → mcp-reconnect-CUOkdPEz.js} +1 -1
  172. package/dist/public/{memoryStorage-C1llaYus.js → memoryStorage-Bh8fjmip.js} +1 -1
  173. package/dist/public/{orchestrator-DNr2HDI2.js → orchestrator-BcSzrg6E.js} +2 -2
  174. package/dist/public/{orchestrator-BeJfwtvz.js → orchestrator-Bi5OdVZD.js} +11 -11
  175. package/dist/public/{peerjs-mG30TAJ_.js → peerjs-CzCXG-NW.js} +1 -1
  176. package/dist/public/{push-client-C2zMT3Sf.js → push-client-Cr3Ruahp.js} +1 -1
  177. package/dist/public/service-worker.js +1 -1
  178. package/dist/public/{shadow-claw-Ble6l0Iw.js → shadow-claw-CzUYuuOa.js} +2 -2
  179. package/dist/public/{shadow-claw-accounts-D1y-zbMs.js → shadow-claw-accounts-BgIHB_aP.js} +1 -1
  180. package/dist/public/{shadow-claw-channels-D_xfBoWp.js → shadow-claw-channels-Ce_trJ5D.js} +1 -1
  181. package/dist/public/{shadow-claw-chat-D_Lbi5oH.js → shadow-claw-chat-CdECLLwL.js} +1 -1
  182. package/dist/public/{shadow-claw-control-plane-CrnA5lM0.js → shadow-claw-control-plane-DM62UmOz.js} +2 -2
  183. package/dist/public/{shadow-claw-conversations-BN-hFmN1.js → shadow-claw-conversations-AM5g3C00.js} +1 -1
  184. package/dist/public/{shadow-claw-file-viewer-BKEpzpbx.js → shadow-claw-file-viewer-BP7gWS5g.js} +1 -1
  185. package/dist/public/{shadow-claw-files-DDZMk5AA.js → shadow-claw-files-RPPGszcK.js} +1 -1
  186. package/dist/public/{shadow-claw-git-CqOO97Re.js → shadow-claw-git-BsHEvLrb.js} +2 -2
  187. package/dist/public/{shadow-claw-integrations-CRGL78Fy.js → shadow-claw-integrations-B0vbcOqg.js} +1 -1
  188. package/dist/public/{shadow-claw-llm-DoGxEHQL.js → shadow-claw-llm-FNNamrc_.js} +2 -2
  189. package/dist/public/{shadow-claw-mcp-remote-DyGnK4S_.js → shadow-claw-mcp-remote-7mDgniQu.js} +1 -1
  190. package/dist/public/{shadow-claw-networking-DJeCdb7e.js → shadow-claw-networking-CGsetaLp.js} +1 -1
  191. package/dist/public/{shadow-claw-notifications-hSKJeMXb.js → shadow-claw-notifications-pnwRcR-4.js} +1 -1
  192. package/dist/public/{shadow-claw-page-header-DA-FG08G.js → shadow-claw-page-header-BUy15Poz.js} +1 -1
  193. package/dist/public/{shadow-claw-pages-DTS98Zbi.js → shadow-claw-pages-ILAjGWNk.js} +1 -1
  194. package/dist/public/{shadow-claw-settings-5w0ce8SP.js → shadow-claw-settings-Bx5IgVqN.js} +3 -3
  195. package/dist/public/{shadow-claw-storage-DqlVt27X.js → shadow-claw-storage-PAtNykaF.js} +1 -1
  196. package/dist/public/{shadow-claw-task-server-ByZwKI6S.js → shadow-claw-task-server-Cbbi_2OO.js} +1 -1
  197. package/dist/public/{shadow-claw-tasks-Dc4G4zBu.js → shadow-claw-tasks-B-jKYWZJ.js} +1 -1
  198. package/dist/public/{shadow-claw-terminal-DvusP7wg.js → shadow-claw-terminal-BRejND-Z.js} +1 -1
  199. package/dist/public/{shadow-claw-tools-BEsid8q-.js → shadow-claw-tools-DNQe3oa-.js} +1 -1
  200. package/dist/public/{shadow-claw-webvm-BWlIeK78.js → shadow-claw-webvm-BFuwRifU.js} +1 -1
  201. package/dist/public/{syncWebMcpRegistration-CqVCB6m8.js → syncWebMcpRegistration-FxKAPwaz.js} +1 -1
  202. package/dist/public/theme-init.js +1 -1
  203. package/dist/public/{tools-Cp1gequ8.js → tools-BwQKGsro.js} +1 -1
  204. package/dist/public/transformers-js.worker.js +1 -1
  205. package/dist/public/webmcp-C28PAlfy.js +1 -0
  206. package/dist/server.js +1 -1
  207. package/package.json +3 -3
  208. package/src/core/utils/initControlPlane.test.ts +122 -1
  209. package/src/core/utils/initControlPlane.ts +12 -8
  210. package/src/subsystems/mcp/webmcp.test.ts +253 -1
  211. package/src/subsystems/mcp/webmcp.ts +147 -4
  212. package/src/subsystems/providers/model-registry.test.ts +139 -0
  213. package/src/subsystems/providers/model-registry.ts +54 -2
  214. package/src/subsystems/providers/providers.test.ts +329 -0
  215. package/src/subsystems/providers/providers.ts +135 -11
  216. package/dist/lib/config-DjZ9QWc4.js.map +0 -1
  217. package/dist/lib/webmcp-BC8_WafM.js +0 -1710
  218. package/dist/lib/webmcp-BC8_WafM.js.map +0 -1
  219. package/dist/public/config-Bnwx4EfS.js +0 -1
  220. package/dist/public/webmcp-DBONjQWd.js +0 -2
@@ -7,6 +7,7 @@ import {
7
7
  getContextLimit,
8
8
  normalizeMeshLlmResult,
9
9
  parseResponse,
10
+ supportsPromptCaching,
10
11
  } from "./providers.js";
11
12
 
12
13
  describe("providers.js", () => {
@@ -935,6 +936,334 @@ describe("providers.js", () => {
935
936
  expect(result.tools[0].cache_control).toBeUndefined();
936
937
  expect(result.system).toBe("System prompt");
937
938
  });
939
+
940
+ it("should allow prompt caching to be enabled explicitly for any non-legacy model", () => {
941
+ const tools = [
942
+ {
943
+ name: "test_tool",
944
+ description: "A tool",
945
+ input_schema: { type: "object" },
946
+ },
947
+ ];
948
+
949
+ const result = formatRequest(
950
+ anthropicProvider,
951
+ [{ role: "user", content: "hello" }],
952
+ tools,
953
+ {
954
+ model: "custom-unlisted-model",
955
+ maxTokens: 1000,
956
+ system: "System prompt",
957
+ promptCaching: true,
958
+ } as any,
959
+ );
960
+
961
+ expect(result.tools[0].cache_control).toEqual({ type: "ephemeral" });
962
+ expect(result.system).toEqual([
963
+ {
964
+ type: "text",
965
+ text: "System prompt",
966
+ cache_control: { type: "ephemeral" },
967
+ },
968
+ ]);
969
+ });
970
+
971
+ it("should guard against prompt caching for legacy models even when promptCaching: true is set", () => {
972
+ const tools = [
973
+ {
974
+ name: "test_tool",
975
+ description: "A tool",
976
+ input_schema: { type: "object" },
977
+ },
978
+ ];
979
+
980
+ const result = formatRequest(
981
+ anthropicProvider,
982
+ [{ role: "user", content: "hello" }],
983
+ tools,
984
+ {
985
+ model: "claude-2.1",
986
+ maxTokens: 1000,
987
+ system: "System prompt",
988
+ promptCaching: true,
989
+ } as any,
990
+ );
991
+
992
+ expect(result.tools[0].cache_control).toBeUndefined();
993
+ expect(result.system).toBe("System prompt");
994
+ });
995
+
996
+ it("should guard against prompt caching for dot-delimited legacy model IDs when promptCaching: true is set", () => {
997
+ const tools = [
998
+ {
999
+ name: "test_tool",
1000
+ description: "A tool",
1001
+ input_schema: { type: "object" },
1002
+ },
1003
+ ];
1004
+
1005
+ const result = formatRequest(
1006
+ anthropicProvider,
1007
+ [{ role: "user", content: "hello" }],
1008
+ tools,
1009
+ {
1010
+ model: "claude.2.1",
1011
+ maxTokens: 1000,
1012
+ system: "System prompt",
1013
+ promptCaching: true,
1014
+ } as any,
1015
+ );
1016
+
1017
+ expect(result.tools[0].cache_control).toBeUndefined();
1018
+ expect(result.system).toBe("System prompt");
1019
+ });
1020
+
1021
+ it("should place cache_control on the last user turn in multi-turn conversations", () => {
1022
+ const tools = [
1023
+ {
1024
+ name: "test_tool",
1025
+ description: "A tool",
1026
+ input_schema: { type: "object" },
1027
+ },
1028
+ ];
1029
+
1030
+ const messages = [
1031
+ { role: "user", content: "First turn" },
1032
+ { role: "assistant", content: "Assistant response" },
1033
+ { role: "user", content: "Second turn" },
1034
+ ];
1035
+
1036
+ const result = formatRequest(anthropicProvider, messages, tools, {
1037
+ model: "claude-3-5-sonnet-20241022",
1038
+ maxTokens: 1000,
1039
+ system: "System prompt",
1040
+ } as any);
1041
+
1042
+ expect(result.messages[0].content).toBe("First turn");
1043
+ expect(result.messages[2].content).toEqual([
1044
+ {
1045
+ type: "text",
1046
+ text: "Second turn",
1047
+ cache_control: { type: "ephemeral" },
1048
+ },
1049
+ ]);
1050
+ });
1051
+
1052
+ it("should never mutate caller input message objects or arrays", () => {
1053
+ const originalUserTurn = { role: "user", content: "First turn" };
1054
+ const originalAssistantTurn = {
1055
+ role: "assistant",
1056
+ content: "Assistant response",
1057
+ };
1058
+ const originalSecondUserTurn = { role: "user", content: "Second turn" };
1059
+ const callerMessages = [
1060
+ originalUserTurn,
1061
+ originalAssistantTurn,
1062
+ originalSecondUserTurn,
1063
+ ];
1064
+
1065
+ const result = formatRequest(anthropicProvider, callerMessages, [], {
1066
+ model: "claude-3-5-sonnet-20241022",
1067
+ maxTokens: 1000,
1068
+ system: "System prompt",
1069
+ } as any);
1070
+
1071
+ // Caller objects must be unchanged
1072
+ expect(originalUserTurn.content).toBe("First turn");
1073
+ expect(originalSecondUserTurn.content).toBe("Second turn");
1074
+ expect((originalSecondUserTurn as any).cache_control).toBeUndefined();
1075
+ expect(callerMessages[0]).toBe(originalUserTurn);
1076
+ expect(callerMessages[2]).toBe(originalSecondUserTurn);
1077
+
1078
+ // Formatted result gets the cache breakpoint
1079
+ expect(result.messages[2].content).toEqual([
1080
+ {
1081
+ type: "text",
1082
+ text: "Second turn",
1083
+ cache_control: { type: "ephemeral" },
1084
+ },
1085
+ ]);
1086
+ });
1087
+
1088
+ it("should dynamically enable prompt caching when ModelRegistry metadata specifies support", () => {
1089
+ modelRegistry.registerModelInfo("arbitrary-proxy-model", {
1090
+ contextWindow: 100000,
1091
+ maxOutput: 4096,
1092
+ supportsPromptCaching: true,
1093
+ });
1094
+
1095
+ const tools = [
1096
+ {
1097
+ name: "test_tool",
1098
+ description: "A tool",
1099
+ input_schema: { type: "object" },
1100
+ },
1101
+ ];
1102
+
1103
+ const result = formatRequest(
1104
+ anthropicProvider,
1105
+ [{ role: "user", content: "hello" }],
1106
+ tools,
1107
+ {
1108
+ model: "arbitrary-proxy-model",
1109
+ maxTokens: 1000,
1110
+ system: "System prompt",
1111
+ } as any,
1112
+ );
1113
+
1114
+ expect(result.tools[0].cache_control).toEqual({ type: "ephemeral" });
1115
+ });
1116
+
1117
+ it("should dynamically disable prompt caching when ModelRegistry metadata specifies false", () => {
1118
+ modelRegistry.registerModelInfo("claude-3-5-sonnet-cached", {
1119
+ contextWindow: 200000,
1120
+ maxOutput: 8192,
1121
+ supportsPromptCaching: false,
1122
+ });
1123
+
1124
+ const tools = [
1125
+ {
1126
+ name: "test_tool",
1127
+ description: "A tool",
1128
+ input_schema: { type: "object" },
1129
+ },
1130
+ ];
1131
+
1132
+ const result = formatRequest(
1133
+ anthropicProvider,
1134
+ [{ role: "user", content: "hello" }],
1135
+ tools,
1136
+ {
1137
+ model: "claude-3-5-sonnet-cached",
1138
+ maxTokens: 1000,
1139
+ system: "System prompt",
1140
+ } as any,
1141
+ );
1142
+
1143
+ expect(result.tools[0].cache_control).toBeUndefined();
1144
+ });
1145
+
1146
+ it("should guard against prompt caching when ModelRegistry explicitly specifies false even if promptCaching: true is set", () => {
1147
+ modelRegistry.registerModelInfo("explicit-no-cache-model", {
1148
+ contextWindow: 128000,
1149
+ maxOutput: 4096,
1150
+ supportsPromptCaching: false,
1151
+ });
1152
+
1153
+ const tools = [
1154
+ {
1155
+ name: "test_tool",
1156
+ description: "A tool",
1157
+ input_schema: { type: "object" },
1158
+ },
1159
+ ];
1160
+
1161
+ const result = formatRequest(
1162
+ anthropicProvider,
1163
+ [{ role: "user", content: "hello" }],
1164
+ tools,
1165
+ {
1166
+ model: "explicit-no-cache-model",
1167
+ maxTokens: 1000,
1168
+ system: "System prompt",
1169
+ promptCaching: true,
1170
+ } as any,
1171
+ );
1172
+
1173
+ expect(result.tools[0].cache_control).toBeUndefined();
1174
+ expect(result.system).toBe("System prompt");
1175
+ });
1176
+
1177
+ it("should preserve pre-existing cache_control on content blocks during mapAnthropicContent", () => {
1178
+ const messages = [
1179
+ {
1180
+ role: "user",
1181
+ content: [
1182
+ {
1183
+ type: "text",
1184
+ text: "Explicitly tagged block",
1185
+ cache_control: { type: "ephemeral" },
1186
+ },
1187
+ ],
1188
+ },
1189
+ ];
1190
+
1191
+ const result = formatRequest(anthropicProvider, messages, [], {
1192
+ model: "claude-3-5-sonnet-20241022",
1193
+ maxTokens: 1000,
1194
+ system: "",
1195
+ } as any);
1196
+
1197
+ expect(result.messages[0].content[0]).toEqual({
1198
+ type: "text",
1199
+ text: "Explicitly tagged block",
1200
+ cache_control: { type: "ephemeral" },
1201
+ });
1202
+ });
1203
+ });
1204
+
1205
+ describe("supportsPromptCaching", () => {
1206
+ it("returns false for empty or non-string inputs", () => {
1207
+ expect(supportsPromptCaching("")).toBe(false);
1208
+ expect(supportsPromptCaching(" ")).toBe(false);
1209
+ expect(supportsPromptCaching(null as any)).toBe(false);
1210
+ expect(supportsPromptCaching(undefined as any)).toBe(false);
1211
+ });
1212
+
1213
+ it("identifies Claude 3.5 models (with dashes and dots)", () => {
1214
+ expect(supportsPromptCaching("claude-3-5-sonnet-20241022")).toBe(true);
1215
+ expect(supportsPromptCaching("claude-3-5-sonnet-latest")).toBe(true);
1216
+ expect(supportsPromptCaching("claude-3.5-sonnet")).toBe(true);
1217
+ expect(supportsPromptCaching("claude-3-5-haiku-20241022")).toBe(true);
1218
+ expect(supportsPromptCaching("claude-3.5-haiku")).toBe(true);
1219
+ });
1220
+
1221
+ it("identifies Claude 3.7 models (with dashes and dots)", () => {
1222
+ expect(supportsPromptCaching("claude-3-7-sonnet-20250219")).toBe(true);
1223
+ expect(supportsPromptCaching("claude-3.7-sonnet")).toBe(true);
1224
+ expect(
1225
+ supportsPromptCaching("anthropic/claude-3.7-sonnet:thinking"),
1226
+ ).toBe(true);
1227
+ });
1228
+
1229
+ it("identifies Claude 3 Haiku and Claude 3 Opus", () => {
1230
+ expect(supportsPromptCaching("claude-3-haiku-20240307")).toBe(true);
1231
+ expect(supportsPromptCaching("claude-3-haiku")).toBe(true);
1232
+ expect(supportsPromptCaching("claude-3-opus-20240229")).toBe(true);
1233
+ expect(supportsPromptCaching("claude-3-opus")).toBe(true);
1234
+ });
1235
+
1236
+ it("identifies Claude 4+ and Claude 5+ standard families", () => {
1237
+ expect(supportsPromptCaching("claude-sonnet-4")).toBe(true);
1238
+ expect(supportsPromptCaching("claude-opus-4")).toBe(true);
1239
+ expect(supportsPromptCaching("claude-haiku-4")).toBe(true);
1240
+ expect(supportsPromptCaching("claude-4-sonnet")).toBe(true);
1241
+ expect(supportsPromptCaching("claude-sonnet-5")).toBe(true);
1242
+ expect(supportsPromptCaching("claude-opus-5")).toBe(true);
1243
+ });
1244
+
1245
+ it("identifies AWS Bedrock inference profile IDs", () => {
1246
+ expect(
1247
+ supportsPromptCaching("anthropic.claude-3-5-sonnet-20241022-v2:0"),
1248
+ ).toBe(true);
1249
+ expect(
1250
+ supportsPromptCaching("us.anthropic.claude-3-7-sonnet-20250219-v1:0"),
1251
+ ).toBe(true);
1252
+ expect(
1253
+ supportsPromptCaching("eu.anthropic.claude-3-5-haiku-20241022-v1:0"),
1254
+ ).toBe(true);
1255
+ });
1256
+
1257
+ it("rejects non-Anthropic models, legacy Claude models, and unspecified families", () => {
1258
+ expect(supportsPromptCaching("amazon.nova-pro-v1:0")).toBe(false);
1259
+ expect(supportsPromptCaching("claude-2.1")).toBe(false);
1260
+ expect(supportsPromptCaching("claude-2.0")).toBe(false);
1261
+ expect(supportsPromptCaching("claude-2")).toBe(false);
1262
+ expect(supportsPromptCaching("anthropic.claude-v2")).toBe(false);
1263
+ expect(supportsPromptCaching("claude-instant-1.2")).toBe(false);
1264
+ expect(supportsPromptCaching("claude-1.3")).toBe(false);
1265
+ expect(supportsPromptCaching("gpt-4o")).toBe(false);
1266
+ });
938
1267
  });
939
1268
 
940
1269
  describe("Anthropic response parsing", () => {
@@ -183,22 +183,92 @@ function mapOpenAiUserContent(blocks: any[], model: string): any[] {
183
183
  return content;
184
184
  }
185
185
 
186
- function supportsPromptCaching(model: string): boolean {
186
+ function normalizeModelId(model: string): string {
187
187
  if (typeof model !== "string" || model.trim().length === 0) {
188
- return false;
188
+ return "";
189
189
  }
190
190
 
191
- const id = model.toLowerCase();
191
+ return model
192
+ .toLowerCase()
193
+ .replace(/[^a-z0-9]+/g, "-")
194
+ .replace(/-+/g, "-")
195
+ .replace(/^-|-$/g, "");
196
+ }
197
+
198
+ function isLegacyClaudeModel(model: string): boolean {
199
+ const id = normalizeModelId(model);
200
+ if (!id) {
201
+ return false;
202
+ }
192
203
 
193
204
  return (
194
- id.includes("claude-3-5-sonnet") ||
195
- id.includes("claude-3-7-sonnet") ||
196
- id.includes("claude-opus-4") ||
197
- id.includes("claude-sonnet-4") ||
198
- id.includes("claude-haiku-4")
205
+ id.includes("claude-1") ||
206
+ id.includes("claude-2") ||
207
+ id.includes("claude-v1") ||
208
+ id.includes("claude-v2") ||
209
+ id.includes("claude-instant")
199
210
  );
200
211
  }
201
212
 
213
+ /**
214
+ * Check if a model supports Anthropic/Bedrock prompt caching.
215
+ *
216
+ * 1. Checks ModelRegistry for dynamic capability metadata (e.g. from OpenRouter
217
+ * `supported_parameters` or explicit registration).
218
+ * 2. Normalizes model identifiers (handling dots, slashes, uppercase).
219
+ * 3. Rejects legacy models (Claude 1, 2, instant).
220
+ * 4. Matches modern Claude 3, 3.5, 3.7, 4+, 5+ families.
221
+ */
222
+ export function supportsPromptCaching(model: string): boolean {
223
+ if (typeof model !== "string" || model.trim().length === 0) {
224
+ return false;
225
+ }
226
+
227
+ // 1. Dynamic metadata lookup (avoids hardcoded strings when provider supplies capabilities)
228
+ const modelInfo = modelRegistry.getModelInfo(model);
229
+ if (typeof modelInfo?.supportsPromptCaching === "boolean") {
230
+ return modelInfo.supportsPromptCaching;
231
+ }
232
+
233
+ // 2. Normalize model identifier (lowercased, non-alphanumeric converted to hyphens)
234
+ const id = normalizeModelId(model);
235
+
236
+ // Legacy Claude models that explicitly do NOT support prompt caching
237
+ if (isLegacyClaudeModel(id)) {
238
+ return false;
239
+ }
240
+
241
+ // Claude 3.5 & 3.7 families (Sonnet, Haiku)
242
+ if (
243
+ id.includes("claude-3-5-sonnet") ||
244
+ id.includes("claude-3-5-haiku") ||
245
+ id.includes("claude-3-7-sonnet")
246
+ ) {
247
+ return true;
248
+ }
249
+
250
+ // Claude 3 Haiku & Claude 3 Opus
251
+ if (id.includes("claude-3-haiku") || id.includes("claude-3-opus")) {
252
+ return true;
253
+ }
254
+
255
+ // Claude 4+ & 5+ families (Sonnet 4+, Opus 4+, Haiku 4+, Sonnet 5, Opus 5, etc.)
256
+ // Matches "claude-sonnet-4", "claude-opus-4", "claude-haiku-4", "claude-sonnet-5", "claude-4-sonnet", etc.
257
+ if (
258
+ /claude-(?:sonnet|opus|haiku)-[4-9]/.test(id) ||
259
+ /claude-[4-9]-(?:sonnet|opus|haiku)/.test(id)
260
+ ) {
261
+ return true;
262
+ }
263
+
264
+ return false;
265
+ }
266
+
267
+ /**
268
+ * Maps incoming content blocks to Anthropic Messages format.
269
+ * Preserves caller-specified `cache_control` blocks if already present on incoming blocks
270
+ * (e.g. from orchestrators or replayed conversation history).
271
+ */
202
272
  function mapAnthropicContent(blocks: any[], model: string): any[] {
203
273
  const content: any[] = [];
204
274
  const canSendImages = canSendNativeImage(model);
@@ -210,7 +280,11 @@ function mapAnthropicContent(blocks: any[], model: string): any[] {
210
280
  continue;
211
281
  }
212
282
 
213
- content.push({ type: "text", text });
283
+ content.push({
284
+ type: "text",
285
+ text,
286
+ ...(block.cache_control && { cache_control: block.cache_control }),
287
+ });
214
288
 
215
289
  continue;
216
290
  }
@@ -269,6 +343,7 @@ function mapAnthropicContent(blocks: any[], model: string): any[] {
269
343
  media_type: block.mimeType,
270
344
  data: block.data,
271
345
  },
346
+ ...(block.cache_control && { cache_control: block.cache_control }),
272
347
  });
273
348
  } else if (
274
349
  block.mediaType === "document" &&
@@ -283,11 +358,13 @@ function mapAnthropicContent(blocks: any[], model: string): any[] {
283
358
  media_type: "application/pdf",
284
359
  data: block.data,
285
360
  },
361
+ ...(block.cache_control && { cache_control: block.cache_control }),
286
362
  });
287
363
  } else {
288
364
  content.push({
289
365
  type: "text",
290
366
  text: formatAttachmentFallbackText(block),
367
+ ...(block.cache_control && { cache_control: block.cache_control }),
291
368
  });
292
369
  }
293
370
  }
@@ -600,16 +677,22 @@ class AnthropicAdapter extends BaseAdapter {
600
677
  },
601
678
  ): any {
602
679
  const { model, maxTokens, system, reasoning } = options;
680
+ const modelInfo = modelRegistry.getModelInfo(model);
681
+ const explicitlyUnsupported =
682
+ isLegacyClaudeModel(model) || modelInfo?.supportsPromptCaching === false;
603
683
  const cacheEnabled =
604
- options.promptCaching !== false && supportsPromptCaching(model);
684
+ !explicitlyUnsupported &&
685
+ (options.promptCaching === true ||
686
+ (options.promptCaching !== false && supportsPromptCaching(model)));
605
687
 
606
688
  // Messages are already in Anthropic format internally.
607
689
  // Filter out system messages (system is passed separately).
690
+ // Always clone message objects so formatting never mutates the caller's array.
608
691
  const filteredMessages = messages
609
692
  .filter((msg) => msg.role !== "system")
610
693
  .map((msg) => {
611
694
  if (!Array.isArray(msg.content)) {
612
- return msg;
695
+ return { ...msg };
613
696
  }
614
697
 
615
698
  return {
@@ -635,6 +718,47 @@ class AnthropicAdapter extends BaseAdapter {
635
718
  ? [{ type: "text", text: system, cache_control: { type: "ephemeral" } }]
636
719
  : system;
637
720
 
721
+ // For multi-turn conversations, place a cache breakpoint on the last user turn (up to 4 total checkpoints).
722
+ // Mutates only the newly cloned message objects in filteredMessages, leaving caller references untouched.
723
+ if (cacheEnabled && filteredMessages.length > 1) {
724
+ for (let i = filteredMessages.length - 1; i >= 0; i--) {
725
+ const msg = filteredMessages[i];
726
+ if (msg.role === "user") {
727
+ if (typeof msg.content === "string") {
728
+ filteredMessages[i] = {
729
+ ...msg,
730
+ content: [
731
+ {
732
+ type: "text",
733
+ text: msg.content,
734
+ cache_control: { type: "ephemeral" },
735
+ },
736
+ ],
737
+ };
738
+ } else if (Array.isArray(msg.content) && msg.content.length > 0) {
739
+ const updated = [...msg.content];
740
+ const lastIdx = updated.length - 1;
741
+ const lastBlock = updated[lastIdx];
742
+ if (
743
+ lastBlock &&
744
+ typeof lastBlock === "object" &&
745
+ !lastBlock.cache_control
746
+ ) {
747
+ updated[lastIdx] = {
748
+ ...lastBlock,
749
+ cache_control: { type: "ephemeral" },
750
+ };
751
+ filteredMessages[i] = {
752
+ ...msg,
753
+ content: updated,
754
+ };
755
+ }
756
+ }
757
+ break;
758
+ }
759
+ }
760
+ }
761
+
638
762
  const request: any = {
639
763
  model,
640
764
  max_tokens: maxTokens,