protolabs-agent 0.101.0__py3-none-any.whl

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 (609) hide show
  1. a2a_impl/__init__.py +1 -0
  2. a2a_impl/auth.py +437 -0
  3. a2a_impl/executor.py +675 -0
  4. a2a_impl/registry.py +164 -0
  5. a2a_impl/stores.py +584 -0
  6. activity/__init__.py +5 -0
  7. activity/store.py +142 -0
  8. apps/web/dist/_ds/plugin-kit.css +5454 -0
  9. apps/web/dist/_ds/plugin-kit.js +140 -0
  10. apps/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  11. apps/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  12. apps/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  13. apps/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  14. apps/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  15. apps/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  16. apps/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  17. apps/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  18. apps/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  19. apps/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  20. apps/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  21. apps/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  22. apps/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  23. apps/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  24. apps/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  25. apps/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  26. apps/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  27. apps/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  28. apps/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  29. apps/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  30. apps/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  31. apps/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  32. apps/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  33. apps/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  34. apps/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  35. apps/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  36. apps/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  37. apps/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  38. apps/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  39. apps/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  40. apps/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  41. apps/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  42. apps/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  43. apps/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  44. apps/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  45. apps/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  46. apps/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  47. apps/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  48. apps/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  49. apps/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  50. apps/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  51. apps/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  52. apps/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  53. apps/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  54. apps/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  55. apps/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  56. apps/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  57. apps/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  58. apps/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  59. apps/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  60. apps/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  61. apps/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  62. apps/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  63. apps/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  64. apps/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  65. apps/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  66. apps/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  67. apps/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  68. apps/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  69. apps/web/dist/assets/abap-BdImnpbu.js +1 -0
  70. apps/web/dist/assets/actionscript-3-CoDkCxhg.js +1 -0
  71. apps/web/dist/assets/ada-bCR0ucgS.js +1 -0
  72. apps/web/dist/assets/andromeeda-C4gqWexZ.js +1 -0
  73. apps/web/dist/assets/angular-html-CU67Zn6k.js +1 -0
  74. apps/web/dist/assets/angular-ts-BwZT4LLn.js +1 -0
  75. apps/web/dist/assets/apache-Pmp26Uib.js +1 -0
  76. apps/web/dist/assets/apex-D8_7TLub.js +1 -0
  77. apps/web/dist/assets/apl-dKokRX4l.js +1 -0
  78. apps/web/dist/assets/applescript-Co6uUVPk.js +1 -0
  79. apps/web/dist/assets/ara-BRHolxvo.js +1 -0
  80. apps/web/dist/assets/asciidoc-Ve4PFQV2.js +1 -0
  81. apps/web/dist/assets/asm-D_Q5rh1f.js +1 -0
  82. apps/web/dist/assets/astro-CbQHKStN.js +1 -0
  83. apps/web/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
  84. apps/web/dist/assets/awk-DMzUqQB5.js +1 -0
  85. apps/web/dist/assets/ayu-dark-DYE7WIF3.js +1 -0
  86. apps/web/dist/assets/ayu-light-BA47KaF1.js +1 -0
  87. apps/web/dist/assets/ayu-mirage-32ctXXKs.js +1 -0
  88. apps/web/dist/assets/ballerina-BFfxhgS-.js +1 -0
  89. apps/web/dist/assets/bat-BkioyH1T.js +1 -0
  90. apps/web/dist/assets/beancount-k_qm7-4y.js +1 -0
  91. apps/web/dist/assets/berry-uYugtg8r.js +1 -0
  92. apps/web/dist/assets/bibtex-CHM0blh-.js +1 -0
  93. apps/web/dist/assets/bicep-Bmn6On1c.js +1 -0
  94. apps/web/dist/assets/bird2-DPOp833l.js +1 -0
  95. apps/web/dist/assets/blade-D4QpJJKB.js +1 -0
  96. apps/web/dist/assets/bsl-BO_Y6i37.js +1 -0
  97. apps/web/dist/assets/c-BIGW1oBm.js +1 -0
  98. apps/web/dist/assets/c3-eo99z4R2.js +1 -0
  99. apps/web/dist/assets/cadence-Bv_4Rxtq.js +1 -0
  100. apps/web/dist/assets/cairo-KRGpt6FW.js +1 -0
  101. apps/web/dist/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  102. apps/web/dist/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  103. apps/web/dist/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  104. apps/web/dist/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  105. apps/web/dist/assets/clarity-D53aC0YG.js +1 -0
  106. apps/web/dist/assets/clojure-P80f7IUj.js +1 -0
  107. apps/web/dist/assets/cmake-D1j8_8rp.js +1 -0
  108. apps/web/dist/assets/cobol-nwyudZeR.js +1 -0
  109. apps/web/dist/assets/codeowners-Bp6g37R7.js +1 -0
  110. apps/web/dist/assets/codeql-DsOJ9woJ.js +1 -0
  111. apps/web/dist/assets/coffee-Ch7k5sss.js +1 -0
  112. apps/web/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
  113. apps/web/dist/assets/coq-DkFqJrB1.js +1 -0
  114. apps/web/dist/assets/cpp-CofmeUqb.js +1 -0
  115. apps/web/dist/assets/crystal-tKQVLTB8.js +1 -0
  116. apps/web/dist/assets/csharp-COcwbKMJ.js +1 -0
  117. apps/web/dist/assets/css-DPfMkruS.js +1 -0
  118. apps/web/dist/assets/csv-fuZLfV_i.js +1 -0
  119. apps/web/dist/assets/cue-D82EKSYY.js +1 -0
  120. apps/web/dist/assets/cypher-COkxafJQ.js +1 -0
  121. apps/web/dist/assets/d-85-TOEBH.js +1 -0
  122. apps/web/dist/assets/dark-plus-C3mMm8J8.js +1 -0
  123. apps/web/dist/assets/dart-CF10PKvl.js +1 -0
  124. apps/web/dist/assets/dax-CEL-wOlO.js +1 -0
  125. apps/web/dist/assets/desktop-BmXAJ9_W.js +1 -0
  126. apps/web/dist/assets/diff-D97Zzqfu.js +1 -0
  127. apps/web/dist/assets/docker-BcOcwvcX.js +1 -0
  128. apps/web/dist/assets/dotenv-Da5cRb03.js +1 -0
  129. apps/web/dist/assets/dracula-BzJJZx-M.js +1 -0
  130. apps/web/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
  131. apps/web/dist/assets/dream-maker-BtqSS_iP.js +1 -0
  132. apps/web/dist/assets/edge-BkV0erSs.js +1 -0
  133. apps/web/dist/assets/elixir-CDX3lj18.js +1 -0
  134. apps/web/dist/assets/elm-DbKCFpqz.js +1 -0
  135. apps/web/dist/assets/emacs-lisp-C9XAeP06.js +1 -0
  136. apps/web/dist/assets/erb-B12qg9BL.js +1 -0
  137. apps/web/dist/assets/erlang-DsQrWhSR.js +1 -0
  138. apps/web/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
  139. apps/web/dist/assets/everforest-light-C8M2exoo.js +1 -0
  140. apps/web/dist/assets/fennel-BYunw83y.js +1 -0
  141. apps/web/dist/assets/fish-BvzEVeQv.js +1 -0
  142. apps/web/dist/assets/fluent-C4IJs8-o.js +1 -0
  143. apps/web/dist/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  144. apps/web/dist/assets/fortran-free-form-BxgE0vQu.js +1 -0
  145. apps/web/dist/assets/fsharp-CXgrBDvD.js +1 -0
  146. apps/web/dist/assets/gdresource-BOOCDP_w.js +1 -0
  147. apps/web/dist/assets/gdscript-C5YyOfLZ.js +1 -0
  148. apps/web/dist/assets/gdshader-DkwncUOv.js +1 -0
  149. apps/web/dist/assets/genie-D0YGMca9.js +1 -0
  150. apps/web/dist/assets/gherkin-DyxjwDmM.js +1 -0
  151. apps/web/dist/assets/git-commit-F4YmCXRG.js +1 -0
  152. apps/web/dist/assets/git-rebase-r7XF79zn.js +1 -0
  153. apps/web/dist/assets/github-dark-DHJKELXO.js +1 -0
  154. apps/web/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
  155. apps/web/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  156. apps/web/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  157. apps/web/dist/assets/github-light-DAi9KRSo.js +1 -0
  158. apps/web/dist/assets/github-light-default-D7oLnXFd.js +1 -0
  159. apps/web/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  160. apps/web/dist/assets/gleam-BspZqrRM.js +1 -0
  161. apps/web/dist/assets/glimmer-js-Rg0-pVw9.js +1 -0
  162. apps/web/dist/assets/glimmer-ts-U6CK756n.js +1 -0
  163. apps/web/dist/assets/glsl-DplSGwfg.js +1 -0
  164. apps/web/dist/assets/gn-n2N0HUVH.js +1 -0
  165. apps/web/dist/assets/gnuplot-DdkO51Og.js +1 -0
  166. apps/web/dist/assets/go-CxLEBnE3.js +1 -0
  167. apps/web/dist/assets/graphql-ChdNCCLP.js +1 -0
  168. apps/web/dist/assets/groovy-gcz8RCvz.js +1 -0
  169. apps/web/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  170. apps/web/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  171. apps/web/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  172. apps/web/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  173. apps/web/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  174. apps/web/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  175. apps/web/dist/assets/hack-CaT9iCJl.js +1 -0
  176. apps/web/dist/assets/haml-B8DHNrY2.js +1 -0
  177. apps/web/dist/assets/handlebars-BL8al0AC.js +1 -0
  178. apps/web/dist/assets/haskell-Df6bDoY_.js +1 -0
  179. apps/web/dist/assets/haxe-CzTSHFRz.js +1 -0
  180. apps/web/dist/assets/hcl-BWvSN4gD.js +1 -0
  181. apps/web/dist/assets/highlighted-body-OFNGDK62-C7ptW_BO.js +1 -0
  182. apps/web/dist/assets/hjson-D5-asLiD.js +1 -0
  183. apps/web/dist/assets/hlsl-D3lLCCz7.js +1 -0
  184. apps/web/dist/assets/horizon-BUw7H-hv.js +1 -0
  185. apps/web/dist/assets/horizon-bright-Cn-bp-IR.js +1 -0
  186. apps/web/dist/assets/houston-DnULxvSX.js +1 -0
  187. apps/web/dist/assets/html-GMplVEZG.js +1 -0
  188. apps/web/dist/assets/html-derivative-BFtXZ54Q.js +1 -0
  189. apps/web/dist/assets/http-jrhK8wxY.js +1 -0
  190. apps/web/dist/assets/hurl-irOxFIW8.js +1 -0
  191. apps/web/dist/assets/hxml-Bvhsp5Yf.js +1 -0
  192. apps/web/dist/assets/hy-DFXneXwc.js +1 -0
  193. apps/web/dist/assets/imba-DGztddWO.js +1 -0
  194. apps/web/dist/assets/index-CN6bosuJ.css +1 -0
  195. apps/web/dist/assets/index-DNmZUlYg.js +739 -0
  196. apps/web/dist/assets/ini-BEwlwnbL.js +1 -0
  197. apps/web/dist/assets/java-CylS5w8V.js +1 -0
  198. apps/web/dist/assets/javascript-wDzz0qaB.js +1 -0
  199. apps/web/dist/assets/jinja-4LBKfQ-Z.js +1 -0
  200. apps/web/dist/assets/jison-wvAkD_A8.js +1 -0
  201. apps/web/dist/assets/json-Cp-IABpG.js +1 -0
  202. apps/web/dist/assets/json5-C9tS-k6U.js +1 -0
  203. apps/web/dist/assets/jsonc-Des-eS-w.js +1 -0
  204. apps/web/dist/assets/jsonl-DcaNXYhu.js +1 -0
  205. apps/web/dist/assets/jsonnet-DFQXde-d.js +1 -0
  206. apps/web/dist/assets/jssm-C2t-YnRu.js +1 -0
  207. apps/web/dist/assets/jsx-g9-lgVsj.js +1 -0
  208. apps/web/dist/assets/julia-CxzCAyBv.js +1 -0
  209. apps/web/dist/assets/just-Cw27pwNe.js +1 -0
  210. apps/web/dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  211. apps/web/dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  212. apps/web/dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
  213. apps/web/dist/assets/kdl-DV7GczEv.js +1 -0
  214. apps/web/dist/assets/kotlin-BdnUsdx6.js +1 -0
  215. apps/web/dist/assets/kusto-DZf3V79B.js +1 -0
  216. apps/web/dist/assets/laserwave-DUszq2jm.js +1 -0
  217. apps/web/dist/assets/latex-CWtU0Tv5.js +1 -0
  218. apps/web/dist/assets/lean-BZvkOJ9d.js +1 -0
  219. apps/web/dist/assets/less-B1dDrJ26.js +1 -0
  220. apps/web/dist/assets/light-plus-B7mTdjB0.js +1 -0
  221. apps/web/dist/assets/liquid-DYVedYrR.js +1 -0
  222. apps/web/dist/assets/llvm-DjAJT7YJ.js +1 -0
  223. apps/web/dist/assets/log-2UxHyX5q.js +1 -0
  224. apps/web/dist/assets/logo-BtOb2qkB.js +1 -0
  225. apps/web/dist/assets/lua-BaeVxFsk.js +1 -0
  226. apps/web/dist/assets/luau-C-HG3fhB.js +1 -0
  227. apps/web/dist/assets/lucide-react-DlS3kJDA.js +7156 -0
  228. apps/web/dist/assets/make-CHLpvVh8.js +1 -0
  229. apps/web/dist/assets/markdown-Cvjx9yec.js +1 -0
  230. apps/web/dist/assets/marko-CnJfTvn9.js +1 -0
  231. apps/web/dist/assets/material-theme-D5KoaKCx.js +1 -0
  232. apps/web/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
  233. apps/web/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  234. apps/web/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
  235. apps/web/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  236. apps/web/dist/assets/matlab-D7o27uSR.js +1 -0
  237. apps/web/dist/assets/mdc-BMNejdWA.js +1 -0
  238. apps/web/dist/assets/mdx-Cmh6b_Ma.js +1 -0
  239. apps/web/dist/assets/mermaid-GHXKKRXX-fpq-tWrh.js +544 -0
  240. apps/web/dist/assets/mermaid-mWjccvbQ.js +1 -0
  241. apps/web/dist/assets/min-dark-CafNBF8u.js +1 -0
  242. apps/web/dist/assets/min-light-CTRr51gU.js +1 -0
  243. apps/web/dist/assets/mipsasm-CKIfxQSi.js +1 -0
  244. apps/web/dist/assets/mojo-rZm6bMo-.js +1 -0
  245. apps/web/dist/assets/monokai-D4h5O-jR.js +1 -0
  246. apps/web/dist/assets/moonbit-_H4v1dQx.js +1 -0
  247. apps/web/dist/assets/move-IF9eRakj.js +1 -0
  248. apps/web/dist/assets/narrat-DRg8JJMk.js +1 -0
  249. apps/web/dist/assets/nextflow-Zz6hmt5N.js +1 -0
  250. apps/web/dist/assets/nextflow-groovy-BeH2EWoN.js +1 -0
  251. apps/web/dist/assets/nginx-BpAMiNFr.js +1 -0
  252. apps/web/dist/assets/night-owl-C39BiMTA.js +1 -0
  253. apps/web/dist/assets/night-owl-light-CMTm3GFP.js +1 -0
  254. apps/web/dist/assets/nim-CVrawwO9.js +1 -0
  255. apps/web/dist/assets/nix-CwoSXNpI.js +1 -0
  256. apps/web/dist/assets/nord-Ddv68eIx.js +1 -0
  257. apps/web/dist/assets/nushell-Cz2AlsmD.js +1 -0
  258. apps/web/dist/assets/objective-c-DXmwc3jG.js +1 -0
  259. apps/web/dist/assets/objective-cpp-CLxacb5B.js +1 -0
  260. apps/web/dist/assets/ocaml-C0hk2d4L.js +1 -0
  261. apps/web/dist/assets/odin-BBf5iR-q.js +1 -0
  262. apps/web/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  263. apps/web/dist/assets/one-light-C3Wv6jpd.js +1 -0
  264. apps/web/dist/assets/openscad-C4EeE6gA.js +1 -0
  265. apps/web/dist/assets/pascal-D93ZcfNL.js +1 -0
  266. apps/web/dist/assets/perl-C0TMdlhV.js +1 -0
  267. apps/web/dist/assets/php-Dhbhpdrm.js +1 -0
  268. apps/web/dist/assets/pkl-u5AG7uiY.js +1 -0
  269. apps/web/dist/assets/plastic-3e1v2bzS.js +1 -0
  270. apps/web/dist/assets/plsql-ChMvpjG-.js +1 -0
  271. apps/web/dist/assets/po-BTJTHyun.js +1 -0
  272. apps/web/dist/assets/poimandres-CS3Unz2-.js +1 -0
  273. apps/web/dist/assets/polar-C0HS_06l.js +1 -0
  274. apps/web/dist/assets/postcss-CXtECtnM.js +1 -0
  275. apps/web/dist/assets/powerquery-CEu0bR-o.js +1 -0
  276. apps/web/dist/assets/powershell-Dpen1YoG.js +1 -0
  277. apps/web/dist/assets/prisma-Dd19v3D-.js +1 -0
  278. apps/web/dist/assets/prolog-CbFg5uaA.js +1 -0
  279. apps/web/dist/assets/proto-C7zT0LnQ.js +1 -0
  280. apps/web/dist/assets/pug-CGlum2m_.js +1 -0
  281. apps/web/dist/assets/puppet-BMWR74SV.js +1 -0
  282. apps/web/dist/assets/purescript-CklMAg4u.js +1 -0
  283. apps/web/dist/assets/python-B6aJPvgy.js +1 -0
  284. apps/web/dist/assets/qml-3beO22l8.js +1 -0
  285. apps/web/dist/assets/qmldir-C8lEn-DE.js +1 -0
  286. apps/web/dist/assets/qss-IeuSbFQv.js +1 -0
  287. apps/web/dist/assets/r-Dspwwk_N.js +1 -0
  288. apps/web/dist/assets/racket-BqYA7rlc.js +1 -0
  289. apps/web/dist/assets/raku-DXvB9xmW.js +1 -0
  290. apps/web/dist/assets/razor-Uh8Bk_45.js +1 -0
  291. apps/web/dist/assets/red-bN70gL4F.js +1 -0
  292. apps/web/dist/assets/reg-C-SQnVFl.js +1 -0
  293. apps/web/dist/assets/regexp-CDVJQ6XC.js +1 -0
  294. apps/web/dist/assets/rel-C3B-1QV4.js +1 -0
  295. apps/web/dist/assets/riscv-BM1_JUlF.js +1 -0
  296. apps/web/dist/assets/ron-D8l8udqQ.js +1 -0
  297. apps/web/dist/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  298. apps/web/dist/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  299. apps/web/dist/assets/rose-pine-qdsjHGoJ.js +1 -0
  300. apps/web/dist/assets/rosmsg-BJDFO7_C.js +1 -0
  301. apps/web/dist/assets/rst-BrH8l1NY.js +1 -0
  302. apps/web/dist/assets/ruby-Dw2BHqvy.js +1 -0
  303. apps/web/dist/assets/rust-B1yitclQ.js +1 -0
  304. apps/web/dist/assets/sas-cz2c8ADy.js +1 -0
  305. apps/web/dist/assets/sass-Cj5Yp3dK.js +1 -0
  306. apps/web/dist/assets/scala-C151Ov-r.js +1 -0
  307. apps/web/dist/assets/scheme-C98Dy4si.js +1 -0
  308. apps/web/dist/assets/scss-OYdSNvt2.js +1 -0
  309. apps/web/dist/assets/sdbl-DVxCFoDh.js +1 -0
  310. apps/web/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
  311. apps/web/dist/assets/shellscript-Yzrsuije.js +1 -0
  312. apps/web/dist/assets/shellsession-BADoaaVG.js +1 -0
  313. apps/web/dist/assets/slack-dark-BthQWCQV.js +1 -0
  314. apps/web/dist/assets/slack-ochin-DqwNpetd.js +1 -0
  315. apps/web/dist/assets/smalltalk-BERRCDM3.js +1 -0
  316. apps/web/dist/assets/snazzy-light-Bw305WKR.js +1 -0
  317. apps/web/dist/assets/solarized-dark-DXbdFlpD.js +1 -0
  318. apps/web/dist/assets/solarized-light-L9t79GZl.js +1 -0
  319. apps/web/dist/assets/solidity-rGO070M0.js +1 -0
  320. apps/web/dist/assets/soy-Brmx7dQM.js +1 -0
  321. apps/web/dist/assets/sparql-rVzFXLq3.js +1 -0
  322. apps/web/dist/assets/splunk-BtCnVYZw.js +1 -0
  323. apps/web/dist/assets/sql-BLtJtn59.js +1 -0
  324. apps/web/dist/assets/ssh-config-_ykCGR6B.js +1 -0
  325. apps/web/dist/assets/stata-BH5u7GGu.js +1 -0
  326. apps/web/dist/assets/stylus-BEDo0Tqx.js +1 -0
  327. apps/web/dist/assets/surrealql-Bq5Q-fJD.js +1 -0
  328. apps/web/dist/assets/svelte-C_ipcX3V.js +1 -0
  329. apps/web/dist/assets/swift-D82vCrfD.js +1 -0
  330. apps/web/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
  331. apps/web/dist/assets/system-verilog-CnnmHF94.js +1 -0
  332. apps/web/dist/assets/systemd-4A_iFExJ.js +1 -0
  333. apps/web/dist/assets/talonscript-CkByrt1z.js +1 -0
  334. apps/web/dist/assets/tasl-QIJgUcNo.js +1 -0
  335. apps/web/dist/assets/tcl-dwOrl1Do.js +1 -0
  336. apps/web/dist/assets/templ-P3uqSqPl.js +1 -0
  337. apps/web/dist/assets/terraform-BETggiCN.js +1 -0
  338. apps/web/dist/assets/tex-idrVyKtj.js +1 -0
  339. apps/web/dist/assets/tokyo-night-hegEt444.js +1 -0
  340. apps/web/dist/assets/toml-vGWfd6FD.js +1 -0
  341. apps/web/dist/assets/ts-tags-zn1MmPIZ.js +1 -0
  342. apps/web/dist/assets/tsv-B_m7g4N7.js +1 -0
  343. apps/web/dist/assets/tsx-COt5Ahok.js +1 -0
  344. apps/web/dist/assets/turtle-BsS91CYL.js +1 -0
  345. apps/web/dist/assets/twig-DNn4PbVi.js +1 -0
  346. apps/web/dist/assets/typescript-BPQ3VLAy.js +1 -0
  347. apps/web/dist/assets/typespec-BGHnOYBU.js +1 -0
  348. apps/web/dist/assets/typst-DHCkPAjA.js +1 -0
  349. apps/web/dist/assets/v-BcVCzyr7.js +1 -0
  350. apps/web/dist/assets/vala-CsfeWuGM.js +1 -0
  351. apps/web/dist/assets/vb-D17OF-Vu.js +1 -0
  352. apps/web/dist/assets/verilog-BQ8w6xss.js +1 -0
  353. apps/web/dist/assets/vesper-DU1UobuO.js +1 -0
  354. apps/web/dist/assets/vhdl-CeAyd5Ju.js +1 -0
  355. apps/web/dist/assets/viml-CJc9bBzg.js +1 -0
  356. apps/web/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
  357. apps/web/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
  358. apps/web/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
  359. apps/web/dist/assets/vue-DN_0RTcg.js +1 -0
  360. apps/web/dist/assets/vue-html-AaS7Mt5G.js +1 -0
  361. apps/web/dist/assets/vue-vine-CQOfvN7w.js +1 -0
  362. apps/web/dist/assets/vyper-CDx5xZoG.js +1 -0
  363. apps/web/dist/assets/wasm-CG6Dc4jp.js +1 -0
  364. apps/web/dist/assets/wasm-MzD3tlZU.js +1 -0
  365. apps/web/dist/assets/wenyan-BV7otONQ.js +1 -0
  366. apps/web/dist/assets/wgsl-Dx-B1_4e.js +1 -0
  367. apps/web/dist/assets/wikitext-BhOHFoWU.js +1 -0
  368. apps/web/dist/assets/wit-5i3qLPDT.js +1 -0
  369. apps/web/dist/assets/wolfram-lXgVvXCa.js +1 -0
  370. apps/web/dist/assets/xml-sdJ4AIDG.js +1 -0
  371. apps/web/dist/assets/xsl-CtQFsRM5.js +1 -0
  372. apps/web/dist/assets/yaml-Buea-lGh.js +1 -0
  373. apps/web/dist/assets/zenscript-DVFEvuxE.js +1 -0
  374. apps/web/dist/assets/zig-VOosw3JB.js +1 -0
  375. apps/web/dist/favicon.svg +10 -0
  376. apps/web/dist/index.html +33 -0
  377. apps/web/dist/protolabs-icon-outline.svg +10 -0
  378. background/__init__.py +8 -0
  379. background/manager.py +659 -0
  380. background/store.py +404 -0
  381. config/SOUL.md +46 -0
  382. config/langgraph-config.example.yaml +363 -0
  383. config/mcp-catalog.json +152 -0
  384. config/plugin-catalog.json +101 -0
  385. config/skills/web-research/SKILL.md +60 -0
  386. config/soul-presets/base.md +36 -0
  387. config/soul-presets/blank.md +24 -0
  388. config/soul-presets/coding.md +37 -0
  389. config/soul-presets/generic-assistant.md +33 -0
  390. config/soul-presets/project-manager.md +40 -0
  391. config/soul-presets/research.md +35 -0
  392. enforcement/__init__.py +1 -0
  393. enforcement/rate_limiter.py +51 -0
  394. evals/README.md +194 -0
  395. evals/__init__.py +0 -0
  396. evals/client.py +405 -0
  397. evals/compare.py +94 -0
  398. evals/judge.py +109 -0
  399. evals/report.py +142 -0
  400. evals/retrieval.py +269 -0
  401. evals/retrieval_gold.yaml +130 -0
  402. evals/runner.py +708 -0
  403. evals/sweep.py +349 -0
  404. evals/tasks.json +406 -0
  405. evals/verify.py +242 -0
  406. evals/webhook.py +80 -0
  407. events/__init__.py +11 -0
  408. events/bus.py +170 -0
  409. graph/__init__.py +0 -0
  410. graph/agent.py +1052 -0
  411. graph/cache_warmer.py +155 -0
  412. graph/checkpoint_prune.py +222 -0
  413. graph/checkpointer.py +97 -0
  414. graph/compaction_op.py +222 -0
  415. graph/components.py +55 -0
  416. graph/config.py +1237 -0
  417. graph/config_explain.py +201 -0
  418. graph/config_io.py +1328 -0
  419. graph/conversation_harvest.py +172 -0
  420. graph/delegations.py +88 -0
  421. graph/extensions/__init__.py +0 -0
  422. graph/extensions/skills.py +86 -0
  423. graph/fleet/__init__.py +7 -0
  424. graph/fleet/cli.py +67 -0
  425. graph/fleet/discovery.py +381 -0
  426. graph/fleet/member_public.py +78 -0
  427. graph/fleet/proxy.py +234 -0
  428. graph/fleet/supervisor.py +954 -0
  429. graph/goals/__init__.py +13 -0
  430. graph/goals/controller.py +562 -0
  431. graph/goals/goal_turn.py +55 -0
  432. graph/goals/hooks.py +42 -0
  433. graph/goals/store.py +170 -0
  434. graph/goals/types.py +124 -0
  435. graph/goals/verifiers.py +372 -0
  436. graph/guardrails.py +97 -0
  437. graph/knobs.py +248 -0
  438. graph/lifecycle/__init__.py +39 -0
  439. graph/lifecycle/dispatch.py +194 -0
  440. graph/lifecycle/hooks.py +62 -0
  441. graph/llm.py +464 -0
  442. graph/memory_facts.py +207 -0
  443. graph/middleware/__init__.py +0 -0
  444. graph/middleware/audit.py +163 -0
  445. graph/middleware/compaction.py +39 -0
  446. graph/middleware/enforcement.py +88 -0
  447. graph/middleware/knowledge.py +471 -0
  448. graph/middleware/memory.py +491 -0
  449. graph/middleware/message_capture.py +32 -0
  450. graph/middleware/model_override.py +73 -0
  451. graph/middleware/multimodal_tool.py +85 -0
  452. graph/middleware/prompt_cache.py +93 -0
  453. graph/middleware/redaction.py +171 -0
  454. graph/middleware/request_context.py +61 -0
  455. graph/middleware/stall_guard.py +165 -0
  456. graph/middleware/steering.py +54 -0
  457. graph/middleware/subagent_fence.py +57 -0
  458. graph/middleware/tool_call_repair.py +65 -0
  459. graph/middleware/tool_deferral.py +110 -0
  460. graph/middleware/trace_context.py +121 -0
  461. graph/middleware/wait_yield.py +55 -0
  462. graph/model_cli.py +151 -0
  463. graph/model_window.py +107 -0
  464. graph/multimodal.py +199 -0
  465. graph/output_format.py +67 -0
  466. graph/plugins/__init__.py +16 -0
  467. graph/plugins/chat_surface.py +153 -0
  468. graph/plugins/cli.py +212 -0
  469. graph/plugins/host.py +44 -0
  470. graph/plugins/installer.py +1084 -0
  471. graph/plugins/loader.py +592 -0
  472. graph/plugins/manifest.py +438 -0
  473. graph/plugins/pconfig.py +175 -0
  474. graph/plugins/registry.py +497 -0
  475. graph/plugins/scaffold.py +521 -0
  476. graph/plugins/testkit.py +392 -0
  477. graph/prompts.py +264 -0
  478. graph/review/__init__.py +12 -0
  479. graph/review/findings.py +227 -0
  480. graph/rewind_op.py +179 -0
  481. graph/sdk.py +820 -0
  482. graph/settings_schema.py +1333 -0
  483. graph/skills/__init__.py +1 -0
  484. graph/skills/authoring.py +132 -0
  485. graph/skills/cli.py +144 -0
  486. graph/skills/curator.py +558 -0
  487. graph/skills/index.py +445 -0
  488. graph/skills/layered.py +142 -0
  489. graph/skills/loader.py +151 -0
  490. graph/slash_commands.py +263 -0
  491. graph/state.py +50 -0
  492. graph/steering.py +75 -0
  493. graph/structured_skill.py +79 -0
  494. graph/subagents/__init__.py +0 -0
  495. graph/subagents/config.py +610 -0
  496. graph/supervisor.py +330 -0
  497. graph/telemetry.py +174 -0
  498. graph/watches/__init__.py +7 -0
  499. graph/watches/controller.py +289 -0
  500. graph/watches/hooks.py +37 -0
  501. graph/watches/store.py +130 -0
  502. graph/watches/types.py +71 -0
  503. graph/workspaces/__init__.py +8 -0
  504. graph/workspaces/cli.py +84 -0
  505. graph/workspaces/manager.py +545 -0
  506. inbox/__init__.py +5 -0
  507. inbox/store.py +207 -0
  508. infra/__init__.py +1 -0
  509. infra/autostart.py +279 -0
  510. infra/cache.py +98 -0
  511. infra/media.py +287 -0
  512. infra/paths.py +704 -0
  513. infra/secrets/__init__.py +56 -0
  514. infra/secrets/base.py +126 -0
  515. infra/secrets/hydrate.py +317 -0
  516. infra/secrets/infisical.py +154 -0
  517. ingestion/__init__.py +44 -0
  518. ingestion/engine.py +419 -0
  519. knowledge/__init__.py +32 -0
  520. knowledge/backend.py +54 -0
  521. knowledge/chunking.py +156 -0
  522. knowledge/hybrid_store.py +486 -0
  523. knowledge/layered.py +141 -0
  524. knowledge/store.py +1231 -0
  525. knowledge/trust.py +88 -0
  526. observability/__init__.py +1 -0
  527. observability/audit.py +174 -0
  528. observability/injection_log.py +184 -0
  529. observability/logging_config.py +83 -0
  530. observability/metrics.py +185 -0
  531. observability/metrics_store.py +143 -0
  532. observability/pricing.py +82 -0
  533. observability/telemetry_store.py +264 -0
  534. observability/trace_export.py +374 -0
  535. observability/tracing.py +444 -0
  536. operator_api/__init__.py +1 -0
  537. operator_api/chat_routes.py +379 -0
  538. operator_api/config_routes.py +300 -0
  539. operator_api/console_handlers.py +671 -0
  540. operator_api/flags_routes.py +26 -0
  541. operator_api/fleet_routes.py +383 -0
  542. operator_api/injection_routes.py +144 -0
  543. operator_api/knowledge_routes.py +753 -0
  544. operator_api/mcp_routes.py +273 -0
  545. operator_api/memory_routes.py +252 -0
  546. operator_api/operations_routes.py +26 -0
  547. operator_api/paths.py +48 -0
  548. operator_api/plugin_routes.py +442 -0
  549. operator_api/routes.py +638 -0
  550. operator_api/runtime.py +168 -0
  551. operator_api/runtime_routes.py +63 -0
  552. operator_api/secrets_routes.py +120 -0
  553. operator_api/subagents.py +88 -0
  554. operator_api/telemetry_routes.py +132 -0
  555. operator_api/theme_routes.py +58 -0
  556. operator_api/web.py +86 -0
  557. ops/__init__.py +97 -0
  558. ops/cli.py +33 -0
  559. ops/config.py +85 -0
  560. ops/fleet.py +35 -0
  561. ops/knowledge.py +211 -0
  562. ops/plugins.py +121 -0
  563. protolabs_agent-0.101.0.dist-info/METADATA +35 -0
  564. protolabs_agent-0.101.0.dist-info/RECORD +609 -0
  565. protolabs_agent-0.101.0.dist-info/WHEEL +4 -0
  566. protolabs_agent-0.101.0.dist-info/entry_points.txt +2 -0
  567. protolabs_agent-0.101.0.dist-info/licenses/LICENSE +21 -0
  568. runtime/__init__.py +5 -0
  569. runtime/acp_agents.py +36 -0
  570. runtime/acp_runtime.py +332 -0
  571. runtime/cli.py +371 -0
  572. runtime/context.py +184 -0
  573. runtime/flags.py +140 -0
  574. runtime/operator_mcp_tools.py +118 -0
  575. runtime/state.py +96 -0
  576. scheduler/__init__.py +16 -0
  577. scheduler/interface.py +149 -0
  578. scheduler/local.py +761 -0
  579. security/__init__.py +1 -0
  580. security/egress.py +149 -0
  581. security/policy.py +108 -0
  582. server/__init__.py +1125 -0
  583. server/__main__.py +12 -0
  584. server/a2a.py +736 -0
  585. server/agent_init.py +2274 -0
  586. server/chat.py +2063 -0
  587. server/cli.py +294 -0
  588. server/knowledge_cli.py +57 -0
  589. server/media.py +32 -0
  590. server/operator_mcp.py +147 -0
  591. static/favicon.svg +10 -0
  592. static/icons/apple-touch-icon.png +0 -0
  593. static/icons/icon-192.png +0 -0
  594. static/icons/icon-192.svg +10 -0
  595. static/icons/icon-512.png +0 -0
  596. static/icons/icon-512.svg +10 -0
  597. static/manifest.json +31 -0
  598. static/sw.js +98 -0
  599. tasks/__init__.py +11 -0
  600. tasks/store.py +228 -0
  601. tools/__init__.py +0 -0
  602. tools/a2a_parse.py +37 -0
  603. tools/fallbacks.py +79 -0
  604. tools/fs_tools.py +316 -0
  605. tools/gh_cli.py +68 -0
  606. tools/lg_tools.py +1774 -0
  607. tools/mcp_session_pool.py +327 -0
  608. tools/mcp_tools.py +432 -0
  609. tools/shell.py +98 -0
