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.
- mycode/__init__.py +1 -0
- mycode/cli/__init__.py +1 -0
- mycode/cli/chat.py +650 -0
- mycode/cli/main.py +245 -0
- mycode/cli/render.py +693 -0
- mycode/cli/runtime.py +271 -0
- mycode/cli/theme.py +109 -0
- mycode/core/__init__.py +30 -0
- mycode/core/agent.py +515 -0
- mycode/core/config.py +551 -0
- mycode/core/messages.py +166 -0
- mycode/core/models.py +144 -0
- mycode/core/models_catalog.json +2090 -0
- mycode/core/providers/__init__.py +86 -0
- mycode/core/providers/anthropic_like.py +366 -0
- mycode/core/providers/base.py +351 -0
- mycode/core/providers/gemini.py +321 -0
- mycode/core/providers/openai_chat.py +356 -0
- mycode/core/providers/openai_responses.py +326 -0
- mycode/core/session.py +537 -0
- mycode/core/system_prompt.md +10 -0
- mycode/core/system_prompt.py +319 -0
- mycode/core/tools.py +898 -0
- mycode/server/__init__.py +1 -0
- mycode/server/app.py +52 -0
- mycode/server/deps.py +29 -0
- mycode/server/routers/__init__.py +7 -0
- mycode/server/routers/chat.py +320 -0
- mycode/server/routers/sessions.py +77 -0
- mycode/server/routers/workspaces.py +92 -0
- mycode/server/run_manager.py +195 -0
- mycode/server/schemas.py +66 -0
- mycode/server/static/assets/EditDiff-C1ql7kft.js +12 -0
- mycode/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- mycode/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- mycode/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- mycode/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- mycode/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- mycode/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- mycode/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- mycode/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- mycode/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- mycode/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- mycode/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- mycode/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- mycode/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- mycode/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- mycode/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- mycode/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- mycode/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- mycode/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- mycode/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- mycode/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- mycode/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- mycode/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- mycode/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- mycode/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- mycode/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- mycode/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- mycode/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- mycode/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- mycode/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- mycode/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- mycode/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- mycode/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- mycode/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- mycode/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- mycode/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- mycode/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- mycode/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- mycode/server/static/assets/abap-BdImnpbu.js +1 -0
- mycode/server/static/assets/actionscript-3-CoDkCxhg.js +1 -0
- mycode/server/static/assets/ada-bCR0ucgS.js +1 -0
- mycode/server/static/assets/andromeeda-C4gqWexZ.js +1 -0
- mycode/server/static/assets/angular-html-DA-rfuFy.js +1 -0
- mycode/server/static/assets/angular-ts-BrjP3tb8.js +1 -0
- mycode/server/static/assets/apache-Pmp26Uib.js +1 -0
- mycode/server/static/assets/apex-D8_7TLub.js +1 -0
- mycode/server/static/assets/apl-CORt7UWP.js +1 -0
- mycode/server/static/assets/applescript-Co6uUVPk.js +1 -0
- mycode/server/static/assets/ara-BRHolxvo.js +1 -0
- mycode/server/static/assets/asciidoc-Ve4PFQV2.js +1 -0
- mycode/server/static/assets/asm-D_Q5rh1f.js +1 -0
- mycode/server/static/assets/astro-HNnZUWAn.js +1 -0
- mycode/server/static/assets/aurora-x-D-2ljcwZ.js +1 -0
- mycode/server/static/assets/auto-render-xntwXHOX.js +261 -0
- mycode/server/static/assets/awk-DMzUqQB5.js +1 -0
- mycode/server/static/assets/ayu-dark-DYE7WIF3.js +1 -0
- mycode/server/static/assets/ayu-light-BA47KaF1.js +1 -0
- mycode/server/static/assets/ayu-mirage-32ctXXKs.js +1 -0
- mycode/server/static/assets/ballerina-BFfxhgS-.js +1 -0
- mycode/server/static/assets/bat-BkioyH1T.js +1 -0
- mycode/server/static/assets/beancount-k_qm7-4y.js +1 -0
- mycode/server/static/assets/berry-uYugtg8r.js +1 -0
- mycode/server/static/assets/bibtex-CHM0blh-.js +1 -0
- mycode/server/static/assets/bicep-Bmn6On1c.js +1 -0
- mycode/server/static/assets/bird2-BIv1doCn.js +1 -0
- mycode/server/static/assets/blade-BjGOyj-B.js +1 -0
- mycode/server/static/assets/bsl-BO_Y6i37.js +1 -0
- mycode/server/static/assets/c-BIGW1oBm.js +1 -0
- mycode/server/static/assets/c3-eo99z4R2.js +1 -0
- mycode/server/static/assets/cadence-Bv_4Rxtq.js +1 -0
- mycode/server/static/assets/cairo-KRGpt6FW.js +1 -0
- mycode/server/static/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- mycode/server/static/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- mycode/server/static/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- mycode/server/static/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- mycode/server/static/assets/clarity-D53aC0YG.js +1 -0
- mycode/server/static/assets/clojure-P80f7IUj.js +1 -0
- mycode/server/static/assets/cmake-D1j8_8rp.js +1 -0
- mycode/server/static/assets/cobol-nBiQ_Alo.js +1 -0
- mycode/server/static/assets/codeowners-Bp6g37R7.js +1 -0
- mycode/server/static/assets/codeql-DsOJ9woJ.js +1 -0
- mycode/server/static/assets/coffee-Ch7k5sss.js +1 -0
- mycode/server/static/assets/common-lisp-Cg-RD9OK.js +1 -0
- mycode/server/static/assets/coq-DkFqJrB1.js +1 -0
- mycode/server/static/assets/cpp-CofmeUqb.js +1 -0
- mycode/server/static/assets/crystal-DNxU26gB.js +1 -0
- mycode/server/static/assets/csharp-COcwbKMJ.js +1 -0
- mycode/server/static/assets/css-CLj8gQPS.js +1 -0
- mycode/server/static/assets/csv-fuZLfV_i.js +1 -0
- mycode/server/static/assets/cue-D82EKSYY.js +1 -0
- mycode/server/static/assets/cypher-COkxafJQ.js +1 -0
- mycode/server/static/assets/d-85-TOEBH.js +1 -0
- mycode/server/static/assets/dark-plus-C3mMm8J8.js +1 -0
- mycode/server/static/assets/dart-bE4Kk8sk.js +1 -0
- mycode/server/static/assets/dax-CEL-wOlO.js +1 -0
- mycode/server/static/assets/desktop-BmXAJ9_W.js +1 -0
- mycode/server/static/assets/diff-D97Zzqfu.js +1 -0
- mycode/server/static/assets/docker-BcOcwvcX.js +1 -0
- mycode/server/static/assets/dotenv-Da5cRb03.js +1 -0
- mycode/server/static/assets/dracula-BzJJZx-M.js +1 -0
- mycode/server/static/assets/dracula-soft-BXkSAIEj.js +1 -0
- mycode/server/static/assets/dream-maker-BtqSS_iP.js +1 -0
- mycode/server/static/assets/edge-FbVlp4U3.js +1 -0
- mycode/server/static/assets/elixir-CkH2-t6x.js +1 -0
- mycode/server/static/assets/elm-DbKCFpqz.js +1 -0
- mycode/server/static/assets/emacs-lisp-CXvaQtF9.js +1 -0
- mycode/server/static/assets/erb-BYCe7drp.js +1 -0
- mycode/server/static/assets/erlang-DsQrWhSR.js +1 -0
- mycode/server/static/assets/everforest-dark-BgDCqdQA.js +1 -0
- mycode/server/static/assets/everforest-light-C8M2exoo.js +1 -0
- mycode/server/static/assets/fennel-BYunw83y.js +1 -0
- mycode/server/static/assets/fish-BvzEVeQv.js +1 -0
- mycode/server/static/assets/fluent-C4IJs8-o.js +1 -0
- mycode/server/static/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- mycode/server/static/assets/fortran-free-form-BxgE0vQu.js +1 -0
- mycode/server/static/assets/fsharp-CXgrBDvD.js +1 -0
- mycode/server/static/assets/gdresource-BOOCDP_w.js +1 -0
- mycode/server/static/assets/gdscript-C5YyOfLZ.js +1 -0
- mycode/server/static/assets/gdshader-DkwncUOv.js +1 -0
- mycode/server/static/assets/genie-D0YGMca9.js +1 -0
- mycode/server/static/assets/gherkin-DyxjwDmM.js +1 -0
- mycode/server/static/assets/git-commit-F4YmCXRG.js +1 -0
- mycode/server/static/assets/git-rebase-r7XF79zn.js +1 -0
- mycode/server/static/assets/github-dark-DHJKELXO.js +1 -0
- mycode/server/static/assets/github-dark-default-Cuk6v7N8.js +1 -0
- mycode/server/static/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- mycode/server/static/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- mycode/server/static/assets/github-light-DAi9KRSo.js +1 -0
- mycode/server/static/assets/github-light-default-D7oLnXFd.js +1 -0
- mycode/server/static/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- mycode/server/static/assets/gleam-BspZqrRM.js +1 -0
- mycode/server/static/assets/glimmer-js-ByusRIyA.js +1 -0
- mycode/server/static/assets/glimmer-ts-BfAWNZQY.js +1 -0
- mycode/server/static/assets/glsl-DplSGwfg.js +1 -0
- mycode/server/static/assets/gn-n2N0HUVH.js +1 -0
- mycode/server/static/assets/gnuplot-DdkO51Og.js +1 -0
- mycode/server/static/assets/go-C27-OAKa.js +1 -0
- mycode/server/static/assets/graphql-ChdNCCLP.js +1 -0
- mycode/server/static/assets/groovy-gcz8RCvz.js +1 -0
- mycode/server/static/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- mycode/server/static/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- mycode/server/static/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- mycode/server/static/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- mycode/server/static/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- mycode/server/static/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- mycode/server/static/assets/hack-i7_Ulhet.js +1 -0
- mycode/server/static/assets/haml-D5jkg6IW.js +1 -0
- mycode/server/static/assets/handlebars-BpdQsYii.js +1 -0
- mycode/server/static/assets/haskell-Df6bDoY_.js +1 -0
- mycode/server/static/assets/haxe-CzTSHFRz.js +1 -0
- mycode/server/static/assets/hcl-BWvSN4gD.js +1 -0
- mycode/server/static/assets/hjson-D5-asLiD.js +1 -0
- mycode/server/static/assets/hlsl-D3lLCCz7.js +1 -0
- mycode/server/static/assets/horizon-BUw7H-hv.js +1 -0
- mycode/server/static/assets/horizon-bright-CUuTKBJd.js +1 -0
- mycode/server/static/assets/houston-DnULxvSX.js +1 -0
- mycode/server/static/assets/html-derivative-DlHx6ybY.js +1 -0
- mycode/server/static/assets/html-pp8916En.js +1 -0
- mycode/server/static/assets/http-jrhK8wxY.js +1 -0
- mycode/server/static/assets/hurl-irOxFIW8.js +1 -0
- mycode/server/static/assets/hxml-Bvhsp5Yf.js +1 -0
- mycode/server/static/assets/hy-DFXneXwc.js +1 -0
- mycode/server/static/assets/imba-DGztddWO.js +1 -0
- mycode/server/static/assets/index-B4e4WQPq.css +1 -0
- mycode/server/static/assets/index-C2xTNJGd.js +203 -0
- mycode/server/static/assets/ini-BEwlwnbL.js +1 -0
- mycode/server/static/assets/java-CylS5w8V.js +1 -0
- mycode/server/static/assets/javascript-wDzz0qaB.js +1 -0
- mycode/server/static/assets/jinja-f2NsQr07.js +1 -0
- mycode/server/static/assets/jison-wvAkD_A8.js +1 -0
- mycode/server/static/assets/json-Cp-IABpG.js +1 -0
- mycode/server/static/assets/json5-C9tS-k6U.js +1 -0
- mycode/server/static/assets/jsonc-Des-eS-w.js +1 -0
- mycode/server/static/assets/jsonl-DcaNXYhu.js +1 -0
- mycode/server/static/assets/jsonnet-DFQXde-d.js +1 -0
- mycode/server/static/assets/jssm-C2t-YnRu.js +1 -0
- mycode/server/static/assets/jsx-g9-lgVsj.js +1 -0
- mycode/server/static/assets/julia-CxzCAyBv.js +1 -0
- mycode/server/static/assets/just-VxiPbLrw.js +1 -0
- mycode/server/static/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- mycode/server/static/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- mycode/server/static/assets/kanagawa-wave-DWedfzmr.js +1 -0
- mycode/server/static/assets/katex-DnJR2-55.css +1 -0
- mycode/server/static/assets/kdl-DV7GczEv.js +1 -0
- mycode/server/static/assets/kotlin-BdnUsdx6.js +1 -0
- mycode/server/static/assets/kusto-wEQ09or8.js +1 -0
- mycode/server/static/assets/laserwave-DUszq2jm.js +1 -0
- mycode/server/static/assets/latex-CWtU0Tv5.js +1 -0
- mycode/server/static/assets/lean-BZvkOJ9d.js +1 -0
- mycode/server/static/assets/less-B1dDrJ26.js +1 -0
- mycode/server/static/assets/light-plus-B7mTdjB0.js +1 -0
- mycode/server/static/assets/liquid-C0sCDyMI.js +1 -0
- mycode/server/static/assets/llvm-DjAJT7YJ.js +1 -0
- mycode/server/static/assets/log-2UxHyX5q.js +1 -0
- mycode/server/static/assets/logo-BtOb2qkB.js +1 -0
- mycode/server/static/assets/lua-BaeVxFsk.js +1 -0
- mycode/server/static/assets/luau-C-HG3fhB.js +1 -0
- mycode/server/static/assets/make-CHLpvVh8.js +1 -0
- mycode/server/static/assets/markdown-Cvjx9yec.js +1 -0
- mycode/server/static/assets/marko-DjSrsDqO.js +1 -0
- mycode/server/static/assets/material-theme-D5KoaKCx.js +1 -0
- mycode/server/static/assets/material-theme-darker-BfHTSMKl.js +1 -0
- mycode/server/static/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- mycode/server/static/assets/material-theme-ocean-CyktbL80.js +1 -0
- mycode/server/static/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- mycode/server/static/assets/matlab-D7o27uSR.js +1 -0
- mycode/server/static/assets/mdc-DTYItulj.js +1 -0
- mycode/server/static/assets/mdx-Cmh6b_Ma.js +1 -0
- mycode/server/static/assets/mermaid-mWjccvbQ.js +1 -0
- mycode/server/static/assets/min-dark-CafNBF8u.js +1 -0
- mycode/server/static/assets/min-light-CTRr51gU.js +1 -0
- mycode/server/static/assets/mipsasm-CKIfxQSi.js +1 -0
- mycode/server/static/assets/mojo-rZm6bMo-.js +1 -0
- mycode/server/static/assets/monokai-D4h5O-jR.js +1 -0
- mycode/server/static/assets/moonbit-_H4v1dQx.js +1 -0
- mycode/server/static/assets/move-IF9eRakj.js +1 -0
- mycode/server/static/assets/narrat-DRg8JJMk.js +1 -0
- mycode/server/static/assets/nextflow-C-mBbutL.js +1 -0
- mycode/server/static/assets/nextflow-groovy-vE_lwT2v.js +1 -0
- mycode/server/static/assets/nginx-BpAMiNFr.js +1 -0
- mycode/server/static/assets/night-owl-C39BiMTA.js +1 -0
- mycode/server/static/assets/night-owl-light-CMTm3GFP.js +1 -0
- mycode/server/static/assets/nim-BIad80T-.js +1 -0
- mycode/server/static/assets/nix-CwoSXNpI.js +1 -0
- mycode/server/static/assets/nord-Ddv68eIx.js +1 -0
- mycode/server/static/assets/nushell-Cz2AlsmD.js +1 -0
- mycode/server/static/assets/objective-c-DXmwc3jG.js +1 -0
- mycode/server/static/assets/objective-cpp-CLxacb5B.js +1 -0
- mycode/server/static/assets/ocaml-C0hk2d4L.js +1 -0
- mycode/server/static/assets/odin-BBf5iR-q.js +1 -0
- mycode/server/static/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- mycode/server/static/assets/one-light-C3Wv6jpd.js +1 -0
- mycode/server/static/assets/openscad-C4EeE6gA.js +1 -0
- mycode/server/static/assets/pascal-D93ZcfNL.js +1 -0
- mycode/server/static/assets/perl-NvoQZIq0.js +1 -0
- mycode/server/static/assets/php-R6g_5hLQ.js +1 -0
- mycode/server/static/assets/pkl-u5AG7uiY.js +1 -0
- mycode/server/static/assets/plastic-3e1v2bzS.js +1 -0
- mycode/server/static/assets/plsql-ChMvpjG-.js +1 -0
- mycode/server/static/assets/po-BTJTHyun.js +1 -0
- mycode/server/static/assets/poimandres-CS3Unz2-.js +1 -0
- mycode/server/static/assets/polar-C0HS_06l.js +1 -0
- mycode/server/static/assets/postcss-CXtECtnM.js +1 -0
- mycode/server/static/assets/powerquery-CEu0bR-o.js +1 -0
- mycode/server/static/assets/powershell-Dpen1YoG.js +1 -0
- mycode/server/static/assets/prisma-Dd19v3D-.js +1 -0
- mycode/server/static/assets/prolog-CbFg5uaA.js +1 -0
- mycode/server/static/assets/proto-C7zT0LnQ.js +1 -0
- mycode/server/static/assets/pug-DKIMFp6K.js +1 -0
- mycode/server/static/assets/puppet-BMWR74SV.js +1 -0
- mycode/server/static/assets/purescript-CklMAg4u.js +1 -0
- mycode/server/static/assets/python-B6aJPvgy.js +1 -0
- mycode/server/static/assets/qml-3beO22l8.js +1 -0
- mycode/server/static/assets/qmldir-C8lEn-DE.js +1 -0
- mycode/server/static/assets/qss-IeuSbFQv.js +1 -0
- mycode/server/static/assets/r-Dspwwk_N.js +1 -0
- mycode/server/static/assets/racket-BqYA7rlc.js +1 -0
- mycode/server/static/assets/raku-DXvB9xmW.js +1 -0
- mycode/server/static/assets/razor-BDqjjVU7.js +1 -0
- mycode/server/static/assets/red-bN70gL4F.js +1 -0
- mycode/server/static/assets/reg-C-SQnVFl.js +1 -0
- mycode/server/static/assets/regexp-CDVJQ6XC.js +1 -0
- mycode/server/static/assets/rel-C3B-1QV4.js +1 -0
- mycode/server/static/assets/riscv-BM1_JUlF.js +1 -0
- mycode/server/static/assets/ron-D8l8udqQ.js +1 -0
- mycode/server/static/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- mycode/server/static/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- mycode/server/static/assets/rose-pine-qdsjHGoJ.js +1 -0
- mycode/server/static/assets/rosmsg-BJDFO7_C.js +1 -0
- mycode/server/static/assets/rst-CRjBmOyv.js +1 -0
- mycode/server/static/assets/ruby-Wjq7vjNf.js +1 -0
- mycode/server/static/assets/rust-B1yitclQ.js +1 -0
- mycode/server/static/assets/sas-cz2c8ADy.js +1 -0
- mycode/server/static/assets/sass-Cj5Yp3dK.js +1 -0
- mycode/server/static/assets/scala-C151Ov-r.js +1 -0
- mycode/server/static/assets/scheme-C98Dy4si.js +1 -0
- mycode/server/static/assets/scss-D5BDwBP9.js +1 -0
- mycode/server/static/assets/sdbl-DVxCFoDh.js +1 -0
- mycode/server/static/assets/shaderlab-Dg9Lc6iA.js +1 -0
- mycode/server/static/assets/shellscript-Yzrsuije.js +1 -0
- mycode/server/static/assets/shellsession-BADoaaVG.js +1 -0
- mycode/server/static/assets/slack-dark-BthQWCQV.js +1 -0
- mycode/server/static/assets/slack-ochin-DqwNpetd.js +1 -0
- mycode/server/static/assets/smalltalk-BERRCDM3.js +1 -0
- mycode/server/static/assets/snazzy-light-Bw305WKR.js +1 -0
- mycode/server/static/assets/solarized-dark-DXbdFlpD.js +1 -0
- mycode/server/static/assets/solarized-light-L9t79GZl.js +1 -0
- mycode/server/static/assets/solidity-rGO070M0.js +1 -0
- mycode/server/static/assets/soy-8wufbnw4.js +1 -0
- mycode/server/static/assets/sparql-rVzFXLq3.js +1 -0
- mycode/server/static/assets/splunk-BtCnVYZw.js +1 -0
- mycode/server/static/assets/sql-BLtJtn59.js +1 -0
- mycode/server/static/assets/ssh-config-_ykCGR6B.js +1 -0
- mycode/server/static/assets/stata-BH5u7GGu.js +1 -0
- mycode/server/static/assets/stylus-BEDo0Tqx.js +1 -0
- mycode/server/static/assets/surrealql-Bq5Q-fJD.js +1 -0
- mycode/server/static/assets/svelte-Cy7k_4gC.js +1 -0
- mycode/server/static/assets/swift-D82vCrfD.js +1 -0
- mycode/server/static/assets/synthwave-84-CbfX1IO0.js +1 -0
- mycode/server/static/assets/system-verilog-CnnmHF94.js +1 -0
- mycode/server/static/assets/systemd-4A_iFExJ.js +1 -0
- mycode/server/static/assets/talonscript-CkByrt1z.js +1 -0
- mycode/server/static/assets/tasl-QIJgUcNo.js +1 -0
- mycode/server/static/assets/tcl-dwOrl1Do.js +1 -0
- mycode/server/static/assets/templ-DhtptRzy.js +1 -0
- mycode/server/static/assets/terraform-BETggiCN.js +1 -0
- mycode/server/static/assets/tex-idrVyKtj.js +1 -0
- mycode/server/static/assets/tokyo-night-hegEt444.js +1 -0
- mycode/server/static/assets/toml-vGWfd6FD.js +1 -0
- mycode/server/static/assets/ts-tags-DQrlYJgV.js +1 -0
- mycode/server/static/assets/tsv-B_m7g4N7.js +1 -0
- mycode/server/static/assets/tsx-COt5Ahok.js +1 -0
- mycode/server/static/assets/turtle-BsS91CYL.js +1 -0
- mycode/server/static/assets/twig-xg9kU7Mw.js +1 -0
- mycode/server/static/assets/typescript-BPQ3VLAy.js +1 -0
- mycode/server/static/assets/typespec-CAFt9gP4.js +1 -0
- mycode/server/static/assets/typst-DHCkPAjA.js +1 -0
- mycode/server/static/assets/v-BcVCzyr7.js +1 -0
- mycode/server/static/assets/vala-CsfeWuGM.js +1 -0
- mycode/server/static/assets/vb-D17OF-Vu.js +1 -0
- mycode/server/static/assets/verilog-BQ8w6xss.js +1 -0
- mycode/server/static/assets/vesper-DU1UobuO.js +1 -0
- mycode/server/static/assets/vhdl-CeAyd5Ju.js +1 -0
- mycode/server/static/assets/viml-CJc9bBzg.js +1 -0
- mycode/server/static/assets/vitesse-black-Bkuqu6BP.js +1 -0
- mycode/server/static/assets/vitesse-dark-D0r3Knsf.js +1 -0
- mycode/server/static/assets/vitesse-light-CVO1_9PV.js +1 -0
- mycode/server/static/assets/vue-D2xRrEX4.js +1 -0
- mycode/server/static/assets/vue-html-AaS7Mt5G.js +1 -0
- mycode/server/static/assets/vue-vine-BoDAl6tE.js +1 -0
- mycode/server/static/assets/vyper-CDx5xZoG.js +1 -0
- mycode/server/static/assets/wasm-CG6Dc4jp.js +1 -0
- mycode/server/static/assets/wasm-MzD3tlZU.js +1 -0
- mycode/server/static/assets/wenyan-BV7otONQ.js +1 -0
- mycode/server/static/assets/wgsl-Dx-B1_4e.js +1 -0
- mycode/server/static/assets/wikitext-BhOHFoWU.js +1 -0
- mycode/server/static/assets/wit-5i3qLPDT.js +1 -0
- mycode/server/static/assets/wolfram-lXgVvXCa.js +1 -0
- mycode/server/static/assets/xml-sdJ4AIDG.js +1 -0
- mycode/server/static/assets/xsl-CtQFsRM5.js +1 -0
- mycode/server/static/assets/yaml-Buea-lGh.js +1 -0
- mycode/server/static/assets/zenscript-DVFEvuxE.js +1 -0
- mycode/server/static/assets/zig-VOosw3JB.js +1 -0
- mycode/server/static/favicon_slashes.svg +12 -0
- mycode/server/static/index.html +35 -0
- mycode_cli-0.1.0.dist-info/METADATA +186 -0
- mycode_cli-0.1.0.dist-info/RECORD +404 -0
- mycode_cli-0.1.0.dist-info/WHEEL +4 -0
- mycode_cli-0.1.0.dist-info/entry_points.txt +2 -0
- mycode_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
mycode/core/config.py
ADDED
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
"""Application configuration and provider resolution.
|
|
2
|
+
|
|
3
|
+
This module keeps runtime config loading intentionally simple:
|
|
4
|
+
|
|
5
|
+
- read the global config, then the workspace config
|
|
6
|
+
- merge provider entries by name
|
|
7
|
+
- resolve one runnable provider from explicit args, config defaults, or env
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import logging
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from mycode.core.models import ModelMetadata, lookup_model_metadata
|
|
21
|
+
from mycode.core.providers import (
|
|
22
|
+
get_provider_adapter,
|
|
23
|
+
is_supported_provider,
|
|
24
|
+
list_env_discoverable_providers,
|
|
25
|
+
list_supported_providers,
|
|
26
|
+
provider_api_key_from_env,
|
|
27
|
+
provider_default_models,
|
|
28
|
+
provider_env_api_key_names,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
_DEFAULT_MYCODE_HOME = "~/.mycode"
|
|
32
|
+
_API_KEY_ENV_REF_RE = re.compile(r"^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$")
|
|
33
|
+
_VALID_REASONING_EFFORTS = ("none", "low", "medium", "high", "xhigh")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(frozen=True)
|
|
37
|
+
class ModelConfig:
|
|
38
|
+
context_window: int | None = None
|
|
39
|
+
max_output_tokens: int | None = None
|
|
40
|
+
supports_reasoning: bool | None = None
|
|
41
|
+
supports_image_input: bool | None = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class ProviderConfig:
|
|
46
|
+
name: str
|
|
47
|
+
type: str # internal provider adapter id: anthropic | moonshotai | minimax | …
|
|
48
|
+
models: dict[str, ModelConfig]
|
|
49
|
+
api_key: str | None = None
|
|
50
|
+
api_key_env_var: str | None = None
|
|
51
|
+
base_url: str | None = None
|
|
52
|
+
reasoning_effort: str | None = None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(frozen=True)
|
|
56
|
+
class Settings:
|
|
57
|
+
providers: dict[str, ProviderConfig]
|
|
58
|
+
default_provider: str | None
|
|
59
|
+
default_model: str | None
|
|
60
|
+
port: int
|
|
61
|
+
cwd: str
|
|
62
|
+
workspace_root: str
|
|
63
|
+
default_reasoning_effort: str | None = None
|
|
64
|
+
compact_threshold: float | None = None
|
|
65
|
+
config_paths: list[str] = field(default_factory=list)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True)
|
|
69
|
+
class ResolvedProvider:
|
|
70
|
+
"""Resolved provider ready for Agent construction."""
|
|
71
|
+
|
|
72
|
+
provider: str
|
|
73
|
+
model: str
|
|
74
|
+
api_key: str | None
|
|
75
|
+
api_base: str | None
|
|
76
|
+
reasoning_effort: str | None
|
|
77
|
+
max_tokens: int = 16_384
|
|
78
|
+
context_window: int | None = 128_000
|
|
79
|
+
supports_reasoning: bool | None = None
|
|
80
|
+
supports_image_input: bool | None = None
|
|
81
|
+
provider_name: str | None = None
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def provider_type(self) -> str:
|
|
85
|
+
return self.provider
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def resolve_mycode_home() -> Path:
|
|
89
|
+
"""Resolve the mycode home directory."""
|
|
90
|
+
|
|
91
|
+
raw = os.environ.get("MYCODE_HOME", _DEFAULT_MYCODE_HOME)
|
|
92
|
+
return Path(raw).expanduser().resolve(strict=False)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def resolve_sessions_dir() -> Path:
|
|
96
|
+
"""Resolve the default directory used for persisted sessions."""
|
|
97
|
+
|
|
98
|
+
return resolve_mycode_home() / "sessions"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def find_workspace_root(cwd: str) -> Path:
|
|
102
|
+
"""Resolve the project/workspace root for the current cwd."""
|
|
103
|
+
|
|
104
|
+
current = Path(cwd).expanduser().resolve(strict=False)
|
|
105
|
+
for parent in [current, *current.parents]:
|
|
106
|
+
if (parent / ".git").exists():
|
|
107
|
+
return parent
|
|
108
|
+
return current
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _load_json(path: Path) -> dict[str, Any] | None:
|
|
112
|
+
if not path.is_file():
|
|
113
|
+
return None
|
|
114
|
+
try:
|
|
115
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
116
|
+
except Exception:
|
|
117
|
+
return None
|
|
118
|
+
return data if isinstance(data, dict) else None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _normalize_models(value: Any) -> dict[str, ModelConfig]:
|
|
122
|
+
if not isinstance(value, dict):
|
|
123
|
+
return {}
|
|
124
|
+
|
|
125
|
+
models: dict[str, ModelConfig] = {}
|
|
126
|
+
for model, raw in value.items():
|
|
127
|
+
if not isinstance(model, str):
|
|
128
|
+
continue
|
|
129
|
+
model_id = model.strip()
|
|
130
|
+
if not model_id:
|
|
131
|
+
continue
|
|
132
|
+
if isinstance(raw, ModelConfig):
|
|
133
|
+
models[model_id] = raw
|
|
134
|
+
continue
|
|
135
|
+
raw_config = raw if isinstance(raw, dict) else {}
|
|
136
|
+
context_window = raw_config.get("context_window")
|
|
137
|
+
max_output_tokens = raw_config.get("max_output_tokens")
|
|
138
|
+
supports_reasoning = raw_config.get("supports_reasoning")
|
|
139
|
+
supports_image_input = raw_config.get("supports_image_input")
|
|
140
|
+
models[model_id] = ModelConfig(
|
|
141
|
+
context_window=(
|
|
142
|
+
context_window if isinstance(context_window, int) and not isinstance(context_window, bool) else None
|
|
143
|
+
),
|
|
144
|
+
max_output_tokens=max_output_tokens
|
|
145
|
+
if isinstance(max_output_tokens, int) and not isinstance(max_output_tokens, bool)
|
|
146
|
+
else None,
|
|
147
|
+
supports_reasoning=supports_reasoning if isinstance(supports_reasoning, bool) else None,
|
|
148
|
+
supports_image_input=supports_image_input if isinstance(supports_image_input, bool) else None,
|
|
149
|
+
)
|
|
150
|
+
return models
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _parse_config_api_key(value: Any) -> tuple[str | None, str | None]:
|
|
154
|
+
if not isinstance(value, str):
|
|
155
|
+
return None, None
|
|
156
|
+
|
|
157
|
+
cleaned = value.strip()
|
|
158
|
+
if not cleaned:
|
|
159
|
+
return None, None
|
|
160
|
+
|
|
161
|
+
match = _API_KEY_ENV_REF_RE.fullmatch(cleaned)
|
|
162
|
+
if match:
|
|
163
|
+
return None, match.group(1)
|
|
164
|
+
return cleaned, None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _parse_compact_threshold(value: Any) -> float | None:
|
|
168
|
+
"""Parse compact_threshold from config.
|
|
169
|
+
|
|
170
|
+
Returns ``None`` when the key should keep the current/default value, ``0.0``
|
|
171
|
+
when compaction is explicitly disabled, or a valid float in ``[0, 1]``.
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
if value is None:
|
|
175
|
+
return None
|
|
176
|
+
if value is False:
|
|
177
|
+
return 0.0
|
|
178
|
+
|
|
179
|
+
try:
|
|
180
|
+
threshold = float(value)
|
|
181
|
+
except (TypeError, ValueError):
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
if threshold < 0 or threshold > 1:
|
|
185
|
+
return None
|
|
186
|
+
return threshold
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def normalize_reasoning_effort(value: Any) -> str | None:
|
|
190
|
+
if not isinstance(value, str):
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
effort = value.strip().lower()
|
|
194
|
+
if effort in {"", "auto", "default"}:
|
|
195
|
+
return None
|
|
196
|
+
if effort in {"off", "disabled"}:
|
|
197
|
+
return "none"
|
|
198
|
+
return effort
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _config_api_key_from_env_var(provider: ProviderConfig, *, require: bool = False) -> str | None:
|
|
202
|
+
env_name = provider.api_key_env_var
|
|
203
|
+
if not env_name:
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
value = (os.environ.get(env_name) or "").strip()
|
|
207
|
+
if value:
|
|
208
|
+
return value
|
|
209
|
+
|
|
210
|
+
if require:
|
|
211
|
+
raise ValueError(f"missing API key env var {env_name!r} referenced by provider {provider.name!r}")
|
|
212
|
+
return None
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def provider_has_api_key(provider: ProviderConfig) -> bool:
|
|
216
|
+
"""Return whether a configured provider can authenticate right now."""
|
|
217
|
+
|
|
218
|
+
if provider.api_key_env_var:
|
|
219
|
+
return bool(_config_api_key_from_env_var(provider))
|
|
220
|
+
return bool(provider.api_key or provider_api_key_from_env(provider.type))
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _candidate_config_paths(cwd: str) -> list[Path]:
|
|
224
|
+
workspace_root = find_workspace_root(cwd)
|
|
225
|
+
return [
|
|
226
|
+
resolve_mycode_home() / "config.json",
|
|
227
|
+
workspace_root / ".mycode" / "config.json",
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _build_providers(raw_providers: dict[str, dict[str, Any]]) -> dict[str, ProviderConfig]:
|
|
232
|
+
providers: dict[str, ProviderConfig] = {}
|
|
233
|
+
|
|
234
|
+
for name, raw in raw_providers.items():
|
|
235
|
+
raw_type = raw.get("type")
|
|
236
|
+
if raw_type:
|
|
237
|
+
provider_type = str(raw_type)
|
|
238
|
+
elif is_supported_provider(name):
|
|
239
|
+
# Built-in providers can be overridden by name without repeating type.
|
|
240
|
+
provider_type = name
|
|
241
|
+
else:
|
|
242
|
+
raise ValueError(f"provider {name!r} must set 'type'")
|
|
243
|
+
|
|
244
|
+
models = _normalize_models(raw.get("models"))
|
|
245
|
+
if not models:
|
|
246
|
+
models = {model: ModelConfig() for model in provider_default_models(provider_type)}
|
|
247
|
+
providers[name] = ProviderConfig(
|
|
248
|
+
name=name,
|
|
249
|
+
type=provider_type,
|
|
250
|
+
models=models,
|
|
251
|
+
api_key=raw.get("api_key") or None,
|
|
252
|
+
api_key_env_var=raw.get("api_key_env_var") or None,
|
|
253
|
+
base_url=raw.get("base_url") or None,
|
|
254
|
+
reasoning_effort=normalize_reasoning_effort(raw.get("reasoning_effort")),
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
return providers
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def get_settings(cwd: str | None = None) -> Settings:
|
|
261
|
+
"""Load settings from global and workspace config files."""
|
|
262
|
+
|
|
263
|
+
resolved_cwd = str(Path(cwd or os.getcwd()).expanduser().resolve(strict=False))
|
|
264
|
+
workspace_root = find_workspace_root(resolved_cwd)
|
|
265
|
+
|
|
266
|
+
raw_providers: dict[str, dict[str, Any]] = {}
|
|
267
|
+
default_provider: str | None = None
|
|
268
|
+
default_model: str | None = None
|
|
269
|
+
default_reasoning_effort: str | None = None
|
|
270
|
+
compact_threshold: float | None = None
|
|
271
|
+
config_paths: list[str] = []
|
|
272
|
+
|
|
273
|
+
for path in _candidate_config_paths(resolved_cwd):
|
|
274
|
+
data = _load_json(path)
|
|
275
|
+
if data is None:
|
|
276
|
+
continue
|
|
277
|
+
|
|
278
|
+
resolved_path = str(path.resolve(strict=False))
|
|
279
|
+
if resolved_path not in config_paths:
|
|
280
|
+
config_paths.append(resolved_path)
|
|
281
|
+
|
|
282
|
+
for name, raw in (data.get("providers") or {}).items():
|
|
283
|
+
if not isinstance(name, str) or not isinstance(raw, dict):
|
|
284
|
+
continue
|
|
285
|
+
|
|
286
|
+
merged = dict(raw_providers.get(name, {}))
|
|
287
|
+
|
|
288
|
+
if "type" in raw:
|
|
289
|
+
merged["type"] = raw.get("type") or "anthropic"
|
|
290
|
+
if "models" in raw:
|
|
291
|
+
merged["models"] = _normalize_models(raw.get("models"))
|
|
292
|
+
if "api_key" in raw:
|
|
293
|
+
api_key, api_key_env_var = _parse_config_api_key(raw.get("api_key"))
|
|
294
|
+
merged["api_key"] = api_key
|
|
295
|
+
merged["api_key_env_var"] = api_key_env_var
|
|
296
|
+
if "base_url" in raw:
|
|
297
|
+
merged["base_url"] = raw.get("base_url") or None
|
|
298
|
+
if "reasoning_effort" in raw:
|
|
299
|
+
merged["reasoning_effort"] = raw.get("reasoning_effort") or None
|
|
300
|
+
|
|
301
|
+
raw_providers[name] = merged
|
|
302
|
+
|
|
303
|
+
default = data.get("default") if isinstance(data.get("default"), dict) else {}
|
|
304
|
+
if "provider" in default:
|
|
305
|
+
value = default.get("provider")
|
|
306
|
+
default_provider = value if isinstance(value, str) else None
|
|
307
|
+
if "model" in default:
|
|
308
|
+
value = default.get("model")
|
|
309
|
+
default_model = value if isinstance(value, str) else None
|
|
310
|
+
if "reasoning_effort" in default:
|
|
311
|
+
value = default.get("reasoning_effort")
|
|
312
|
+
default_reasoning_effort = value if isinstance(value, str) else None
|
|
313
|
+
if "compact_threshold" in default:
|
|
314
|
+
parsed_threshold = _parse_compact_threshold(default.get("compact_threshold"))
|
|
315
|
+
if parsed_threshold is not None:
|
|
316
|
+
compact_threshold = parsed_threshold
|
|
317
|
+
|
|
318
|
+
return Settings(
|
|
319
|
+
providers=_build_providers(raw_providers),
|
|
320
|
+
default_provider=default_provider,
|
|
321
|
+
default_model=default_model,
|
|
322
|
+
default_reasoning_effort=normalize_reasoning_effort(default_reasoning_effort),
|
|
323
|
+
compact_threshold=compact_threshold,
|
|
324
|
+
port=int(os.environ.get("PORT", "8000")),
|
|
325
|
+
cwd=resolved_cwd,
|
|
326
|
+
workspace_root=str(workspace_root),
|
|
327
|
+
config_paths=config_paths,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def resolve_provider(
|
|
332
|
+
settings: Settings,
|
|
333
|
+
*,
|
|
334
|
+
provider_name: str | None = None,
|
|
335
|
+
model: str | None = None,
|
|
336
|
+
api_key: str | None = None,
|
|
337
|
+
api_base: str | None = None,
|
|
338
|
+
) -> ResolvedProvider:
|
|
339
|
+
"""Resolve provider, model, api_key, and api_base from settings and overrides."""
|
|
340
|
+
|
|
341
|
+
selected_name = (provider_name or settings.default_provider or "").strip()
|
|
342
|
+
if selected_name:
|
|
343
|
+
return _resolve_provider_runtime(
|
|
344
|
+
settings,
|
|
345
|
+
selected_name=selected_name,
|
|
346
|
+
model=model,
|
|
347
|
+
api_key=api_key,
|
|
348
|
+
api_base=api_base,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
for available_name, _provider in _available_provider_references(settings):
|
|
352
|
+
return _resolve_provider_runtime(
|
|
353
|
+
settings,
|
|
354
|
+
selected_name=available_name,
|
|
355
|
+
model=model,
|
|
356
|
+
api_key=api_key,
|
|
357
|
+
api_base=api_base,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
env_names: list[str] = []
|
|
361
|
+
for provider_id in list_env_discoverable_providers():
|
|
362
|
+
for env_name in provider_env_api_key_names(provider_id):
|
|
363
|
+
if env_name not in env_names:
|
|
364
|
+
env_names.append(env_name)
|
|
365
|
+
checked = ", ".join(env_names) or "<api key env>"
|
|
366
|
+
raise ValueError(
|
|
367
|
+
"no available providers found; set one of the supported API key env vars "
|
|
368
|
+
f"({checked}) or configure a provider in ~/.mycode/config.json or <workspace>/.mycode/config.json"
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def resolve_provider_choices(settings: Settings) -> list[ResolvedProvider]:
|
|
373
|
+
"""Return currently selectable providers in stable selection order."""
|
|
374
|
+
|
|
375
|
+
choices: list[ResolvedProvider] = []
|
|
376
|
+
for selected_name, _provider in _available_provider_references(settings):
|
|
377
|
+
try:
|
|
378
|
+
choices.append(_resolve_provider_runtime(settings, selected_name=selected_name))
|
|
379
|
+
except ValueError:
|
|
380
|
+
continue
|
|
381
|
+
return choices
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def _available_provider_references(settings: Settings) -> list[tuple[str, ProviderConfig | None]]:
|
|
385
|
+
"""Return usable provider references with the configured default first."""
|
|
386
|
+
|
|
387
|
+
available: list[tuple[str, ProviderConfig | None]] = []
|
|
388
|
+
seen: set[str] = set()
|
|
389
|
+
configured_types_with_credentials: set[str] = set()
|
|
390
|
+
|
|
391
|
+
def add(name: str | None) -> None:
|
|
392
|
+
cleaned = (name or "").strip()
|
|
393
|
+
if not cleaned or cleaned in seen:
|
|
394
|
+
return
|
|
395
|
+
|
|
396
|
+
provider_config = settings.providers.get(cleaned)
|
|
397
|
+
provider_type = provider_config.type if provider_config else cleaned
|
|
398
|
+
if not is_supported_provider(provider_type):
|
|
399
|
+
return
|
|
400
|
+
|
|
401
|
+
if provider_config:
|
|
402
|
+
if not provider_has_api_key(provider_config):
|
|
403
|
+
return
|
|
404
|
+
configured_types_with_credentials.add(provider_type)
|
|
405
|
+
elif not provider_api_key_from_env(provider_type):
|
|
406
|
+
return
|
|
407
|
+
|
|
408
|
+
seen.add(cleaned)
|
|
409
|
+
available.append((cleaned, provider_config))
|
|
410
|
+
|
|
411
|
+
add(settings.default_provider)
|
|
412
|
+
|
|
413
|
+
for name, provider in settings.providers.items():
|
|
414
|
+
if provider_has_api_key(provider):
|
|
415
|
+
add(name)
|
|
416
|
+
|
|
417
|
+
for provider_id in list_env_discoverable_providers():
|
|
418
|
+
if provider_id in configured_types_with_credentials or not provider_api_key_from_env(provider_id):
|
|
419
|
+
continue
|
|
420
|
+
add(provider_id)
|
|
421
|
+
|
|
422
|
+
return available
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def _resolve_provider_runtime(
|
|
426
|
+
settings: Settings,
|
|
427
|
+
*,
|
|
428
|
+
selected_name: str,
|
|
429
|
+
model: str | None = None,
|
|
430
|
+
api_key: str | None = None,
|
|
431
|
+
api_base: str | None = None,
|
|
432
|
+
) -> ResolvedProvider:
|
|
433
|
+
"""Resolve one configured alias or raw provider id into a runnable config."""
|
|
434
|
+
|
|
435
|
+
provider_config = settings.providers.get(selected_name)
|
|
436
|
+
provider_type = provider_config.type if provider_config else selected_name
|
|
437
|
+
|
|
438
|
+
if not is_supported_provider(provider_type):
|
|
439
|
+
supported = ", ".join(list_supported_providers())
|
|
440
|
+
raise ValueError(f"unsupported provider {provider_type!r}; supported: {supported}")
|
|
441
|
+
|
|
442
|
+
requested_model = (model or "").strip()
|
|
443
|
+
if requested_model:
|
|
444
|
+
resolved_model = requested_model
|
|
445
|
+
elif provider_config and provider_config.models:
|
|
446
|
+
resolved_model = next(iter(provider_config.models))
|
|
447
|
+
elif selected_name == settings.default_provider and (settings.default_model or "").strip():
|
|
448
|
+
resolved_model = str(settings.default_model).strip()
|
|
449
|
+
else:
|
|
450
|
+
defaults = provider_default_models(provider_type)
|
|
451
|
+
if not defaults:
|
|
452
|
+
raise ValueError(f"provider {selected_name!r} does not define any default models")
|
|
453
|
+
resolved_model = defaults[0]
|
|
454
|
+
|
|
455
|
+
resolved_api_base = api_base or (provider_config.base_url if provider_config else None)
|
|
456
|
+
model_metadata = lookup_model_metadata(
|
|
457
|
+
provider_type=provider_type,
|
|
458
|
+
provider_name=selected_name,
|
|
459
|
+
model=resolved_model,
|
|
460
|
+
api_base=resolved_api_base,
|
|
461
|
+
)
|
|
462
|
+
if provider_config:
|
|
463
|
+
model_config = provider_config.models.get(resolved_model)
|
|
464
|
+
if model_config:
|
|
465
|
+
if model_metadata is None:
|
|
466
|
+
model_metadata = ModelMetadata(
|
|
467
|
+
provider=provider_type,
|
|
468
|
+
model=resolved_model,
|
|
469
|
+
context_window=model_config.context_window,
|
|
470
|
+
max_output_tokens=model_config.max_output_tokens,
|
|
471
|
+
supports_reasoning=model_config.supports_reasoning,
|
|
472
|
+
supports_image_input=model_config.supports_image_input,
|
|
473
|
+
)
|
|
474
|
+
else:
|
|
475
|
+
model_metadata = ModelMetadata(
|
|
476
|
+
provider=model_metadata.provider,
|
|
477
|
+
model=model_metadata.model,
|
|
478
|
+
context_window=(
|
|
479
|
+
model_config.context_window
|
|
480
|
+
if model_config.context_window is not None
|
|
481
|
+
else model_metadata.context_window
|
|
482
|
+
),
|
|
483
|
+
max_output_tokens=(
|
|
484
|
+
model_config.max_output_tokens
|
|
485
|
+
if model_config.max_output_tokens is not None
|
|
486
|
+
else model_metadata.max_output_tokens
|
|
487
|
+
),
|
|
488
|
+
supports_reasoning=(
|
|
489
|
+
model_config.supports_reasoning
|
|
490
|
+
if model_config.supports_reasoning is not None
|
|
491
|
+
else model_metadata.supports_reasoning
|
|
492
|
+
),
|
|
493
|
+
supports_image_input=(
|
|
494
|
+
model_config.supports_image_input
|
|
495
|
+
if model_config.supports_image_input is not None
|
|
496
|
+
else model_metadata.supports_image_input
|
|
497
|
+
),
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
configured_effort = settings.default_reasoning_effort
|
|
501
|
+
if provider_config and provider_config.reasoning_effort is not None:
|
|
502
|
+
configured_effort = provider_config.reasoning_effort
|
|
503
|
+
|
|
504
|
+
if configured_effort is not None and configured_effort not in _VALID_REASONING_EFFORTS:
|
|
505
|
+
supported = ", ".join(_VALID_REASONING_EFFORTS)
|
|
506
|
+
raise ValueError(f"unsupported reasoning_effort {configured_effort!r}; supported: {supported}")
|
|
507
|
+
|
|
508
|
+
supports_reasoning = model_metadata.supports_reasoning if model_metadata else None
|
|
509
|
+
supports_image_input = model_metadata.supports_image_input if model_metadata else None
|
|
510
|
+
adapter = get_provider_adapter(provider_type)
|
|
511
|
+
if (
|
|
512
|
+
configured_effort is None
|
|
513
|
+
or model_metadata is None
|
|
514
|
+
or supports_reasoning is not True
|
|
515
|
+
or not adapter.supports_reasoning_effort
|
|
516
|
+
):
|
|
517
|
+
reasoning_effort = None
|
|
518
|
+
else:
|
|
519
|
+
reasoning_effort = configured_effort
|
|
520
|
+
|
|
521
|
+
resolved_api_key = api_key
|
|
522
|
+
if not resolved_api_key and provider_config:
|
|
523
|
+
if provider_config.api_key_env_var:
|
|
524
|
+
resolved_api_key = _config_api_key_from_env_var(provider_config, require=True)
|
|
525
|
+
elif provider_config.api_key:
|
|
526
|
+
resolved_api_key = provider_config.api_key
|
|
527
|
+
if not resolved_api_key:
|
|
528
|
+
resolved_api_key = provider_api_key_from_env(provider_type)
|
|
529
|
+
|
|
530
|
+
if not resolved_api_key:
|
|
531
|
+
checked = ", ".join(provider_env_api_key_names(provider_type)) or "<api key env>"
|
|
532
|
+
raise ValueError(f"provider {selected_name!r} is selected but no API key is available; checked: {checked}")
|
|
533
|
+
|
|
534
|
+
return ResolvedProvider(
|
|
535
|
+
provider_name=selected_name,
|
|
536
|
+
provider=provider_type,
|
|
537
|
+
model=resolved_model,
|
|
538
|
+
api_key=resolved_api_key,
|
|
539
|
+
api_base=resolved_api_base,
|
|
540
|
+
reasoning_effort=reasoning_effort,
|
|
541
|
+
max_tokens=model_metadata.max_output_tokens if model_metadata and model_metadata.max_output_tokens else 16_384,
|
|
542
|
+
context_window=model_metadata.context_window if model_metadata and model_metadata.context_window else 128_000,
|
|
543
|
+
supports_reasoning=supports_reasoning,
|
|
544
|
+
supports_image_input=supports_image_input,
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def setup_logging() -> None:
|
|
549
|
+
"""Configure default logging."""
|
|
550
|
+
|
|
551
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s")
|