mycode-cli 0.1.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 (404) hide show
  1. mycode/__init__.py +1 -0
  2. mycode/cli/__init__.py +1 -0
  3. mycode/cli/chat.py +650 -0
  4. mycode/cli/main.py +245 -0
  5. mycode/cli/render.py +693 -0
  6. mycode/cli/runtime.py +271 -0
  7. mycode/cli/theme.py +109 -0
  8. mycode/core/__init__.py +30 -0
  9. mycode/core/agent.py +515 -0
  10. mycode/core/config.py +551 -0
  11. mycode/core/messages.py +166 -0
  12. mycode/core/models.py +144 -0
  13. mycode/core/models_catalog.json +2090 -0
  14. mycode/core/providers/__init__.py +86 -0
  15. mycode/core/providers/anthropic_like.py +366 -0
  16. mycode/core/providers/base.py +351 -0
  17. mycode/core/providers/gemini.py +321 -0
  18. mycode/core/providers/openai_chat.py +356 -0
  19. mycode/core/providers/openai_responses.py +326 -0
  20. mycode/core/session.py +537 -0
  21. mycode/core/system_prompt.md +10 -0
  22. mycode/core/system_prompt.py +319 -0
  23. mycode/core/tools.py +898 -0
  24. mycode/server/__init__.py +1 -0
  25. mycode/server/app.py +52 -0
  26. mycode/server/deps.py +29 -0
  27. mycode/server/routers/__init__.py +7 -0
  28. mycode/server/routers/chat.py +320 -0
  29. mycode/server/routers/sessions.py +77 -0
  30. mycode/server/routers/workspaces.py +92 -0
  31. mycode/server/run_manager.py +195 -0
  32. mycode/server/schemas.py +66 -0
  33. mycode/server/static/assets/EditDiff-C1ql7kft.js +12 -0
  34. mycode/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  35. mycode/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  36. mycode/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  37. mycode/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  38. mycode/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  39. mycode/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  40. mycode/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  41. mycode/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  42. mycode/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  43. mycode/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  44. mycode/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  45. mycode/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  46. mycode/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  47. mycode/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  48. mycode/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  49. mycode/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  50. mycode/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  51. mycode/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  52. mycode/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  53. mycode/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  54. mycode/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  55. mycode/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  56. mycode/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  57. mycode/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  58. mycode/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  59. mycode/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  60. mycode/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  61. mycode/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  62. mycode/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  63. mycode/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  64. mycode/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  65. mycode/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  66. mycode/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  67. mycode/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  68. mycode/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  69. mycode/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  70. mycode/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  71. mycode/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  72. mycode/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  73. mycode/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  74. mycode/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  75. mycode/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  76. mycode/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  77. mycode/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  78. mycode/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  79. mycode/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  80. mycode/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  81. mycode/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  82. mycode/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  83. mycode/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  84. mycode/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  85. mycode/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  86. mycode/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  87. mycode/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  88. mycode/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  89. mycode/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  90. mycode/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  91. mycode/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  92. mycode/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  93. mycode/server/static/assets/abap-BdImnpbu.js +1 -0
  94. mycode/server/static/assets/actionscript-3-CoDkCxhg.js +1 -0
  95. mycode/server/static/assets/ada-bCR0ucgS.js +1 -0
  96. mycode/server/static/assets/andromeeda-C4gqWexZ.js +1 -0
  97. mycode/server/static/assets/angular-html-DA-rfuFy.js +1 -0
  98. mycode/server/static/assets/angular-ts-BrjP3tb8.js +1 -0
  99. mycode/server/static/assets/apache-Pmp26Uib.js +1 -0
  100. mycode/server/static/assets/apex-D8_7TLub.js +1 -0
  101. mycode/server/static/assets/apl-CORt7UWP.js +1 -0
  102. mycode/server/static/assets/applescript-Co6uUVPk.js +1 -0
  103. mycode/server/static/assets/ara-BRHolxvo.js +1 -0
  104. mycode/server/static/assets/asciidoc-Ve4PFQV2.js +1 -0
  105. mycode/server/static/assets/asm-D_Q5rh1f.js +1 -0
  106. mycode/server/static/assets/astro-HNnZUWAn.js +1 -0
  107. mycode/server/static/assets/aurora-x-D-2ljcwZ.js +1 -0
  108. mycode/server/static/assets/auto-render-xntwXHOX.js +261 -0
  109. mycode/server/static/assets/awk-DMzUqQB5.js +1 -0
  110. mycode/server/static/assets/ayu-dark-DYE7WIF3.js +1 -0
  111. mycode/server/static/assets/ayu-light-BA47KaF1.js +1 -0
  112. mycode/server/static/assets/ayu-mirage-32ctXXKs.js +1 -0
  113. mycode/server/static/assets/ballerina-BFfxhgS-.js +1 -0
  114. mycode/server/static/assets/bat-BkioyH1T.js +1 -0
  115. mycode/server/static/assets/beancount-k_qm7-4y.js +1 -0
  116. mycode/server/static/assets/berry-uYugtg8r.js +1 -0
  117. mycode/server/static/assets/bibtex-CHM0blh-.js +1 -0
  118. mycode/server/static/assets/bicep-Bmn6On1c.js +1 -0
  119. mycode/server/static/assets/bird2-BIv1doCn.js +1 -0
  120. mycode/server/static/assets/blade-BjGOyj-B.js +1 -0
  121. mycode/server/static/assets/bsl-BO_Y6i37.js +1 -0
  122. mycode/server/static/assets/c-BIGW1oBm.js +1 -0
  123. mycode/server/static/assets/c3-eo99z4R2.js +1 -0
  124. mycode/server/static/assets/cadence-Bv_4Rxtq.js +1 -0
  125. mycode/server/static/assets/cairo-KRGpt6FW.js +1 -0
  126. mycode/server/static/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  127. mycode/server/static/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  128. mycode/server/static/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  129. mycode/server/static/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  130. mycode/server/static/assets/clarity-D53aC0YG.js +1 -0
  131. mycode/server/static/assets/clojure-P80f7IUj.js +1 -0
  132. mycode/server/static/assets/cmake-D1j8_8rp.js +1 -0
  133. mycode/server/static/assets/cobol-nBiQ_Alo.js +1 -0
  134. mycode/server/static/assets/codeowners-Bp6g37R7.js +1 -0
  135. mycode/server/static/assets/codeql-DsOJ9woJ.js +1 -0
  136. mycode/server/static/assets/coffee-Ch7k5sss.js +1 -0
  137. mycode/server/static/assets/common-lisp-Cg-RD9OK.js +1 -0
  138. mycode/server/static/assets/coq-DkFqJrB1.js +1 -0
  139. mycode/server/static/assets/cpp-CofmeUqb.js +1 -0
  140. mycode/server/static/assets/crystal-DNxU26gB.js +1 -0
  141. mycode/server/static/assets/csharp-COcwbKMJ.js +1 -0
  142. mycode/server/static/assets/css-CLj8gQPS.js +1 -0
  143. mycode/server/static/assets/csv-fuZLfV_i.js +1 -0
  144. mycode/server/static/assets/cue-D82EKSYY.js +1 -0
  145. mycode/server/static/assets/cypher-COkxafJQ.js +1 -0
  146. mycode/server/static/assets/d-85-TOEBH.js +1 -0
  147. mycode/server/static/assets/dark-plus-C3mMm8J8.js +1 -0
  148. mycode/server/static/assets/dart-bE4Kk8sk.js +1 -0
  149. mycode/server/static/assets/dax-CEL-wOlO.js +1 -0
  150. mycode/server/static/assets/desktop-BmXAJ9_W.js +1 -0
  151. mycode/server/static/assets/diff-D97Zzqfu.js +1 -0
  152. mycode/server/static/assets/docker-BcOcwvcX.js +1 -0
  153. mycode/server/static/assets/dotenv-Da5cRb03.js +1 -0
  154. mycode/server/static/assets/dracula-BzJJZx-M.js +1 -0
  155. mycode/server/static/assets/dracula-soft-BXkSAIEj.js +1 -0
  156. mycode/server/static/assets/dream-maker-BtqSS_iP.js +1 -0
  157. mycode/server/static/assets/edge-FbVlp4U3.js +1 -0
  158. mycode/server/static/assets/elixir-CkH2-t6x.js +1 -0
  159. mycode/server/static/assets/elm-DbKCFpqz.js +1 -0
  160. mycode/server/static/assets/emacs-lisp-CXvaQtF9.js +1 -0
  161. mycode/server/static/assets/erb-BYCe7drp.js +1 -0
  162. mycode/server/static/assets/erlang-DsQrWhSR.js +1 -0
  163. mycode/server/static/assets/everforest-dark-BgDCqdQA.js +1 -0
  164. mycode/server/static/assets/everforest-light-C8M2exoo.js +1 -0
  165. mycode/server/static/assets/fennel-BYunw83y.js +1 -0
  166. mycode/server/static/assets/fish-BvzEVeQv.js +1 -0
  167. mycode/server/static/assets/fluent-C4IJs8-o.js +1 -0
  168. mycode/server/static/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  169. mycode/server/static/assets/fortran-free-form-BxgE0vQu.js +1 -0
  170. mycode/server/static/assets/fsharp-CXgrBDvD.js +1 -0
  171. mycode/server/static/assets/gdresource-BOOCDP_w.js +1 -0
  172. mycode/server/static/assets/gdscript-C5YyOfLZ.js +1 -0
  173. mycode/server/static/assets/gdshader-DkwncUOv.js +1 -0
  174. mycode/server/static/assets/genie-D0YGMca9.js +1 -0
  175. mycode/server/static/assets/gherkin-DyxjwDmM.js +1 -0
  176. mycode/server/static/assets/git-commit-F4YmCXRG.js +1 -0
  177. mycode/server/static/assets/git-rebase-r7XF79zn.js +1 -0
  178. mycode/server/static/assets/github-dark-DHJKELXO.js +1 -0
  179. mycode/server/static/assets/github-dark-default-Cuk6v7N8.js +1 -0
  180. mycode/server/static/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  181. mycode/server/static/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  182. mycode/server/static/assets/github-light-DAi9KRSo.js +1 -0
  183. mycode/server/static/assets/github-light-default-D7oLnXFd.js +1 -0
  184. mycode/server/static/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  185. mycode/server/static/assets/gleam-BspZqrRM.js +1 -0
  186. mycode/server/static/assets/glimmer-js-ByusRIyA.js +1 -0
  187. mycode/server/static/assets/glimmer-ts-BfAWNZQY.js +1 -0
  188. mycode/server/static/assets/glsl-DplSGwfg.js +1 -0
  189. mycode/server/static/assets/gn-n2N0HUVH.js +1 -0
  190. mycode/server/static/assets/gnuplot-DdkO51Og.js +1 -0
  191. mycode/server/static/assets/go-C27-OAKa.js +1 -0
  192. mycode/server/static/assets/graphql-ChdNCCLP.js +1 -0
  193. mycode/server/static/assets/groovy-gcz8RCvz.js +1 -0
  194. mycode/server/static/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  195. mycode/server/static/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  196. mycode/server/static/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  197. mycode/server/static/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  198. mycode/server/static/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  199. mycode/server/static/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  200. mycode/server/static/assets/hack-i7_Ulhet.js +1 -0
  201. mycode/server/static/assets/haml-D5jkg6IW.js +1 -0
  202. mycode/server/static/assets/handlebars-BpdQsYii.js +1 -0
  203. mycode/server/static/assets/haskell-Df6bDoY_.js +1 -0
  204. mycode/server/static/assets/haxe-CzTSHFRz.js +1 -0
  205. mycode/server/static/assets/hcl-BWvSN4gD.js +1 -0
  206. mycode/server/static/assets/hjson-D5-asLiD.js +1 -0
  207. mycode/server/static/assets/hlsl-D3lLCCz7.js +1 -0
  208. mycode/server/static/assets/horizon-BUw7H-hv.js +1 -0
  209. mycode/server/static/assets/horizon-bright-CUuTKBJd.js +1 -0
  210. mycode/server/static/assets/houston-DnULxvSX.js +1 -0
  211. mycode/server/static/assets/html-derivative-DlHx6ybY.js +1 -0
  212. mycode/server/static/assets/html-pp8916En.js +1 -0
  213. mycode/server/static/assets/http-jrhK8wxY.js +1 -0
  214. mycode/server/static/assets/hurl-irOxFIW8.js +1 -0
  215. mycode/server/static/assets/hxml-Bvhsp5Yf.js +1 -0
  216. mycode/server/static/assets/hy-DFXneXwc.js +1 -0
  217. mycode/server/static/assets/imba-DGztddWO.js +1 -0
  218. mycode/server/static/assets/index-B4e4WQPq.css +1 -0
  219. mycode/server/static/assets/index-C2xTNJGd.js +203 -0
  220. mycode/server/static/assets/ini-BEwlwnbL.js +1 -0
  221. mycode/server/static/assets/java-CylS5w8V.js +1 -0
  222. mycode/server/static/assets/javascript-wDzz0qaB.js +1 -0
  223. mycode/server/static/assets/jinja-f2NsQr07.js +1 -0
  224. mycode/server/static/assets/jison-wvAkD_A8.js +1 -0
  225. mycode/server/static/assets/json-Cp-IABpG.js +1 -0
  226. mycode/server/static/assets/json5-C9tS-k6U.js +1 -0
  227. mycode/server/static/assets/jsonc-Des-eS-w.js +1 -0
  228. mycode/server/static/assets/jsonl-DcaNXYhu.js +1 -0
  229. mycode/server/static/assets/jsonnet-DFQXde-d.js +1 -0
  230. mycode/server/static/assets/jssm-C2t-YnRu.js +1 -0
  231. mycode/server/static/assets/jsx-g9-lgVsj.js +1 -0
  232. mycode/server/static/assets/julia-CxzCAyBv.js +1 -0
  233. mycode/server/static/assets/just-VxiPbLrw.js +1 -0
  234. mycode/server/static/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  235. mycode/server/static/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  236. mycode/server/static/assets/kanagawa-wave-DWedfzmr.js +1 -0
  237. mycode/server/static/assets/katex-DnJR2-55.css +1 -0
  238. mycode/server/static/assets/kdl-DV7GczEv.js +1 -0
  239. mycode/server/static/assets/kotlin-BdnUsdx6.js +1 -0
  240. mycode/server/static/assets/kusto-wEQ09or8.js +1 -0
  241. mycode/server/static/assets/laserwave-DUszq2jm.js +1 -0
  242. mycode/server/static/assets/latex-CWtU0Tv5.js +1 -0
  243. mycode/server/static/assets/lean-BZvkOJ9d.js +1 -0
  244. mycode/server/static/assets/less-B1dDrJ26.js +1 -0
  245. mycode/server/static/assets/light-plus-B7mTdjB0.js +1 -0
  246. mycode/server/static/assets/liquid-C0sCDyMI.js +1 -0
  247. mycode/server/static/assets/llvm-DjAJT7YJ.js +1 -0
  248. mycode/server/static/assets/log-2UxHyX5q.js +1 -0
  249. mycode/server/static/assets/logo-BtOb2qkB.js +1 -0
  250. mycode/server/static/assets/lua-BaeVxFsk.js +1 -0
  251. mycode/server/static/assets/luau-C-HG3fhB.js +1 -0
  252. mycode/server/static/assets/make-CHLpvVh8.js +1 -0
  253. mycode/server/static/assets/markdown-Cvjx9yec.js +1 -0
  254. mycode/server/static/assets/marko-DjSrsDqO.js +1 -0
  255. mycode/server/static/assets/material-theme-D5KoaKCx.js +1 -0
  256. mycode/server/static/assets/material-theme-darker-BfHTSMKl.js +1 -0
  257. mycode/server/static/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  258. mycode/server/static/assets/material-theme-ocean-CyktbL80.js +1 -0
  259. mycode/server/static/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  260. mycode/server/static/assets/matlab-D7o27uSR.js +1 -0
  261. mycode/server/static/assets/mdc-DTYItulj.js +1 -0
  262. mycode/server/static/assets/mdx-Cmh6b_Ma.js +1 -0
  263. mycode/server/static/assets/mermaid-mWjccvbQ.js +1 -0
  264. mycode/server/static/assets/min-dark-CafNBF8u.js +1 -0
  265. mycode/server/static/assets/min-light-CTRr51gU.js +1 -0
  266. mycode/server/static/assets/mipsasm-CKIfxQSi.js +1 -0
  267. mycode/server/static/assets/mojo-rZm6bMo-.js +1 -0
  268. mycode/server/static/assets/monokai-D4h5O-jR.js +1 -0
  269. mycode/server/static/assets/moonbit-_H4v1dQx.js +1 -0
  270. mycode/server/static/assets/move-IF9eRakj.js +1 -0
  271. mycode/server/static/assets/narrat-DRg8JJMk.js +1 -0
  272. mycode/server/static/assets/nextflow-C-mBbutL.js +1 -0
  273. mycode/server/static/assets/nextflow-groovy-vE_lwT2v.js +1 -0
  274. mycode/server/static/assets/nginx-BpAMiNFr.js +1 -0
  275. mycode/server/static/assets/night-owl-C39BiMTA.js +1 -0
  276. mycode/server/static/assets/night-owl-light-CMTm3GFP.js +1 -0
  277. mycode/server/static/assets/nim-BIad80T-.js +1 -0
  278. mycode/server/static/assets/nix-CwoSXNpI.js +1 -0
  279. mycode/server/static/assets/nord-Ddv68eIx.js +1 -0
  280. mycode/server/static/assets/nushell-Cz2AlsmD.js +1 -0
  281. mycode/server/static/assets/objective-c-DXmwc3jG.js +1 -0
  282. mycode/server/static/assets/objective-cpp-CLxacb5B.js +1 -0
  283. mycode/server/static/assets/ocaml-C0hk2d4L.js +1 -0
  284. mycode/server/static/assets/odin-BBf5iR-q.js +1 -0
  285. mycode/server/static/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  286. mycode/server/static/assets/one-light-C3Wv6jpd.js +1 -0
  287. mycode/server/static/assets/openscad-C4EeE6gA.js +1 -0
  288. mycode/server/static/assets/pascal-D93ZcfNL.js +1 -0
  289. mycode/server/static/assets/perl-NvoQZIq0.js +1 -0
  290. mycode/server/static/assets/php-R6g_5hLQ.js +1 -0
  291. mycode/server/static/assets/pkl-u5AG7uiY.js +1 -0
  292. mycode/server/static/assets/plastic-3e1v2bzS.js +1 -0
  293. mycode/server/static/assets/plsql-ChMvpjG-.js +1 -0
  294. mycode/server/static/assets/po-BTJTHyun.js +1 -0
  295. mycode/server/static/assets/poimandres-CS3Unz2-.js +1 -0
  296. mycode/server/static/assets/polar-C0HS_06l.js +1 -0
  297. mycode/server/static/assets/postcss-CXtECtnM.js +1 -0
  298. mycode/server/static/assets/powerquery-CEu0bR-o.js +1 -0
  299. mycode/server/static/assets/powershell-Dpen1YoG.js +1 -0
  300. mycode/server/static/assets/prisma-Dd19v3D-.js +1 -0
  301. mycode/server/static/assets/prolog-CbFg5uaA.js +1 -0
  302. mycode/server/static/assets/proto-C7zT0LnQ.js +1 -0
  303. mycode/server/static/assets/pug-DKIMFp6K.js +1 -0
  304. mycode/server/static/assets/puppet-BMWR74SV.js +1 -0
  305. mycode/server/static/assets/purescript-CklMAg4u.js +1 -0
  306. mycode/server/static/assets/python-B6aJPvgy.js +1 -0
  307. mycode/server/static/assets/qml-3beO22l8.js +1 -0
  308. mycode/server/static/assets/qmldir-C8lEn-DE.js +1 -0
  309. mycode/server/static/assets/qss-IeuSbFQv.js +1 -0
  310. mycode/server/static/assets/r-Dspwwk_N.js +1 -0
  311. mycode/server/static/assets/racket-BqYA7rlc.js +1 -0
  312. mycode/server/static/assets/raku-DXvB9xmW.js +1 -0
  313. mycode/server/static/assets/razor-BDqjjVU7.js +1 -0
  314. mycode/server/static/assets/red-bN70gL4F.js +1 -0
  315. mycode/server/static/assets/reg-C-SQnVFl.js +1 -0
  316. mycode/server/static/assets/regexp-CDVJQ6XC.js +1 -0
  317. mycode/server/static/assets/rel-C3B-1QV4.js +1 -0
  318. mycode/server/static/assets/riscv-BM1_JUlF.js +1 -0
  319. mycode/server/static/assets/ron-D8l8udqQ.js +1 -0
  320. mycode/server/static/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  321. mycode/server/static/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  322. mycode/server/static/assets/rose-pine-qdsjHGoJ.js +1 -0
  323. mycode/server/static/assets/rosmsg-BJDFO7_C.js +1 -0
  324. mycode/server/static/assets/rst-CRjBmOyv.js +1 -0
  325. mycode/server/static/assets/ruby-Wjq7vjNf.js +1 -0
  326. mycode/server/static/assets/rust-B1yitclQ.js +1 -0
  327. mycode/server/static/assets/sas-cz2c8ADy.js +1 -0
  328. mycode/server/static/assets/sass-Cj5Yp3dK.js +1 -0
  329. mycode/server/static/assets/scala-C151Ov-r.js +1 -0
  330. mycode/server/static/assets/scheme-C98Dy4si.js +1 -0
  331. mycode/server/static/assets/scss-D5BDwBP9.js +1 -0
  332. mycode/server/static/assets/sdbl-DVxCFoDh.js +1 -0
  333. mycode/server/static/assets/shaderlab-Dg9Lc6iA.js +1 -0
  334. mycode/server/static/assets/shellscript-Yzrsuije.js +1 -0
  335. mycode/server/static/assets/shellsession-BADoaaVG.js +1 -0
  336. mycode/server/static/assets/slack-dark-BthQWCQV.js +1 -0
  337. mycode/server/static/assets/slack-ochin-DqwNpetd.js +1 -0
  338. mycode/server/static/assets/smalltalk-BERRCDM3.js +1 -0
  339. mycode/server/static/assets/snazzy-light-Bw305WKR.js +1 -0
  340. mycode/server/static/assets/solarized-dark-DXbdFlpD.js +1 -0
  341. mycode/server/static/assets/solarized-light-L9t79GZl.js +1 -0
  342. mycode/server/static/assets/solidity-rGO070M0.js +1 -0
  343. mycode/server/static/assets/soy-8wufbnw4.js +1 -0
  344. mycode/server/static/assets/sparql-rVzFXLq3.js +1 -0
  345. mycode/server/static/assets/splunk-BtCnVYZw.js +1 -0
  346. mycode/server/static/assets/sql-BLtJtn59.js +1 -0
  347. mycode/server/static/assets/ssh-config-_ykCGR6B.js +1 -0
  348. mycode/server/static/assets/stata-BH5u7GGu.js +1 -0
  349. mycode/server/static/assets/stylus-BEDo0Tqx.js +1 -0
  350. mycode/server/static/assets/surrealql-Bq5Q-fJD.js +1 -0
  351. mycode/server/static/assets/svelte-Cy7k_4gC.js +1 -0
  352. mycode/server/static/assets/swift-D82vCrfD.js +1 -0
  353. mycode/server/static/assets/synthwave-84-CbfX1IO0.js +1 -0
  354. mycode/server/static/assets/system-verilog-CnnmHF94.js +1 -0
  355. mycode/server/static/assets/systemd-4A_iFExJ.js +1 -0
  356. mycode/server/static/assets/talonscript-CkByrt1z.js +1 -0
  357. mycode/server/static/assets/tasl-QIJgUcNo.js +1 -0
  358. mycode/server/static/assets/tcl-dwOrl1Do.js +1 -0
  359. mycode/server/static/assets/templ-DhtptRzy.js +1 -0
  360. mycode/server/static/assets/terraform-BETggiCN.js +1 -0
  361. mycode/server/static/assets/tex-idrVyKtj.js +1 -0
  362. mycode/server/static/assets/tokyo-night-hegEt444.js +1 -0
  363. mycode/server/static/assets/toml-vGWfd6FD.js +1 -0
  364. mycode/server/static/assets/ts-tags-DQrlYJgV.js +1 -0
  365. mycode/server/static/assets/tsv-B_m7g4N7.js +1 -0
  366. mycode/server/static/assets/tsx-COt5Ahok.js +1 -0
  367. mycode/server/static/assets/turtle-BsS91CYL.js +1 -0
  368. mycode/server/static/assets/twig-xg9kU7Mw.js +1 -0
  369. mycode/server/static/assets/typescript-BPQ3VLAy.js +1 -0
  370. mycode/server/static/assets/typespec-CAFt9gP4.js +1 -0
  371. mycode/server/static/assets/typst-DHCkPAjA.js +1 -0
  372. mycode/server/static/assets/v-BcVCzyr7.js +1 -0
  373. mycode/server/static/assets/vala-CsfeWuGM.js +1 -0
  374. mycode/server/static/assets/vb-D17OF-Vu.js +1 -0
  375. mycode/server/static/assets/verilog-BQ8w6xss.js +1 -0
  376. mycode/server/static/assets/vesper-DU1UobuO.js +1 -0
  377. mycode/server/static/assets/vhdl-CeAyd5Ju.js +1 -0
  378. mycode/server/static/assets/viml-CJc9bBzg.js +1 -0
  379. mycode/server/static/assets/vitesse-black-Bkuqu6BP.js +1 -0
  380. mycode/server/static/assets/vitesse-dark-D0r3Knsf.js +1 -0
  381. mycode/server/static/assets/vitesse-light-CVO1_9PV.js +1 -0
  382. mycode/server/static/assets/vue-D2xRrEX4.js +1 -0
  383. mycode/server/static/assets/vue-html-AaS7Mt5G.js +1 -0
  384. mycode/server/static/assets/vue-vine-BoDAl6tE.js +1 -0
  385. mycode/server/static/assets/vyper-CDx5xZoG.js +1 -0
  386. mycode/server/static/assets/wasm-CG6Dc4jp.js +1 -0
  387. mycode/server/static/assets/wasm-MzD3tlZU.js +1 -0
  388. mycode/server/static/assets/wenyan-BV7otONQ.js +1 -0
  389. mycode/server/static/assets/wgsl-Dx-B1_4e.js +1 -0
  390. mycode/server/static/assets/wikitext-BhOHFoWU.js +1 -0
  391. mycode/server/static/assets/wit-5i3qLPDT.js +1 -0
  392. mycode/server/static/assets/wolfram-lXgVvXCa.js +1 -0
  393. mycode/server/static/assets/xml-sdJ4AIDG.js +1 -0
  394. mycode/server/static/assets/xsl-CtQFsRM5.js +1 -0
  395. mycode/server/static/assets/yaml-Buea-lGh.js +1 -0
  396. mycode/server/static/assets/zenscript-DVFEvuxE.js +1 -0
  397. mycode/server/static/assets/zig-VOosw3JB.js +1 -0
  398. mycode/server/static/favicon_slashes.svg +12 -0
  399. mycode/server/static/index.html +35 -0
  400. mycode_cli-0.1.0.dist-info/METADATA +186 -0
  401. mycode_cli-0.1.0.dist-info/RECORD +404 -0
  402. mycode_cli-0.1.0.dist-info/WHEEL +4 -0
  403. mycode_cli-0.1.0.dist-info/entry_points.txt +2 -0
  404. mycode_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1 @@