a2a_impl/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """A2A protocol layer — request auth/origin, the AgentExecutor, and the durable task/push stores (split out of the root modules)."""
a2a_impl/auth.py ADDED
@@ -0,0 +1,437 @@
1
+ """Request-time auth + origin enforcement — default-deny posture.
2
+
3
+ ``a2a-sdk`` advertises security schemes on the agent card but does NOT enforce
4
+ them on the wire — enforcement is the host's job. This module is a small
5
+ Starlette/FastAPI middleware that guards **every** path except an explicit public
6
+ allowlist:
7
+
8
+ - **Bearer** — ``Authorization: Bearer <token>`` validated against the
9
+ configured token (``auth.token`` in YAML or ``A2A_AUTH_TOKEN`` env). No-op
10
+ when unset (open mode, logged at WARNING).
11
+ - **X-API-Key** — legacy ``<AGENT>_API_KEY`` header, validated when set.
12
+ - **Origin** — ``A2A_ALLOWED_ORIGINS`` allowlist for browser callers. No-op
13
+ when unset or ``*``.
14
+
15
+ Default-deny: anything NOT on the public allowlist requires auth. The SSE
16
+ endpoint ``/api/events`` accepts a short-lived HMAC query-string token so
17
+ browser ``EventSource`` clients (which cannot send ``Authorization`` headers)
18
+ can authenticate.
19
+
20
+ The active bearer token lives in a module-level holder so a wizard/drawer reload
21
+ can update it live via ``set_bearer_token`` without re-registering routes.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import base64
27
+ import hashlib
28
+ import hmac
29
+ import json
30
+ import logging
31
+ import os
32
+ import re
33
+ import time
34
+
35
+ from starlette.middleware.base import BaseHTTPMiddleware
36
+ from starlette.requests import Request
37
+ from starlette.responses import JSONResponse
38
+
39
+ logger = logging.getLogger(__name__)
40
+
41
+ # Live-updatable bearer token (None = open mode for bearer).
42
+ _BEARER: list[str | None] = [None]
43
+ # Optional federation token (ADR 0066) — a second credential confined to the /a2a + /v1
44
+ # consumer surfaces and DENIED the /api operator surface. None = no federation tier.
45
+ _FEDERATION: list[str | None] = [None]
46
+ # X-API-Key (env-seeded at install; constant for the process).
47
+ _API_KEY: list[str] = [""]
48
+ # Allowed origins: None = verification disabled; list = allowlist.
49
+ _ALLOWED_ORIGINS: list[list[str] | None] = [None]
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Public allowlist — paths/prefixes that pass WITHOUT auth.
53
+ # Everything else requires bearer / X-API-Key (default-deny).
54
+ # ---------------------------------------------------------------------------
55
+ _PUBLIC_PREFIXES = (
56
+ "/healthz",
57
+ "/.well-known/",
58
+ "/app",
59
+ "/manifest.json",
60
+ "/sw.js",
61
+ "/favicon.svg",
62
+ "/favicon.ico",
63
+ "/static/",
64
+ "/_ds/",
65
+ )
66
+
67
+ # /metrics is CONDITIONALLY public — see ``_metrics_public``. It carries
68
+ # operational data (model/tool inventory, cost, traffic) so it is exposed without
69
+ # auth only in open mode (no token configured). Once a bearer / X-API-Key gates
70
+ # the surface, the Prometheus scraper must authenticate too — set
71
+ # ``PROTOAGENT_PUBLIC_METRICS=1`` to keep it anonymous behind a network boundary.
72
+
73
+ # Plugin-declared auth-exempt prefixes. Set once at startup (and on reload) from
74
+ # enabled plugins' manifest ``public_paths`` — each already validated to the
75
+ # plugin's own ``/plugins/<id>/`` namespace by the manifest parser. This lets a
76
+ # plugin serve an inbound webhook (no bearer — verified by its own HMAC) or a
77
+ # public view page even when a bearer gates everything else. A plugin can ONLY
78
+ # exempt its own routes; ``set_public_prefixes`` rejects anything else as
79
+ # defence-in-depth.
80
+ _PLUGIN_PUBLIC: list[str] = []
81
+
82
+ # SSE token lifetime (seconds).
83
+ _SSE_TOKEN_LIFETIME = 30
84
+
85
+ # A plugin public-prefix must be a real SUBTREE of its own namespace —
86
+ # ``/plugins/<id>/…`` or ``/api/plugins/<id>/…`` with a trailing slash after the
87
+ # id segment — so a bare core route like ``/api/plugins/install`` can never be
88
+ # prefix-matched into the exempt set (defence-in-depth behind the manifest
89
+ # parser, which applies the same boundary).
90
+ _PLUGIN_NS_RE = re.compile(r"^/(?:api/)?plugins/[^/]+/")
91
+
92
+
93
+ def set_public_prefixes(prefixes) -> None:
94
+ """Replace the plugin-declared public-prefix set (idempotent + reload-safe).
95
+
96
+ Each prefix must live under a ``/plugins/<id>/`` namespace — a plugin can
97
+ exempt its own routes, never a core path. Non-conforming entries are dropped
98
+ with a warning."""
99
+ cleaned: list[str] = []
100
+ for p in prefixes or []:
101
+ s = str(p).strip()
102
+ if not s:
103
+ continue
104
+ if _PLUGIN_NS_RE.match(s):
105
+ cleaned.append(s)
106
+ else:
107
+ logger.warning(
108
+ "[a2a] ignoring plugin public prefix %r — must be under /plugins/<id>/ or /api/plugins/<id>/", s
109
+ )
110
+ _PLUGIN_PUBLIC[:] = cleaned
111
+ if cleaned:
112
+ logger.info("[a2a] %d plugin-declared auth-exempt path(s): %s", len(cleaned), ", ".join(cleaned))
113
+
114
+
115
+ def public_prefixes() -> list[str]:
116
+ """The live plugin-declared auth-exempt prefixes (post-validation) — exactly what
117
+ ``_is_public`` enforces. Served on the public-paths well-known endpoint so a fleet
118
+ hub can defer its public decision to this member (#1890)."""
119
+ return list(_PLUGIN_PUBLIC)
120
+
121
+
122
+ # Fleet-proxied member view pages (#1890). A member's plugin view page is public
123
+ # *chrome* on the member itself (see ``set_public_prefixes``) — but the console
124
+ # iframes it through the hub as ``/agents/<slug>/plugins/<id>/…``, a plain
125
+ # navigation that cannot carry the operator bearer, and the hub's own public list
126
+ # is built from the HUB's manifests (the member may run plugins the hub doesn't).
127
+ # The member is the authority on what it serves anonymously, so the hub defers:
128
+ # for a slug-prefixed path inside a plugin namespace, an injected async resolver
129
+ # ``(slug, rest) -> bool`` answers "would the member serve this anonymously?"
130
+ # (graph/fleet/member_public.py — fetched from the member's public-paths endpoint,
131
+ # TTL-cached, fail-closed). Injected from the server bootstrap so this module
132
+ # stays host-free.
133
+ _MEMBER_PUBLIC: list = [None]
134
+
135
+ _AGENTS_RE = re.compile(r"^/agents/([^/]+)(/.+)$")
136
+
137
+
138
+ def set_member_public_resolver(fn) -> None:
139
+ """Install the async ``(slug, rest) -> bool`` member-public resolver (None = off)."""
140
+ _MEMBER_PUBLIC[0] = fn
141
+
142
+
143
+ def _metrics_public() -> bool:
144
+ """Whether ``/metrics`` is reachable without auth.
145
+
146
+ Default: only in open mode (no bearer AND no X-API-Key configured), where the
147
+ whole surface is already unauthenticated. When any token gates the surface,
148
+ ``/metrics`` is gated too — unless ``PROTOAGENT_PUBLIC_METRICS=1`` keeps it
149
+ open for an anonymous Prometheus scraper fenced by a network boundary.
150
+ """
151
+ if os.environ.get("PROTOAGENT_PUBLIC_METRICS", "").strip().lower() in ("1", "true", "yes"):
152
+ return True
153
+ return _BEARER[0] is None and not _API_KEY[0]
154
+
155
+
156
+ def _is_public(path: str) -> bool:
157
+ """Return True when ``path`` is on the public allowlist (no auth needed)."""
158
+ if any(path.startswith(p) for p in _PUBLIC_PREFIXES):
159
+ return True
160
+ if any(path.startswith(p) for p in _PLUGIN_PUBLIC):
161
+ return True
162
+ if path.startswith("/metrics") and _metrics_public():
163
+ return True
164
+ return False
165
+
166
+
167
+ def _requires_operator(path: str) -> bool:
168
+ """Paths that require the OPERATOR credential (ADR 0066 R1 ceiling).
169
+
170
+ The ``/api`` operator/console surface — plugin install+enable (host code-exec),
171
+ config/SOUL rewrite, subagent runs, the operator goal set-path — is operator-only; a
172
+ configured federation token is denied it (403). ``/a2a`` + ``/v1`` are the
173
+ federation/consumer surfaces and are NOT operator-only. Public + SSE-token paths never
174
+ reach the ceiling (handled earlier in dispatch). The substring form also catches the
175
+ fleet-proxy variants (``/active/<slug>/api/…``, ``/agents/<slug>/api/…``)."""
176
+ return "/api/" in path or path == "/api" or path.endswith("/api")
177
+
178
+
179
+ def set_bearer_token(token: str | None) -> None:
180
+ """Update the active bearer token at runtime (wizard/drawer reload)."""
181
+ _BEARER[0] = (token or "").strip() or None
182
+
183
+
184
+ def set_federation_token(token: str | None) -> None:
185
+ """Update the federation token at runtime (wizard/drawer reload). None = no federation tier."""
186
+ _FEDERATION[0] = (token or "").strip() or None
187
+
188
+
189
+ def configure(
190
+ *, bearer_token: str | None, api_key: str, allowed_origins_raw: str, federation_token: str | None = None
191
+ ) -> None:
192
+ """Seed the guard at route-registration time.
193
+
194
+ Args:
195
+ bearer_token: from YAML ``auth.token``. The caller is authoritative:
196
+ ``None`` means "unspecified" and falls back to ``A2A_AUTH_TOKEN``;
197
+ an explicit ``""`` means "bearer off" (e.g. an apiKey-only agent)
198
+ and does NOT fall back — otherwise a stray env var would silently
199
+ enable bearer auth the card never advertises. Empty/whitespace ->
200
+ open mode.
201
+ api_key: the ``<AGENT>_API_KEY`` value; "" disables the X-API-Key check.
202
+ allowed_origins_raw: ``A2A_ALLOWED_ORIGINS`` value ("" = disabled,
203
+ "*" = disabled, else comma-separated allowlist).
204
+ """
205
+ raw_bearer = bearer_token if bearer_token is not None else os.environ.get("A2A_AUTH_TOKEN", "")
206
+ seed = (raw_bearer or "").strip()
207
+ _BEARER[0] = seed or None
208
+ if _BEARER[0] is None:
209
+ logger.warning("[a2a] A2A auth token not configured — endpoint is open")
210
+
211
+ # Federation token (ADR 0066) — same authoritative-vs-env-fallback rule as the bearer.
212
+ raw_fed = federation_token if federation_token is not None else os.environ.get("A2A_FEDERATION_TOKEN", "")
213
+ _FEDERATION[0] = (raw_fed or "").strip() or None
214
+ if _FEDERATION[0] is not None and _BEARER[0] is None:
215
+ logger.warning("[a2a] federation_token set but no operator bearer — federation tier is inert (open mode)")
216
+ if _FEDERATION[0] is not None and _FEDERATION[0] == _BEARER[0]:
217
+ logger.warning("[a2a] federation_token equals the operator token — federation tier collapses to operator")
218
+
219
+ _API_KEY[0] = api_key or ""
220
+
221
+ raw = (allowed_origins_raw or "").strip()
222
+ if not raw:
223
+ logger.warning("[a2a] A2A_ALLOWED_ORIGINS not set — origin verification disabled")
224
+ _ALLOWED_ORIGINS[0] = None
225
+ elif raw == "*":
226
+ _ALLOWED_ORIGINS[0] = None
227
+ else:
228
+ _ALLOWED_ORIGINS[0] = [o.strip().lower() for o in raw.split(",") if o.strip()]
229
+
230
+
231
+ # ---------------------------------------------------------------------------
232
+ # Short-lived SSE query-string token (Part 3)
233
+ # ---------------------------------------------------------------------------
234
+
235
+
236
+ def generate_sse_token(session_id: str = "") -> str:
237
+ """Return a base64url-encoded, HMAC-signed token valid for ``_SSE_TOKEN_LIFETIME`` seconds.
238
+
239
+ The token is a JSON payload ``{session_id, exp}`` concatenated with an
240
+ HMAC-SHA256 signature. The signing key is the active bearer token — when
241
+ no bearer is configured (open mode) the function returns an empty string
242
+ (SSE is already unrestricted).
243
+ """
244
+ key = _BEARER[0]
245
+ if not key:
246
+ return ""
247
+ payload = json.dumps({"sid": session_id, "exp": int(time.time()) + _SSE_TOKEN_LIFETIME}, separators=(",", ":"))
248
+ sig = hmac.new(key.encode(), payload.encode(), hashlib.sha256).digest()
249
+ return base64.urlsafe_b64encode(payload.encode() + b"." + sig).decode()
250
+
251
+
252
+ def _validate_sse_token(token: str) -> bool:
253
+ """Validate a query-string SSE token in constant time. Returns True when valid."""
254
+ key = _BEARER[0]
255
+ if not key:
256
+ return True # open mode — no bearer ⇒ no token needed
257
+ if not token:
258
+ return False
259
+ try:
260
+ raw = base64.urlsafe_b64decode(token.encode())
261
+ except Exception:
262
+ return False
263
+ # HMAC-SHA256 is always 32 bytes; the delimiter "." is the byte before it.
264
+ # Split by known offset instead of rsplit to avoid ambiguity when the
265
+ # signature bytes happen to contain 0x2e (".").
266
+ _SIG_LEN = 32
267
+ if len(raw) < _SIG_LEN + 2 or raw[-_SIG_LEN - 1 : -_SIG_LEN] != b".":
268
+ return False
269
+ payload_bytes = raw[: -_SIG_LEN - 1]
270
+ sig = raw[-_SIG_LEN:]
271
+ expected = hmac.new(key.encode(), payload_bytes, hashlib.sha256).digest()
272
+ if not hmac.compare_digest(sig, expected):
273
+ return False
274
+ try:
275
+ data = json.loads(payload_bytes)
276
+ except Exception:
277
+ return False
278
+ exp = data.get("exp", 0)
279
+ if time.time() > exp:
280
+ return False
281
+ return True
282
+
283
+
284
+ def _unauthorized(detail: str) -> JSONResponse:
285
+ return JSONResponse({"detail": detail}, status_code=401)
286
+
287
+
288
+ class A2AAuthMiddleware(BaseHTTPMiddleware):
289
+ """Default-deny auth: everything except the public allowlist requires auth."""
290
+
291
+ async def dispatch(self, request: Request, call_next):
292
+ path = request.url.path
293
+
294
+ # Public allowlist — pass without auth.
295
+ if _is_public(path):
296
+ return await call_next(request)
297
+
298
+ # Fleet-proxied member-public paths (#1890): ``/agents/<slug>/<rest>`` where
299
+ # ``<rest>`` sits inside a plugin namespace defers to the MEMBER's own public
300
+ # list — its view pages are public chrome THERE, and the iframe navigation
301
+ # cannot carry a bearer. Consulted only when a credential actually gates this
302
+ # hub (open mode passes below anyway) and only for the plugin namespace —
303
+ # never ``/agents/<slug>/api/…``. ``request.state.member_public`` tells the
304
+ # fleet proxy NOT to lend a stored remote bearer to this request.
305
+ resolver = _MEMBER_PUBLIC[0]
306
+ if resolver is not None and (_BEARER[0] is not None or _API_KEY[0]):
307
+ m = _AGENTS_RE.match(path)
308
+ if m and _PLUGIN_NS_RE.match(m.group(2)):
309
+ try:
310
+ member_public = await resolver(m.group(1), m.group(2))
311
+ except Exception: # noqa: BLE001 — resolver trouble = fail closed to normal auth
312
+ logger.exception("[a2a] member-public resolver failed for %s", path)
313
+ member_public = False
314
+ if member_public:
315
+ request.state.member_public = True
316
+ return await call_next(request)
317
+
318
+ # Core media store (#1929): ``/media/<file>`` serves tool-generated artifacts
319
+ # that the console chat renders as inline ``<img>`` tags — a plain browser
320
+ # fetch that cannot carry an Authorization header. Each saved URL carries a
321
+ # per-file HMAC signature minted at save time (``infra/media.py``); a request
322
+ # passes iff the signature verifies (or the store is explicitly opted public
323
+ # via ``media.public``). Anything else falls through to the normal bearer /
324
+ # X-API-Key checks below — default-deny holds.
325
+ if path.startswith("/media/"):
326
+ try:
327
+ from infra.media import request_allowed as _media_allowed
328
+
329
+ if _media_allowed(path, request.query_params.get("sig", "")):
330
+ return await call_next(request)
331
+ except Exception: # noqa: BLE001 — a check failure fails CLOSED to normal auth
332
+ logger.exception("[a2a] media access check failed for %s", path)
333
+
334
+ # SSE endpoint: accept either a valid query-string token OR a bearer header.
335
+ # The query token is for browser EventSource clients that cannot send headers.
336
+ if path == "/api/events" or path.endswith("/api/events"):
337
+ sse_token = request.query_params.get("token", "")
338
+ if _validate_sse_token(sse_token):
339
+ return await call_next(request)
340
+ # Fall through to the normal bearer/X-API-Key check below — a
341
+ # server-to-server caller with an Authorization header still passes.
342
+
343
+ # X-API-Key (legacy) — enforced only when configured.
344
+ api_key = _API_KEY[0]
345
+ if api_key and not hmac.compare_digest(request.headers.get("x-api-key", "") or "", api_key):
346
+ return _unauthorized("Unauthorized")
347
+
348
+ # Bearer — enforced only when configured. Classify which credential matched
349
+ # (ADR 0066): the operator token → full access; a configured federation token →
350
+ # the /a2a + /v1 consumer surfaces only (the /api ceiling below denies it the
351
+ # operator surface). Open mode + single-token mode resolve to operator (R3
352
+ # backward-compat: unset federation_token ⇒ this is the old single-token check).
353
+ active = _BEARER[0]
354
+ fed = _FEDERATION[0]
355
+ tier = "operator"
356
+ if active:
357
+ header = request.headers.get("Authorization", "")
358
+ if not header.startswith("Bearer "):
359
+ return _unauthorized("Unauthorized: expected 'Authorization: Bearer <token>'")
360
+ token = header[len("Bearer ") :]
361
+ # Constant-time compare against each configured secret; classify by which
362
+ # matched. Trust = the matched secret, never the path/Origin/loopback (R5).
363
+ is_operator = hmac.compare_digest(token, active)
364
+ is_federation = fed is not None and hmac.compare_digest(token, fed)
365
+ if is_operator:
366
+ tier = "operator"
367
+ elif is_federation:
368
+ tier = "federation"
369
+ else:
370
+ return _unauthorized("Unauthorized: invalid bearer token")
371
+
372
+ # R1 path ceiling (ADR 0066): a federation credential is denied the /api operator
373
+ # surface — otherwise the token split is cosmetic (it has RCE via
374
+ # /api/plugins/install anyway). /a2a + /v1 stay open to either tier.
375
+ if tier == "federation" and _requires_operator(path):
376
+ return JSONResponse({"detail": "Forbidden: operator credential required"}, status_code=403)
377
+ request.state.trust_tier = tier
378
+
379
+ # Origin — enforced only when an allowlist is set AND an Origin is
380
+ # present. Origin is a browser-only header; server-to-server callers
381
+ # (the hub, the LocalScheduler loopback) send none and must not be
382
+ # rejected for it.
383
+ allowed = _ALLOWED_ORIGINS[0]
384
+ if allowed is not None:
385
+ origin = request.headers.get("Origin")
386
+ if origin is not None and origin.lower() not in allowed:
387
+ return JSONResponse({"detail": "Forbidden: origin not allowed"}, status_code=403)
388
+
389
+ return await call_next(request)
390
+
391
+
392
+ def install(
393
+ app, *, bearer_token: str | None, api_key: str, allowed_origins_raw: str, federation_token: str | None = None
394
+ ) -> None:
395
+ """Configure the guard and add the middleware to ``app``."""
396
+ configure(
397
+ bearer_token=bearer_token,
398
+ api_key=api_key,
399
+ allowed_origins_raw=allowed_origins_raw,
400
+ federation_token=federation_token,
401
+ )
402
+ app.add_middleware(A2AAuthMiddleware)
403
+
404
+
405
+ _LOOPBACK_HOSTS = ("127.0.0.1", "localhost", "::1")
406
+
407
+
408
+ def evaluate_open_bind(host: str, *, bearer_configured: bool, allow_open: bool) -> tuple[bool, str | None]:
409
+ """Boot-time gate for binding a non-loopback host without an auth token.
410
+
411
+ An unauthenticated non-loopback bind exposes the full operator API
412
+ (plugin install+enable = code execution, config/SOUL rewrite, subagent
413
+ runs) to anything that can reach the port — so it is refused unless the
414
+ operator explicitly opts in with ``PROTOAGENT_ALLOW_OPEN=1`` (the posture
415
+ for binds fenced by a published-port/network-policy boundary, e.g. a
416
+ container publishing to 127.0.0.1 only).
417
+
418
+ Returns ``(allowed, message)``: ``(True, None)`` silent, ``(True, msg)``
419
+ allowed with a warning to log, ``(False, msg)`` refuse startup.
420
+ """
421
+ if host in _LOOPBACK_HOSTS or bearer_configured:
422
+ return True, None
423
+ if allow_open:
424
+ return True, (
425
+ f"[security] binding {host} with NO A2A auth token "
426
+ "(PROTOAGENT_ALLOW_OPEN=1) — the agent + operator API are open to "
427
+ "anything that can reach this port. Make sure a network boundary "
428
+ "(localhost-published port, firewall, network policy) fences it."
429
+ )
430
+ return False, (
431
+ f"[security] refusing to bind {host} with NO A2A auth token — the "
432
+ "operator API (/api/*, /v1/*) includes plugin install/enable (code "
433
+ "execution) and config rewrite. Set auth.token in "
434
+ "langgraph-config.yaml or A2A_AUTH_TOKEN, bind 127.0.0.1 (the "
435
+ "default), or set PROTOAGENT_ALLOW_OPEN=1 if a network boundary "
436
+ "fences this port."
437
+ )