1
+ """FastAPI server interface."""
mycode/server/app.py ADDED
@@ -0,0 +1,52 @@
1
+ """FastAPI application entry point."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ from fastapi import FastAPI
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.staticfiles import StaticFiles
9
+
10
+ from mycode.core.config import setup_logging
11
+ from mycode.server.routers import chat_router, sessions_router, workspaces_router
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def frontend_static_path() -> Path:
17
+ """Return the packaged frontend static directory."""
18
+
19
+ return Path(__file__).resolve().parent / "static"
20
+
21
+
22
+ def create_app(*, serve_frontend: bool = True) -> FastAPI:
23
+ """Create the FastAPI app."""
24
+ setup_logging()
25
+ application = FastAPI(title="mycode")
26
+
27
+ application.add_middleware(
28
+ CORSMiddleware,
29
+ allow_origins=["*"],
30
+ allow_methods=["*"],
31
+ allow_headers=["*"],
32
+ )
33
+
34
+ # Mount API routers
35
+ application.include_router(chat_router, prefix="/api")
36
+ application.include_router(sessions_router, prefix="/api")
37
+ application.include_router(workspaces_router, prefix="/api")
38
+
39
+ if not serve_frontend:
40
+ logger.info("frontend disabled; starting in API-only mode")
41
+ return application
42
+
43
+ frontend_static = frontend_static_path()
44
+ if frontend_static.is_dir():
45
+ application.mount("/", StaticFiles(directory=str(frontend_static), html=True), name="frontend")
46
+ else:
47
+ logger.warning("frontend assets not found at %s; starting in API-only mode", frontend_static)
48
+
49
+ return application
50
+
51
+
52
+ app = create_app()
mycode/server/deps.py ADDED
@@ -0,0 +1,29 @@
1
+ """Shared dependencies for server routers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from functools import lru_cache
6
+ from typing import Annotated
7
+
8
+ from fastapi import Depends
9
+
10
+ from mycode.core.session import SessionStore
11
+ from mycode.server.run_manager import RunManager
12
+
13
+
14
+ @lru_cache
15
+ def get_store() -> SessionStore:
16
+ """Return the shared session store for server requests."""
17
+
18
+ return SessionStore()
19
+
20
+
21
+ @lru_cache
22
+ def get_run_manager() -> RunManager:
23
+ """Return the shared in-process run manager."""
24
+
25
+ return RunManager()
26
+
27
+
28
+ StoreDep = Annotated[SessionStore, Depends(get_store)]
29
+ RunManagerDep = Annotated[RunManager, Depends(get_run_manager)]
@@ -0,0 +1,7 @@
1
+ """API routers package."""
2
+
3
+ from mycode.server.routers.chat import router as chat_router
4
+ from mycode.server.routers.sessions import router as sessions_router
5
+ from mycode.server.routers.workspaces import router as workspaces_router
6
+
7
+ __all__ = ["chat_router", "sessions_router", "workspaces_router"]
@@ -0,0 +1,320 @@
1
+ """Chat and run streaming API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ import os
8
+ from base64 import b64encode
9
+ from collections.abc import AsyncIterator
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ from fastapi import APIRouter, HTTPException, Request
14
+ from fastapi.responses import StreamingResponse
15
+
16
+ from mycode.core.agent import Agent
17
+ from mycode.core.config import (
18
+ get_settings,
19
+ normalize_reasoning_effort,
20
+ resolve_provider,
21
+ resolve_provider_choices,
22
+ )
23
+ from mycode.core.messages import build_message, flatten_message_text, image_block, text_block
24
+ from mycode.core.providers import get_provider_adapter, provider_default_models
25
+ from mycode.core.tools import detect_image_mime_type, resolve_path
26
+ from mycode.server.deps import RunManagerDep, StoreDep
27
+ from mycode.server.run_manager import ActiveRunError, RunState
28
+ from mycode.server.schemas import ChatRequest, StreamEvent
29
+
30
+ router = APIRouter()
31
+
32
+ REASONING_EFFORT_OPTIONS = ("auto", "none", "low", "medium", "high", "xhigh")
33
+
34
+
35
+ def _format_sse(event: StreamEvent) -> str:
36
+ return f"data: {json.dumps(event.model_dump(exclude_none=True), ensure_ascii=False)}\n\n"
37
+
38
+
39
+ async def _stream_run(req: Request, state: RunState, after: int) -> AsyncIterator[str]:
40
+ last_seq = max(0, after)
41
+
42
+ while True:
43
+ if await req.is_disconnected():
44
+ return
45
+
46
+ async with state.condition:
47
+ pending = [event for event in state.events if int(event.get("seq") or 0) > last_seq]
48
+ finished = state.status != "running"
49
+
50
+ if not pending and not finished:
51
+ try:
52
+ await asyncio.wait_for(state.condition.wait(), timeout=0.5)
53
+ except TimeoutError:
54
+ continue
55
+ continue
56
+
57
+ for payload in pending:
58
+ if await req.is_disconnected():
59
+ return
60
+ yield _format_sse(StreamEvent(**payload))
61
+ last_seq = int(payload.get("seq") or last_seq)
62
+
63
+ if finished:
64
+ break
65
+
66
+ yield "data: [DONE]\n\n"
67
+
68
+
69
+ @router.post("/chat")
70
+ async def chat(chat: ChatRequest, store: StoreDep, runs: RunManagerDep):
71
+ cwd = os.path.abspath(chat.cwd or os.getcwd())
72
+ settings = get_settings(cwd)
73
+ resolved = resolve_provider(
74
+ settings,
75
+ provider_name=chat.provider,
76
+ model=chat.model,
77
+ api_key=chat.api_key,
78
+ api_base=chat.api_base,
79
+ )
80
+ request_effort = normalize_reasoning_effort(chat.reasoning_effort)
81
+ reasoning_effort = request_effort if request_effort is not None else resolved.reasoning_effort
82
+ session_id = chat.session_id or "default"
83
+
84
+ if chat.message and chat.input:
85
+ raise HTTPException(status_code=400, detail="message and input are mutually exclusive")
86
+
87
+ if chat.input:
88
+ blocks: list[dict[str, Any]] = []
89
+ for block in chat.input:
90
+ if block.type == "text":
91
+ text = str(block.text or "")
92
+ if text:
93
+ blocks.append(text_block(text))
94
+ continue
95
+
96
+ if block.data:
97
+ # Inline base64 from web upload
98
+ if not block.mime_type:
99
+ raise HTTPException(status_code=400, detail="image data requires mime_type")
100
+ blocks.append(image_block(block.data, mime_type=block.mime_type, name=block.name or "image"))
101
+ continue
102
+
103
+ if not block.path:
104
+ raise HTTPException(status_code=400, detail="image input requires path or data")
105
+ resolved_path = resolve_path(block.path, cwd=cwd)
106
+ image_path = Path(resolved_path)
107
+ if not image_path.exists() or not image_path.is_file():
108
+ raise HTTPException(status_code=400, detail=f"image file not found: {block.path}")
109
+ mime_type = block.mime_type or detect_image_mime_type(image_path)
110
+ if not mime_type:
111
+ raise HTTPException(status_code=400, detail=f"unsupported image file: {block.path}")
112
+ image_data = b64encode(image_path.read_bytes()).decode("utf-8")
113
+ blocks.append(image_block(image_data, mime_type=mime_type, name=block.name or image_path.name))
114
+
115
+ if not blocks:
116
+ raise HTTPException(status_code=400, detail="input must include at least one non-empty block")
117
+ user_message = build_message("user", blocks)
118
+ else:
119
+ message_text = str(chat.message or "").strip()
120
+ if not message_text:
121
+ raise HTTPException(status_code=400, detail="message or input is required")
122
+ user_message = build_message("user", [text_block(message_text)])
123
+
124
+ if any(isinstance(block, dict) and block.get("type") == "image" for block in user_message.get("content") or []):
125
+ if resolved.supports_image_input is not True:
126
+ raise HTTPException(status_code=400, detail="current model does not support image input")
127
+
128
+ data = await store.load_session(session_id)
129
+ session = (data or {}).get("session")
130
+ messages = (data or {}).get("messages") or []
131
+
132
+ if not session and chat.rewind_to is not None:
133
+ raise HTTPException(status_code=400, detail="rewind_to requires an existing session")
134
+
135
+ if not session:
136
+ title = flatten_message_text(user_message).replace("\n", " ").strip()[:48] or "New chat"
137
+ created = await store.create_session(
138
+ title,
139
+ session_id=session_id,
140
+ provider=resolved.provider,
141
+ model=resolved.model,
142
+ cwd=cwd,
143
+ api_base=resolved.api_base,
144
+ )
145
+ session = created["session"]
146
+
147
+ if chat.rewind_to is not None:
148
+ if not (0 <= chat.rewind_to < len(messages)):
149
+ raise HTTPException(
150
+ status_code=400,
151
+ detail=f"rewind_to must reference a visible message index between 0 and {len(messages) - 1}",
152
+ )
153
+
154
+ target = messages[chat.rewind_to]
155
+ blocks = target.get("content")
156
+ has_user_content = isinstance(blocks, list) and any(
157
+ isinstance(block, dict)
158
+ and ((block.get("type") == "text" and block.get("text")) or block.get("type") == "image")
159
+ for block in blocks
160
+ )
161
+
162
+ # Rewind only makes sense for real user prompts. Synthetic compact
163
+ # summaries, assistant messages, and tool-result-only user messages are
164
+ # not valid targets.
165
+ if target.get("role") != "user" or (target.get("meta") or {}).get("synthetic") or not has_user_content:
166
+ raise HTTPException(
167
+ status_code=400,
168
+ detail="rewind_to must reference a real user message",
169
+ )
170
+
171
+ messages = messages[: chat.rewind_to]
172
+
173
+ agent = Agent(
174
+ model=resolved.model,
175
+ provider=resolved.provider,
176
+ cwd=cwd,
177
+ session_dir=store.session_dir(session_id),
178
+ session_id=session_id,
179
+ api_key=resolved.api_key,
180
+ api_base=resolved.api_base,
181
+ messages=messages,
182
+ settings=settings,
183
+ reasoning_effort=reasoning_effort,
184
+ supports_image_input=resolved.supports_image_input,
185
+ max_tokens=resolved.max_tokens,
186
+ context_window=resolved.context_window,
187
+ compact_threshold=settings.compact_threshold,
188
+ )
189
+
190
+ rewind_persisted = False
191
+
192
+ async def on_persist(message: dict) -> None:
193
+ nonlocal rewind_persisted
194
+ if chat.rewind_to is not None and not rewind_persisted:
195
+ await store.append_rewind(session_id, chat.rewind_to)
196
+ rewind_persisted = True
197
+ await store.append_message(
198
+ session_id,
199
+ message,
200
+ provider=resolved.provider,
201
+ model=resolved.model,
202
+ cwd=cwd,
203
+ api_base=resolved.api_base,
204
+ )
205
+
206
+ try:
207
+ run = await runs.start_run(
208
+ session_id=session_id,
209
+ user_message=user_message,
210
+ base_messages=messages,
211
+ agent=agent,
212
+ on_persist=on_persist,
213
+ )
214
+ except ActiveRunError as exc:
215
+ existing = await runs.get_run(exc.run_id)
216
+ detail: dict[str, Any] = {"message": "session already has a running task"}
217
+ if existing:
218
+ detail["run"] = existing.info()
219
+ raise HTTPException(status_code=409, detail=detail) from exc
220
+
221
+ return {"run": run, "session": session}
222
+
223
+
224
+ @router.get("/runs/{run_id}/stream")
225
+ async def stream_run(run_id: str, req: Request, runs: RunManagerDep, after: int = 0):
226
+ state = await runs.get_run(run_id)
227
+ if not state:
228
+ raise HTTPException(status_code=404, detail="run not found")
229
+
230
+ return StreamingResponse(
231
+ _stream_run(req, state, after),
232
+ media_type="text/event-stream",
233
+ headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"},
234
+ )
235
+
236
+
237
+ @router.post("/runs/{run_id}/cancel")
238
+ async def cancel_run(run_id: str, runs: RunManagerDep):
239
+ run = await runs.cancel_run(run_id)
240
+ if not run:
241
+ raise HTTPException(status_code=404, detail="run not found")
242
+ return {"status": "ok", "run": run}
243
+
244
+
245
+ @router.get("/config")
246
+ async def get_config(cwd: str | None = None):
247
+ resolved_cwd = os.path.abspath(cwd or os.getcwd())
248
+ settings = get_settings(resolved_cwd)
249
+ try:
250
+ resolved = resolve_provider(settings)
251
+ except ValueError as exc:
252
+ raise HTTPException(status_code=503, detail=str(exc)) from exc
253
+
254
+ providers_info: dict[str, Any] = {}
255
+ for provider in resolve_provider_choices(settings):
256
+ provider_config = settings.providers.get(provider.provider_name or "")
257
+ models = (
258
+ list(provider_config.models)
259
+ if provider_config and provider_config.models
260
+ else list(provider_default_models(provider.provider))
261
+ )
262
+ if not models:
263
+ models = [provider.model]
264
+
265
+ info: dict[str, Any] = {
266
+ "name": provider.provider_name,
267
+ "provider": provider.provider,
268
+ "type": provider.provider,
269
+ "models": models,
270
+ "base_url": provider.api_base or "",
271
+ "has_api_key": True,
272
+ }
273
+
274
+ image_models: list[str] = []
275
+ adapter = get_provider_adapter(provider.provider)
276
+ if adapter.supports_reasoning_effort:
277
+ reasoning_models: list[str] = []
278
+ for model in models:
279
+ resolved_model = resolve_provider(
280
+ settings,
281
+ provider_name=provider.provider_name or provider.provider,
282
+ model=model,
283
+ api_base=provider.api_base or None,
284
+ )
285
+ if resolved_model.supports_reasoning is True:
286
+ reasoning_models.append(model)
287
+ if resolved_model.supports_image_input is True:
288
+ image_models.append(model)
289
+
290
+ info["supports_reasoning_effort"] = True
291
+ info["reasoning_models"] = reasoning_models
292
+ info["reasoning_effort"] = provider.reasoning_effort
293
+ else:
294
+ for model in models:
295
+ resolved_model = resolve_provider(
296
+ settings,
297
+ provider_name=provider.provider_name or provider.provider,
298
+ model=model,
299
+ api_base=provider.api_base or None,
300
+ )
301
+ if resolved_model.supports_image_input is True:
302
+ image_models.append(model)
303
+
304
+ info["supports_image_input"] = bool(image_models)
305
+ info["image_input_models"] = image_models
306
+
307
+ providers_info[provider.provider_name or provider.provider] = info
308
+
309
+ return {
310
+ "providers": providers_info,
311
+ "default": {
312
+ "provider": resolved.provider_name,
313
+ "model": resolved.model,
314
+ },
315
+ "default_reasoning_effort": settings.default_reasoning_effort,
316
+ "reasoning_effort_options": REASONING_EFFORT_OPTIONS,
317
+ "cwd": resolved_cwd,
318
+ "workspace_root": settings.workspace_root,
319
+ "config_paths": settings.config_paths,
320
+ }
@@ -0,0 +1,77 @@
1
+ """Session management API endpoints."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+
7
+ from fastapi import APIRouter, HTTPException
8
+
9
+ from mycode.core.config import get_settings, resolve_provider
10
+ from mycode.server.deps import RunManagerDep, StoreDep
11
+ from mycode.server.schemas import SessionCreateRequest
12
+
13
+ router = APIRouter(prefix="/sessions", tags=["sessions"])
14
+
15
+
16
+ @router.post("")
17
+ async def create_session(req: SessionCreateRequest, store: StoreDep):
18
+ cwd = os.path.abspath(req.cwd or os.getcwd())
19
+ settings = get_settings(cwd)
20
+ resolved = resolve_provider(settings, provider_name=req.provider, model=req.model, api_base=req.api_base)
21
+ return await store.create_session(
22
+ req.title,
23
+ provider=resolved.provider,
24
+ model=resolved.model,
25
+ cwd=cwd,
26
+ api_base=resolved.api_base,
27
+ )
28
+
29
+
30
+ @router.get("")
31
+ async def list_sessions(store: StoreDep, runs: RunManagerDep, cwd: str | None = None):
32
+ sessions = await store.list_sessions(cwd=cwd)
33
+ for session in sessions:
34
+ session["is_running"] = await runs.has_active_run(session.get("id", ""))
35
+ return {"sessions": sessions}
36
+
37
+
38
+ @router.get("/{session_id}")
39
+ async def load_session(session_id: str, store: StoreDep, runs: RunManagerDep):
40
+ """Load a session, overlaying any active in-memory run state."""
41
+
42
+ data = await store.load_session(session_id)
43
+ session = data.get("session") if data else None
44
+ active = await runs.snapshot_session(session_id)
45
+ if active:
46
+ return {
47
+ "session": session,
48
+ "messages": active["messages"],
49
+ "active_run": active["run"],
50
+ "pending_events": active["pending_events"],
51
+ }
52
+
53
+ if not data:
54
+ return {"session": None, "messages": [], "active_run": None, "pending_events": []}
55
+
56
+ return {
57
+ "session": session,
58
+ "messages": data.get("messages") or [],
59
+ "active_run": None,
60
+ "pending_events": [],
61
+ }
62
+
63
+
64
+ @router.delete("/{session_id}")
65
+ async def delete_session(session_id: str, store: StoreDep, runs: RunManagerDep):
66
+ if await runs.has_active_run(session_id):
67
+ raise HTTPException(status_code=409, detail="session has a running task")
68
+ await store.delete_session(session_id)
69
+ return {"status": "ok"}
70
+
71
+
72
+ @router.post("/{session_id}/clear")
73
+ async def clear_session(session_id: str, store: StoreDep, runs: RunManagerDep):
74
+ if await runs.has_active_run(session_id):
75
+ raise HTTPException(status_code=409, detail="session has a running task")
76
+ await store.clear_session(session_id)
77
+ return {"status": "ok"}
@@ -0,0 +1,92 @@
1
+ """Workspace browsing API endpoints."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+
6
+ from fastapi import APIRouter
7
+
8
+ router = APIRouter(prefix="/workspaces", tags=["workspaces"])
9
+
10
+
11
+ def _parse_workspace_roots() -> list[Path]:
12
+ """Parse allowed workspace roots from environment variables."""
13
+ raw = os.environ.get("MYCODE_WORKSPACE_ROOTS") or os.environ.get("WORKSPACE_ROOTS")
14
+ if raw:
15
+ candidates = [item.strip() for item in raw.split(",") if item.strip()]
16
+ else:
17
+ candidates = [str(Path.home()), os.sep]
18
+
19
+ roots: list[Path] = []
20
+ seen: set[str] = set()
21
+ for value in candidates:
22
+ root = Path(value).expanduser().resolve(strict=False)
23
+ if not root.exists():
24
+ continue
25
+ key = str(root)
26
+ if key not in seen:
27
+ seen.add(key)
28
+ roots.append(root)
29
+
30
+ return roots or [Path(os.getcwd()).resolve(strict=False)]
31
+
32
+
33
+ @router.get("/roots")
34
+ async def list_workspace_roots():
35
+ """List workspace roots for browsing."""
36
+ return {"roots": [str(root) for root in _parse_workspace_roots()]}
37
+
38
+
39
+ @router.get("/browse")
40
+ async def browse_workspaces(root: str, path: str | None = None):
41
+ """Browse directories within a workspace root."""
42
+ root_path = None
43
+ requested_root = Path(root).expanduser().resolve(strict=False)
44
+ for allowed_root in _parse_workspace_roots():
45
+ if requested_root == allowed_root:
46
+ root_path = allowed_root
47
+ break
48
+
49
+ if not root_path:
50
+ return {"root": root, "path": "", "current": "", "entries": [], "error": "Invalid root"}
51
+
52
+ rel_path = Path(path) if path else Path()
53
+ target = (root_path / rel_path).resolve(strict=False)
54
+
55
+ try:
56
+ target.relative_to(root_path)
57
+ except ValueError:
58
+ return {
59
+ "root": str(root_path),
60
+ "path": "",
61
+ "current": str(root_path),
62
+ "entries": [],
63
+ "error": "Path outside root",
64
+ }
65
+
66
+ try:
67
+ entries: list[dict[str, str]] = []
68
+ for entry in sorted(target.iterdir(), key=lambda item: item.name.lower()):
69
+ try:
70
+ if entry.name.startswith("."):
71
+ continue
72
+ if entry.is_dir():
73
+ entries.append({"name": entry.name, "path": entry.relative_to(root_path).as_posix()})
74
+ except OSError:
75
+ continue
76
+ except OSError as exc:
77
+ return {
78
+ "root": str(root_path),
79
+ "path": "",
80
+ "current": str(root_path),
81
+ "entries": [],
82
+ "error": str(exc),
83
+ }
84
+
85
+ current_path = "" if target == root_path else target.relative_to(root_path).as_posix()
86
+ return {"root": str(root_path), "path": current_path, "current": str(target), "entries": entries, "error": ""}
87
+
88
+
89
+ @router.get("/cwd")
90
+ async def get_cwd():
91
+ """Get current working directory."""
92
+ return {"cwd": os.getcwd(), "exists": Path(os.getcwd()).exists()}