pythinker-code 2.0.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.
- pythinker_code/CHANGELOG.md +16 -0
- pythinker_code/__init__.py +0 -0
- pythinker_code/__main__.py +92 -0
- pythinker_code/acp/AGENTS.md +93 -0
- pythinker_code/acp/__init__.py +13 -0
- pythinker_code/acp/convert.py +128 -0
- pythinker_code/acp/host.py +298 -0
- pythinker_code/acp/mcp.py +46 -0
- pythinker_code/acp/server.py +497 -0
- pythinker_code/acp/session.py +496 -0
- pythinker_code/acp/tools.py +167 -0
- pythinker_code/acp/types.py +13 -0
- pythinker_code/acp/version.py +45 -0
- pythinker_code/agents/default/agent.yaml +36 -0
- pythinker_code/agents/default/coder.yaml +25 -0
- pythinker_code/agents/default/explore.yaml +46 -0
- pythinker_code/agents/default/plan.yaml +30 -0
- pythinker_code/agents/default/system.md +164 -0
- pythinker_code/agents/okabe/agent.yaml +22 -0
- pythinker_code/agentspec.py +163 -0
- pythinker_code/app.py +820 -0
- pythinker_code/approval_runtime/__init__.py +29 -0
- pythinker_code/approval_runtime/models.py +42 -0
- pythinker_code/approval_runtime/runtime.py +235 -0
- pythinker_code/auth/__init__.py +25 -0
- pythinker_code/auth/anthropic_direct.py +207 -0
- pythinker_code/auth/deepseek.py +192 -0
- pythinker_code/auth/lm_studio.py +418 -0
- pythinker_code/auth/minimax.py +203 -0
- pythinker_code/auth/oauth.py +1122 -0
- pythinker_code/auth/ollama.py +293 -0
- pythinker_code/auth/openai.py +771 -0
- pythinker_code/auth/opencode_go.py +203 -0
- pythinker_code/auth/openrouter.py +225 -0
- pythinker_code/auth/platforms.py +466 -0
- pythinker_code/background/__init__.py +36 -0
- pythinker_code/background/agent_runner.py +231 -0
- pythinker_code/background/ids.py +19 -0
- pythinker_code/background/manager.py +650 -0
- pythinker_code/background/models.py +105 -0
- pythinker_code/background/store.py +237 -0
- pythinker_code/background/summary.py +66 -0
- pythinker_code/background/worker.py +209 -0
- pythinker_code/cli/__init__.py +1326 -0
- pythinker_code/cli/__main__.py +19 -0
- pythinker_code/cli/_lazy_group.py +238 -0
- pythinker_code/cli/export.py +322 -0
- pythinker_code/cli/info.py +62 -0
- pythinker_code/cli/mcp.py +349 -0
- pythinker_code/cli/plugin.py +351 -0
- pythinker_code/cli/toad.py +74 -0
- pythinker_code/cli/vis.py +38 -0
- pythinker_code/cli/web.py +80 -0
- pythinker_code/config.py +453 -0
- pythinker_code/constant.py +33 -0
- pythinker_code/exception.py +43 -0
- pythinker_code/hooks/__init__.py +4 -0
- pythinker_code/hooks/config.py +34 -0
- pythinker_code/hooks/engine.py +371 -0
- pythinker_code/hooks/events.py +190 -0
- pythinker_code/hooks/runner.py +89 -0
- pythinker_code/llm.py +412 -0
- pythinker_code/metadata.py +79 -0
- pythinker_code/notifications/__init__.py +33 -0
- pythinker_code/notifications/llm.py +77 -0
- pythinker_code/notifications/manager.py +145 -0
- pythinker_code/notifications/models.py +50 -0
- pythinker_code/notifications/notifier.py +41 -0
- pythinker_code/notifications/store.py +118 -0
- pythinker_code/notifications/wire.py +21 -0
- pythinker_code/plugin/__init__.py +124 -0
- pythinker_code/plugin/manager.py +153 -0
- pythinker_code/plugin/tool.py +173 -0
- pythinker_code/prompts/__init__.py +6 -0
- pythinker_code/prompts/compact.md +73 -0
- pythinker_code/prompts/init.md +21 -0
- pythinker_code/py.typed +0 -0
- pythinker_code/session.py +319 -0
- pythinker_code/session_fork.py +325 -0
- pythinker_code/session_state.py +132 -0
- pythinker_code/share.py +14 -0
- pythinker_code/skill/__init__.py +727 -0
- pythinker_code/skill/flow/__init__.py +99 -0
- pythinker_code/skill/flow/d2.py +482 -0
- pythinker_code/skill/flow/mermaid.py +266 -0
- pythinker_code/skills/pythinker-code-help/SKILL.md +54 -0
- pythinker_code/skills/skill-creator/SKILL.md +367 -0
- pythinker_code/soul/__init__.py +304 -0
- pythinker_code/soul/agent.py +520 -0
- pythinker_code/soul/approval.py +267 -0
- pythinker_code/soul/btw.py +214 -0
- pythinker_code/soul/compaction.py +189 -0
- pythinker_code/soul/context.py +339 -0
- pythinker_code/soul/denwarenji.py +39 -0
- pythinker_code/soul/dynamic_injection.py +84 -0
- pythinker_code/soul/dynamic_injections/__init__.py +0 -0
- pythinker_code/soul/dynamic_injections/auto_mode.py +72 -0
- pythinker_code/soul/dynamic_injections/plan_mode.py +239 -0
- pythinker_code/soul/message.py +92 -0
- pythinker_code/soul/pythinkersoul.py +1613 -0
- pythinker_code/soul/slash.py +340 -0
- pythinker_code/soul/toolset.py +788 -0
- pythinker_code/subagents/__init__.py +21 -0
- pythinker_code/subagents/builder.py +42 -0
- pythinker_code/subagents/core.py +86 -0
- pythinker_code/subagents/git_context.py +172 -0
- pythinker_code/subagents/models.py +54 -0
- pythinker_code/subagents/output.py +71 -0
- pythinker_code/subagents/registry.py +28 -0
- pythinker_code/subagents/runner.py +428 -0
- pythinker_code/subagents/store.py +196 -0
- pythinker_code/telemetry/__init__.py +211 -0
- pythinker_code/telemetry/config.py +54 -0
- pythinker_code/telemetry/crash.py +157 -0
- pythinker_code/telemetry/metrics.py +208 -0
- pythinker_code/telemetry/otel.py +240 -0
- pythinker_code/telemetry/sentry.py +167 -0
- pythinker_code/telemetry/sink.py +189 -0
- pythinker_code/tools/AGENTS.md +6 -0
- pythinker_code/tools/__init__.py +105 -0
- pythinker_code/tools/agent/__init__.py +277 -0
- pythinker_code/tools/agent/description.md +41 -0
- pythinker_code/tools/ask_user/__init__.py +159 -0
- pythinker_code/tools/ask_user/description.md +19 -0
- pythinker_code/tools/background/__init__.py +318 -0
- pythinker_code/tools/background/list.md +10 -0
- pythinker_code/tools/background/output.md +11 -0
- pythinker_code/tools/background/stop.md +8 -0
- pythinker_code/tools/display.py +46 -0
- pythinker_code/tools/dmail/__init__.py +38 -0
- pythinker_code/tools/dmail/dmail.md +17 -0
- pythinker_code/tools/file/__init__.py +30 -0
- pythinker_code/tools/file/glob.md +17 -0
- pythinker_code/tools/file/glob.py +160 -0
- pythinker_code/tools/file/grep.md +6 -0
- pythinker_code/tools/file/grep_local.py +589 -0
- pythinker_code/tools/file/plan_mode.py +45 -0
- pythinker_code/tools/file/read.md +16 -0
- pythinker_code/tools/file/read.py +300 -0
- pythinker_code/tools/file/read_media.md +24 -0
- pythinker_code/tools/file/read_media.py +217 -0
- pythinker_code/tools/file/replace.md +7 -0
- pythinker_code/tools/file/replace.py +195 -0
- pythinker_code/tools/file/utils.py +257 -0
- pythinker_code/tools/file/write.md +5 -0
- pythinker_code/tools/file/write.py +177 -0
- pythinker_code/tools/plan/__init__.py +327 -0
- pythinker_code/tools/plan/description.md +29 -0
- pythinker_code/tools/plan/enter.py +190 -0
- pythinker_code/tools/plan/enter_description.md +35 -0
- pythinker_code/tools/plan/heroes.py +277 -0
- pythinker_code/tools/shell/__init__.py +253 -0
- pythinker_code/tools/shell/bash.md +35 -0
- pythinker_code/tools/shell/powershell.md +30 -0
- pythinker_code/tools/test.py +55 -0
- pythinker_code/tools/think/__init__.py +21 -0
- pythinker_code/tools/think/think.md +1 -0
- pythinker_code/tools/todo/__init__.py +168 -0
- pythinker_code/tools/todo/set_todo_list.md +23 -0
- pythinker_code/tools/utils.py +199 -0
- pythinker_code/tools/web/__init__.py +4 -0
- pythinker_code/tools/web/fetch.md +1 -0
- pythinker_code/tools/web/fetch.py +189 -0
- pythinker_code/tools/web/search.md +1 -0
- pythinker_code/tools/web/search.py +163 -0
- pythinker_code/ui/__init__.py +0 -0
- pythinker_code/ui/acp/__init__.py +99 -0
- pythinker_code/ui/print/__init__.py +474 -0
- pythinker_code/ui/print/visualize.py +185 -0
- pythinker_code/ui/shell/__init__.py +1696 -0
- pythinker_code/ui/shell/console.py +109 -0
- pythinker_code/ui/shell/debug.py +190 -0
- pythinker_code/ui/shell/echo.py +17 -0
- pythinker_code/ui/shell/export_import.py +117 -0
- pythinker_code/ui/shell/keyboard.py +300 -0
- pythinker_code/ui/shell/mcp_status.py +113 -0
- pythinker_code/ui/shell/model_picker.py +318 -0
- pythinker_code/ui/shell/oauth.py +272 -0
- pythinker_code/ui/shell/placeholders.py +531 -0
- pythinker_code/ui/shell/prompt.py +2278 -0
- pythinker_code/ui/shell/replay.py +215 -0
- pythinker_code/ui/shell/session_picker.py +227 -0
- pythinker_code/ui/shell/setup.py +212 -0
- pythinker_code/ui/shell/slash.py +898 -0
- pythinker_code/ui/shell/startup.py +32 -0
- pythinker_code/ui/shell/task_browser.py +486 -0
- pythinker_code/ui/shell/update.py +350 -0
- pythinker_code/ui/shell/usage.py +291 -0
- pythinker_code/ui/shell/usage_adapters/__init__.py +50 -0
- pythinker_code/ui/shell/usage_adapters/anthropic_admin.py +233 -0
- pythinker_code/ui/shell/usage_adapters/base.py +72 -0
- pythinker_code/ui/shell/usage_adapters/deepseek.py +137 -0
- pythinker_code/ui/shell/usage_adapters/minimax.py +236 -0
- pythinker_code/ui/shell/usage_adapters/openai_admin.py +225 -0
- pythinker_code/ui/shell/usage_adapters/openai_chatgpt.py +241 -0
- pythinker_code/ui/shell/usage_adapters/opencode_go.py +232 -0
- pythinker_code/ui/shell/usage_adapters/openrouter.py +105 -0
- pythinker_code/ui/shell/usage_adapters/pythinker.py +189 -0
- pythinker_code/ui/shell/usage_adapters/pythinker_ai.py +50 -0
- pythinker_code/ui/shell/usage_render.py +150 -0
- pythinker_code/ui/shell/visualize/__init__.py +165 -0
- pythinker_code/ui/shell/visualize/_approval_panel.py +505 -0
- pythinker_code/ui/shell/visualize/_blocks.py +629 -0
- pythinker_code/ui/shell/visualize/_btw_panel.py +224 -0
- pythinker_code/ui/shell/visualize/_input_router.py +48 -0
- pythinker_code/ui/shell/visualize/_interactive.py +523 -0
- pythinker_code/ui/shell/visualize/_live_view.py +826 -0
- pythinker_code/ui/shell/visualize/_question_panel.py +586 -0
- pythinker_code/ui/theme.py +241 -0
- pythinker_code/usage_ratelimit_cache.py +175 -0
- pythinker_code/utils/__init__.py +0 -0
- pythinker_code/utils/aiohttp.py +24 -0
- pythinker_code/utils/aioqueue.py +72 -0
- pythinker_code/utils/broadcast.py +37 -0
- pythinker_code/utils/changelog.py +108 -0
- pythinker_code/utils/clipboard.py +246 -0
- pythinker_code/utils/datetime.py +64 -0
- pythinker_code/utils/diff.py +135 -0
- pythinker_code/utils/editor.py +91 -0
- pythinker_code/utils/environment.py +73 -0
- pythinker_code/utils/envvar.py +22 -0
- pythinker_code/utils/export.py +696 -0
- pythinker_code/utils/file_filter.py +375 -0
- pythinker_code/utils/frontmatter.py +70 -0
- pythinker_code/utils/io.py +27 -0
- pythinker_code/utils/logging.py +146 -0
- pythinker_code/utils/media_tags.py +29 -0
- pythinker_code/utils/message.py +24 -0
- pythinker_code/utils/path.py +199 -0
- pythinker_code/utils/proctitle.py +33 -0
- pythinker_code/utils/proxy.py +31 -0
- pythinker_code/utils/pyinstaller.py +45 -0
- pythinker_code/utils/rich/__init__.py +33 -0
- pythinker_code/utils/rich/columns.py +99 -0
- pythinker_code/utils/rich/diff_render.py +481 -0
- pythinker_code/utils/rich/markdown.py +900 -0
- pythinker_code/utils/rich/markdown_sample.md +108 -0
- pythinker_code/utils/rich/markdown_sample_short.md +2 -0
- pythinker_code/utils/rich/syntax.py +114 -0
- pythinker_code/utils/sensitive.py +54 -0
- pythinker_code/utils/server.py +121 -0
- pythinker_code/utils/signals.py +43 -0
- pythinker_code/utils/slashcmd.py +124 -0
- pythinker_code/utils/string.py +41 -0
- pythinker_code/utils/subprocess_env.py +73 -0
- pythinker_code/utils/term.py +168 -0
- pythinker_code/utils/typing.py +20 -0
- pythinker_code/vis/__init__.py +0 -0
- pythinker_code/vis/api/__init__.py +5 -0
- pythinker_code/vis/api/sessions.py +687 -0
- pythinker_code/vis/api/statistics.py +209 -0
- pythinker_code/vis/api/system.py +19 -0
- pythinker_code/vis/app.py +175 -0
- pythinker_code/vis/static/assets/highlighted-body-B3W2YXNL-D2MTYyJz.js +1 -0
- pythinker_code/vis/static/assets/index-CezafTt_.js +185 -0
- pythinker_code/vis/static/assets/index-DSRInNnm.css +1 -0
- pythinker_code/vis/static/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- pythinker_code/vis/static/index.html +17 -0
- pythinker_code/web/__init__.py +5 -0
- pythinker_code/web/api/__init__.py +15 -0
- pythinker_code/web/api/config.py +208 -0
- pythinker_code/web/api/open_in.py +199 -0
- pythinker_code/web/api/sessions.py +1225 -0
- pythinker_code/web/app.py +451 -0
- pythinker_code/web/auth.py +191 -0
- pythinker_code/web/models.py +98 -0
- pythinker_code/web/runner/__init__.py +5 -0
- pythinker_code/web/runner/messages.py +57 -0
- pythinker_code/web/runner/process.py +754 -0
- pythinker_code/web/runner/worker.py +97 -0
- pythinker_code/web/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- pythinker_code/web/static/assets/_baseUniq--dyU3g5v.js +1 -0
- pythinker_code/web/static/assets/abap-BdImnpbu.js +1 -0
- pythinker_code/web/static/assets/actionscript-3-CfeIJUat.js +1 -0
- pythinker_code/web/static/assets/ada-bCR0ucgS.js +1 -0
- pythinker_code/web/static/assets/andromeeda-C-Jbm3Hp.js +1 -0
- pythinker_code/web/static/assets/angular-html-CU67Zn6k.js +1 -0
- pythinker_code/web/static/assets/angular-ts-BwZT4LLn.js +1 -0
- pythinker_code/web/static/assets/apache-Pmp26Uib.js +1 -0
- pythinker_code/web/static/assets/apex-D8_7TLub.js +1 -0
- pythinker_code/web/static/assets/apl-dKokRX4l.js +1 -0
- pythinker_code/web/static/assets/applescript-Co6uUVPk.js +1 -0
- pythinker_code/web/static/assets/ara-BRHolxvo.js +1 -0
- pythinker_code/web/static/assets/arc-DkMjLpYa.js +1 -0
- pythinker_code/web/static/assets/architectureDiagram-VXUJARFQ-CHWVaGo9.js +36 -0
- pythinker_code/web/static/assets/asciidoc-Dv7Oe6Be.js +1 -0
- pythinker_code/web/static/assets/asm-D_Q5rh1f.js +1 -0
- pythinker_code/web/static/assets/astro-CbQHKStN.js +1 -0
- pythinker_code/web/static/assets/aurora-x-D-2ljcwZ.js +1 -0
- pythinker_code/web/static/assets/awk-DMzUqQB5.js +1 -0
- pythinker_code/web/static/assets/ayu-dark-CmMr59Fi.js +1 -0
- pythinker_code/web/static/assets/ballerina-BFfxhgS-.js +1 -0
- pythinker_code/web/static/assets/bat-BkioyH1T.js +1 -0
- pythinker_code/web/static/assets/beancount-k_qm7-4y.js +1 -0
- pythinker_code/web/static/assets/berry-uYugtg8r.js +1 -0
- pythinker_code/web/static/assets/bibtex-CHM0blh-.js +1 -0
- pythinker_code/web/static/assets/bicep-Bmn6On1c.js +1 -0
- pythinker_code/web/static/assets/blade-D4QpJJKB.js +1 -0
- pythinker_code/web/static/assets/blockDiagram-VD42YOAC-DzdKe497.js +122 -0
- pythinker_code/web/static/assets/bsl-BO_Y6i37.js +1 -0
- pythinker_code/web/static/assets/c-BIGW1oBm.js +1 -0
- pythinker_code/web/static/assets/c3-VCDPK7BO.js +1 -0
- pythinker_code/web/static/assets/c4Diagram-YG6GDRKO-D84Blotg.js +10 -0
- pythinker_code/web/static/assets/cadence-Bv_4Rxtq.js +1 -0
- pythinker_code/web/static/assets/cairo-KRGpt6FW.js +1 -0
- pythinker_code/web/static/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- pythinker_code/web/static/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- pythinker_code/web/static/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- pythinker_code/web/static/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- pythinker_code/web/static/assets/channel-CllSjjdl.js +1 -0
- pythinker_code/web/static/assets/chunk-4BX2VUAB-C9w8wleE.js +1 -0
- pythinker_code/web/static/assets/chunk-55IACEB6-YlYJ8HnF.js +1 -0
- pythinker_code/web/static/assets/chunk-B4BG7PRW-Bwtz_AHU.js +165 -0
- pythinker_code/web/static/assets/chunk-DI55MBZ5-BbEHkl8h.js +220 -0
- pythinker_code/web/static/assets/chunk-FMBD7UC4-BKPbvjLC.js +15 -0
- pythinker_code/web/static/assets/chunk-QN33PNHL-D73dQvKf.js +1 -0
- pythinker_code/web/static/assets/chunk-QZHKN3VN-zGiLKes_.js +1 -0
- pythinker_code/web/static/assets/chunk-TZMSLE5B-LHJCi2fy.js +1 -0
- pythinker_code/web/static/assets/clarity-D53aC0YG.js +1 -0
- pythinker_code/web/static/assets/classDiagram-2ON5EDUG-vX27iZwa.js +1 -0
- pythinker_code/web/static/assets/classDiagram-v2-WZHVMYZB-vX27iZwa.js +1 -0
- pythinker_code/web/static/assets/clojure-P80f7IUj.js +1 -0
- pythinker_code/web/static/assets/clone-DYBkaPm2.js +1 -0
- pythinker_code/web/static/assets/cmake-D1j8_8rp.js +1 -0
- pythinker_code/web/static/assets/cobol-nwyudZeR.js +1 -0
- pythinker_code/web/static/assets/code-block-IT6T5CEO-NtKViZGl.js +2 -0
- pythinker_code/web/static/assets/codeowners-Bp6g37R7.js +1 -0
- pythinker_code/web/static/assets/codeql-DsOJ9woJ.js +1 -0
- pythinker_code/web/static/assets/coffee-Ch7k5sss.js +1 -0
- pythinker_code/web/static/assets/common-lisp-Cg-RD9OK.js +1 -0
- pythinker_code/web/static/assets/coq-DkFqJrB1.js +1 -0
- pythinker_code/web/static/assets/cose-bilkent-S5V4N54A-DialjZpd.js +1 -0
- pythinker_code/web/static/assets/cpp-CofmeUqb.js +1 -0
- pythinker_code/web/static/assets/crystal-tKQVLTB8.js +1 -0
- pythinker_code/web/static/assets/csharp-K5feNrxe.js +1 -0
- pythinker_code/web/static/assets/css-DPfMkruS.js +1 -0
- pythinker_code/web/static/assets/csv-fuZLfV_i.js +1 -0
- pythinker_code/web/static/assets/cue-D82EKSYY.js +1 -0
- pythinker_code/web/static/assets/cypher-COkxafJQ.js +1 -0
- pythinker_code/web/static/assets/cytoscape.esm-C_Fzpdck.js +321 -0
- pythinker_code/web/static/assets/d-85-TOEBH.js +1 -0
- pythinker_code/web/static/assets/dagre-6UL2VRFP-DfuvkZZ7.js +4 -0
- pythinker_code/web/static/assets/dark-plus-C3mMm8J8.js +1 -0
- pythinker_code/web/static/assets/dart-CF10PKvl.js +1 -0
- pythinker_code/web/static/assets/dax-CEL-wOlO.js +1 -0
- pythinker_code/web/static/assets/defaultLocale-DX6XiGOO.js +1 -0
- pythinker_code/web/static/assets/desktop-BmXAJ9_W.js +1 -0
- pythinker_code/web/static/assets/diagram-PSM6KHXK-DLGctX3v.js +24 -0
- pythinker_code/web/static/assets/diagram-QEK2KX5R-DnxN6S0F.js +43 -0
- pythinker_code/web/static/assets/diagram-S2PKOQOG-Caq_Set9.js +24 -0
- pythinker_code/web/static/assets/diff-D97Zzqfu.js +1 -0
- pythinker_code/web/static/assets/docker-BcOcwvcX.js +1 -0
- pythinker_code/web/static/assets/dotenv-Da5cRb03.js +1 -0
- pythinker_code/web/static/assets/dracula-BzJJZx-M.js +1 -0
- pythinker_code/web/static/assets/dracula-soft-BXkSAIEj.js +1 -0
- pythinker_code/web/static/assets/dream-maker-BtqSS_iP.js +1 -0
- pythinker_code/web/static/assets/edge-BkV0erSs.js +1 -0
- pythinker_code/web/static/assets/elixir-CDX3lj18.js +1 -0
- pythinker_code/web/static/assets/elm-DbKCFpqz.js +1 -0
- pythinker_code/web/static/assets/emacs-lisp-C9XAeP06.js +1 -0
- pythinker_code/web/static/assets/erDiagram-Q2GNP2WA-BgTfALoK.js +60 -0
- pythinker_code/web/static/assets/erb-BOJIQeun.js +1 -0
- pythinker_code/web/static/assets/erlang-DsQrWhSR.js +1 -0
- pythinker_code/web/static/assets/everforest-dark-BgDCqdQA.js +1 -0
- pythinker_code/web/static/assets/everforest-light-C8M2exoo.js +1 -0
- pythinker_code/web/static/assets/fennel-BYunw83y.js +1 -0
- pythinker_code/web/static/assets/fish-BvzEVeQv.js +1 -0
- pythinker_code/web/static/assets/flowDiagram-NV44I4VS-QjW_fnGi.js +162 -0
- pythinker_code/web/static/assets/fluent-C4IJs8-o.js +1 -0
- pythinker_code/web/static/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- pythinker_code/web/static/assets/fortran-free-form-BxgE0vQu.js +1 -0
- pythinker_code/web/static/assets/fsharp-CXgrBDvD.js +1 -0
- pythinker_code/web/static/assets/ganttDiagram-JELNMOA3-fqi8JFof.js +267 -0
- pythinker_code/web/static/assets/gdresource-B7Tvp0Sc.js +1 -0
- pythinker_code/web/static/assets/gdscript-DTMYz4Jt.js +1 -0
- pythinker_code/web/static/assets/gdshader-DkwncUOv.js +1 -0
- pythinker_code/web/static/assets/genie-D0YGMca9.js +1 -0
- pythinker_code/web/static/assets/gherkin-DyxjwDmM.js +1 -0
- pythinker_code/web/static/assets/git-commit-F4YmCXRG.js +1 -0
- pythinker_code/web/static/assets/git-rebase-r7XF79zn.js +1 -0
- pythinker_code/web/static/assets/gitGraphDiagram-NY62KEGX-i7o6VQ8x.js +65 -0
- pythinker_code/web/static/assets/github-dark-DHJKELXO.js +1 -0
- pythinker_code/web/static/assets/github-dark-default-Cuk6v7N8.js +1 -0
- pythinker_code/web/static/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- pythinker_code/web/static/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- pythinker_code/web/static/assets/github-light-DAi9KRSo.js +1 -0
- pythinker_code/web/static/assets/github-light-default-D7oLnXFd.js +1 -0
- pythinker_code/web/static/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- pythinker_code/web/static/assets/gleam-BspZqrRM.js +1 -0
- pythinker_code/web/static/assets/glimmer-js-Rg0-pVw9.js +1 -0
- pythinker_code/web/static/assets/glimmer-ts-U6CK756n.js +1 -0
- pythinker_code/web/static/assets/glsl-DplSGwfg.js +1 -0
- pythinker_code/web/static/assets/gn-n2N0HUVH.js +1 -0
- pythinker_code/web/static/assets/gnuplot-DdkO51Og.js +1 -0
- pythinker_code/web/static/assets/go-Dn2_MT6a.js +1 -0
- pythinker_code/web/static/assets/graph-C0vZK2pT.js +1 -0
- pythinker_code/web/static/assets/graphql-ChdNCCLP.js +1 -0
- pythinker_code/web/static/assets/groovy-gcz8RCvz.js +1 -0
- pythinker_code/web/static/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- pythinker_code/web/static/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- pythinker_code/web/static/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- pythinker_code/web/static/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- pythinker_code/web/static/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- pythinker_code/web/static/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- pythinker_code/web/static/assets/hack-CaT9iCJl.js +1 -0
- pythinker_code/web/static/assets/haml-B8DHNrY2.js +1 -0
- pythinker_code/web/static/assets/handlebars-BL8al0AC.js +1 -0
- pythinker_code/web/static/assets/haskell-Df6bDoY_.js +1 -0
- pythinker_code/web/static/assets/haxe-CzTSHFRz.js +1 -0
- pythinker_code/web/static/assets/hcl-BWvSN4gD.js +1 -0
- pythinker_code/web/static/assets/hjson-D5-asLiD.js +1 -0
- pythinker_code/web/static/assets/hlsl-D3lLCCz7.js +1 -0
- pythinker_code/web/static/assets/houston-DnULxvSX.js +1 -0
- pythinker_code/web/static/assets/html-GMplVEZG.js +1 -0
- pythinker_code/web/static/assets/html-derivative-BFtXZ54Q.js +1 -0
- pythinker_code/web/static/assets/http-jrhK8wxY.js +1 -0
- pythinker_code/web/static/assets/hurl-irOxFIW8.js +1 -0
- pythinker_code/web/static/assets/hxml-Bvhsp5Yf.js +1 -0
- pythinker_code/web/static/assets/hy-DFXneXwc.js +1 -0
- pythinker_code/web/static/assets/imba-DGztddWO.js +1 -0
- pythinker_code/web/static/assets/index-BYCCk6-K.js +153 -0
- pythinker_code/web/static/assets/index-BpoLgcEt.js +1 -0
- pythinker_code/web/static/assets/index-Cpy4G3uJ.js +2 -0
- pythinker_code/web/static/assets/index-CzV_vCfu.css +1 -0
- pythinker_code/web/static/assets/index-DI2oedCt.js +19 -0
- pythinker_code/web/static/assets/index-DdIkp80K.js +5 -0
- pythinker_code/web/static/assets/infoDiagram-WHAUD3N6-BMPpeZSM.js +2 -0
- pythinker_code/web/static/assets/ini-BEwlwnbL.js +1 -0
- pythinker_code/web/static/assets/init-Gi6I4Gst.js +1 -0
- pythinker_code/web/static/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- pythinker_code/web/static/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- pythinker_code/web/static/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- pythinker_code/web/static/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- pythinker_code/web/static/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- pythinker_code/web/static/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- pythinker_code/web/static/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- pythinker_code/web/static/assets/java-CylS5w8V.js +1 -0
- pythinker_code/web/static/assets/javascript-wDzz0qaB.js +1 -0
- pythinker_code/web/static/assets/jinja-4LBKfQ-Z.js +1 -0
- pythinker_code/web/static/assets/jison-wvAkD_A8.js +1 -0
- pythinker_code/web/static/assets/journeyDiagram-XKPGCS4Q-DAM7gngo.js +139 -0
- pythinker_code/web/static/assets/json-Cp-IABpG.js +1 -0
- pythinker_code/web/static/assets/json5-C9tS-k6U.js +1 -0
- pythinker_code/web/static/assets/jsonc-Des-eS-w.js +1 -0
- pythinker_code/web/static/assets/jsonl-DcaNXYhu.js +1 -0
- pythinker_code/web/static/assets/jsonnet-DFQXde-d.js +1 -0
- pythinker_code/web/static/assets/jssm-C2t-YnRu.js +1 -0
- pythinker_code/web/static/assets/jsx-g9-lgVsj.js +1 -0
- pythinker_code/web/static/assets/julia-CxzCAyBv.js +1 -0
- pythinker_code/web/static/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- pythinker_code/web/static/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- pythinker_code/web/static/assets/kanagawa-wave-DWedfzmr.js +1 -0
- pythinker_code/web/static/assets/kanban-definition-3W4ZIXB7-ChpBpV0k.js +89 -0
- pythinker_code/web/static/assets/katex-D2lIc1rk.css +1 -0
- pythinker_code/web/static/assets/kdl-DV7GczEv.js +1 -0
- pythinker_code/web/static/assets/kotlin-BdnUsdx6.js +1 -0
- pythinker_code/web/static/assets/kusto-DZf3V79B.js +1 -0
- pythinker_code/web/static/assets/laserwave-DUszq2jm.js +1 -0
- pythinker_code/web/static/assets/latex-B4uzh10-.js +1 -0
- pythinker_code/web/static/assets/layout-C3Jp1gKO.js +1 -0
- pythinker_code/web/static/assets/lean-BZvkOJ9d.js +1 -0
- pythinker_code/web/static/assets/less-B1dDrJ26.js +1 -0
- pythinker_code/web/static/assets/light-plus-B7mTdjB0.js +1 -0
- pythinker_code/web/static/assets/linear-BGHtL1N4.js +1 -0
- pythinker_code/web/static/assets/liquid-DYVedYrR.js +1 -0
- pythinker_code/web/static/assets/llvm-BtvRca6l.js +1 -0
- pythinker_code/web/static/assets/log-2UxHyX5q.js +1 -0
- pythinker_code/web/static/assets/logo-BtOb2qkB.js +1 -0
- pythinker_code/web/static/assets/lua-BbnMAYS6.js +1 -0
- pythinker_code/web/static/assets/luau-C-HG3fhB.js +1 -0
- pythinker_code/web/static/assets/make-CHLpvVh8.js +1 -0
- pythinker_code/web/static/assets/markdown-Cvjx9yec.js +1 -0
- pythinker_code/web/static/assets/marko-DZsq8hO1.js +1 -0
- pythinker_code/web/static/assets/material-theme-D5KoaKCx.js +1 -0
- pythinker_code/web/static/assets/material-theme-darker-BfHTSMKl.js +1 -0
- pythinker_code/web/static/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- pythinker_code/web/static/assets/material-theme-ocean-CyktbL80.js +1 -0
- pythinker_code/web/static/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- pythinker_code/web/static/assets/matlab-D7o27uSR.js +1 -0
- pythinker_code/web/static/assets/mdc-DUICxH0z.js +1 -0
- pythinker_code/web/static/assets/mdx-Cmh6b_Ma.js +1 -0
- pythinker_code/web/static/assets/mermaid-VLURNSYL-B2P5VJ9v.css +1 -0
- pythinker_code/web/static/assets/mermaid-VLURNSYL-C_HW6koB.js +465 -0
- pythinker_code/web/static/assets/mermaid-mWjccvbQ.js +1 -0
- pythinker_code/web/static/assets/mermaid.core-CnT4VrPC.js +191 -0
- pythinker_code/web/static/assets/min-Dn5VRVmX.js +1 -0
- pythinker_code/web/static/assets/min-dark-CafNBF8u.js +1 -0
- pythinker_code/web/static/assets/min-light-CTRr51gU.js +1 -0
- pythinker_code/web/static/assets/mindmap-definition-VGOIOE7T-x8EwhfIt.js +68 -0
- pythinker_code/web/static/assets/mipsasm-CKIfxQSi.js +1 -0
- pythinker_code/web/static/assets/mojo-B93PlW-d.js +1 -0
- pythinker_code/web/static/assets/monokai-D4h5O-jR.js +1 -0
- pythinker_code/web/static/assets/moonbit-Ba13S78F.js +1 -0
- pythinker_code/web/static/assets/move-Bu9oaDYs.js +1 -0
- pythinker_code/web/static/assets/narrat-DRg8JJMk.js +1 -0
- pythinker_code/web/static/assets/nextflow-BrzmwbiE.js +1 -0
- pythinker_code/web/static/assets/nginx-DknmC5AR.js +1 -0
- pythinker_code/web/static/assets/night-owl-C39BiMTA.js +1 -0
- pythinker_code/web/static/assets/nim-CVrawwO9.js +1 -0
- pythinker_code/web/static/assets/nix-CwoSXNpI.js +1 -0
- pythinker_code/web/static/assets/nord-Ddv68eIx.js +1 -0
- pythinker_code/web/static/assets/nushell-C-sUppwS.js +1 -0
- pythinker_code/web/static/assets/objective-c-DXmwc3jG.js +1 -0
- pythinker_code/web/static/assets/objective-cpp-CLxacb5B.js +1 -0
- pythinker_code/web/static/assets/ocaml-C0hk2d4L.js +1 -0
- pythinker_code/web/static/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- pythinker_code/web/static/assets/one-light-PoHY5YXO.js +1 -0
- pythinker_code/web/static/assets/openscad-C4EeE6gA.js +1 -0
- pythinker_code/web/static/assets/ordinal-Cboi1Yqb.js +1 -0
- pythinker_code/web/static/assets/pascal-D93ZcfNL.js +1 -0
- pythinker_code/web/static/assets/perl-C0TMdlhV.js +1 -0
- pythinker_code/web/static/assets/php-CDn_0X-4.js +1 -0
- pythinker_code/web/static/assets/pieDiagram-ADFJNKIX-DgxBKGz2.js +30 -0
- pythinker_code/web/static/assets/pkl-u5AG7uiY.js +1 -0
- pythinker_code/web/static/assets/plastic-3e1v2bzS.js +1 -0
- pythinker_code/web/static/assets/plsql-ChMvpjG-.js +1 -0
- pythinker_code/web/static/assets/po-BTJTHyun.js +1 -0
- pythinker_code/web/static/assets/poimandres-CS3Unz2-.js +1 -0
- pythinker_code/web/static/assets/polar-C0HS_06l.js +1 -0
- pythinker_code/web/static/assets/postcss-CXtECtnM.js +1 -0
- pythinker_code/web/static/assets/powerquery-CEu0bR-o.js +1 -0
- pythinker_code/web/static/assets/powershell-Dpen1YoG.js +1 -0
- pythinker_code/web/static/assets/prisma-Dd19v3D-.js +1 -0
- pythinker_code/web/static/assets/prolog-CbFg5uaA.js +1 -0
- pythinker_code/web/static/assets/proto-C7zT0LnQ.js +1 -0
- pythinker_code/web/static/assets/pug-CGlum2m_.js +1 -0
- pythinker_code/web/static/assets/puppet-BMWR74SV.js +1 -0
- pythinker_code/web/static/assets/purescript-CklMAg4u.js +1 -0
- pythinker_code/web/static/assets/python-B6aJPvgy.js +1 -0
- pythinker_code/web/static/assets/qml-3beO22l8.js +1 -0
- pythinker_code/web/static/assets/qmldir-C8lEn-DE.js +1 -0
- pythinker_code/web/static/assets/qss-IeuSbFQv.js +1 -0
- pythinker_code/web/static/assets/quadrantDiagram-AYHSOK5B-DSpe_dqk.js +7 -0
- pythinker_code/web/static/assets/r-Dspwwk_N.js +1 -0
- pythinker_code/web/static/assets/racket-BqYA7rlc.js +1 -0
- pythinker_code/web/static/assets/raku-DXvB9xmW.js +1 -0
- pythinker_code/web/static/assets/razor-C1TweQQi.js +1 -0
- pythinker_code/web/static/assets/red-bN70gL4F.js +1 -0
- pythinker_code/web/static/assets/reg-C-SQnVFl.js +1 -0
- pythinker_code/web/static/assets/regexp-CDVJQ6XC.js +1 -0
- pythinker_code/web/static/assets/rel-C3B-1QV4.js +1 -0
- pythinker_code/web/static/assets/requirementDiagram-UZGBJVZJ-8o9hozL-.js +64 -0
- pythinker_code/web/static/assets/riscv-BM1_JUlF.js +1 -0
- pythinker_code/web/static/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- pythinker_code/web/static/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- pythinker_code/web/static/assets/rose-pine-qdsjHGoJ.js +1 -0
- pythinker_code/web/static/assets/rosmsg-BJDFO7_C.js +1 -0
- pythinker_code/web/static/assets/rst-B0xPkSld.js +1 -0
- pythinker_code/web/static/assets/ruby-BvKwtOVI.js +1 -0
- pythinker_code/web/static/assets/rust-B1yitclQ.js +1 -0
- pythinker_code/web/static/assets/sankeyDiagram-TZEHDZUN-BLOSUixH.js +10 -0
- pythinker_code/web/static/assets/sas-cz2c8ADy.js +1 -0
- pythinker_code/web/static/assets/sass-Cj5Yp3dK.js +1 -0
- pythinker_code/web/static/assets/scala-C151Ov-r.js +1 -0
- pythinker_code/web/static/assets/scheme-C98Dy4si.js +1 -0
- pythinker_code/web/static/assets/scss-OYdSNvt2.js +1 -0
- pythinker_code/web/static/assets/sdbl-DVxCFoDh.js +1 -0
- pythinker_code/web/static/assets/sequenceDiagram-WL72ISMW-6F2G8JTU.js +145 -0
- pythinker_code/web/static/assets/shaderlab-Dg9Lc6iA.js +1 -0
- pythinker_code/web/static/assets/shellscript-Yzrsuije.js +1 -0
- pythinker_code/web/static/assets/shellsession-BADoaaVG.js +1 -0
- pythinker_code/web/static/assets/slack-dark-BthQWCQV.js +1 -0
- pythinker_code/web/static/assets/slack-ochin-DqwNpetd.js +1 -0
- pythinker_code/web/static/assets/smalltalk-BERRCDM3.js +1 -0
- pythinker_code/web/static/assets/snazzy-light-Bw305WKR.js +1 -0
- pythinker_code/web/static/assets/solarized-dark-DXbdFlpD.js +1 -0
- pythinker_code/web/static/assets/solarized-light-L9t79GZl.js +1 -0
- pythinker_code/web/static/assets/solidity-rGO070M0.js +1 -0
- pythinker_code/web/static/assets/soy-Brmx7dQM.js +1 -0
- pythinker_code/web/static/assets/sparql-rVzFXLq3.js +1 -0
- pythinker_code/web/static/assets/splunk-BtCnVYZw.js +1 -0
- pythinker_code/web/static/assets/sql-BLtJtn59.js +1 -0
- pythinker_code/web/static/assets/ssh-config-_ykCGR6B.js +1 -0
- pythinker_code/web/static/assets/stata-BH5u7GGu.js +1 -0
- pythinker_code/web/static/assets/stateDiagram-FKZM4ZOC-DP8xP0iJ.js +1 -0
- pythinker_code/web/static/assets/stateDiagram-v2-4FDKWEC3-1l6-EZNX.js +1 -0
- pythinker_code/web/static/assets/stylus-BEDo0Tqx.js +1 -0
- pythinker_code/web/static/assets/svelte-zxCyuUbr.js +1 -0
- pythinker_code/web/static/assets/swift-Dg5xB15N.js +1 -0
- pythinker_code/web/static/assets/synthwave-84-CbfX1IO0.js +1 -0
- pythinker_code/web/static/assets/system-verilog-CnnmHF94.js +1 -0
- pythinker_code/web/static/assets/systemd-4A_iFExJ.js +1 -0
- pythinker_code/web/static/assets/talonscript-CkByrt1z.js +1 -0
- pythinker_code/web/static/assets/tasl-QIJgUcNo.js +1 -0
- pythinker_code/web/static/assets/tcl-dwOrl1Do.js +1 -0
- pythinker_code/web/static/assets/templ-W15q3VgB.js +1 -0
- pythinker_code/web/static/assets/terraform-BETggiCN.js +1 -0
- pythinker_code/web/static/assets/tex-CvyZ59Mk.js +1 -0
- pythinker_code/web/static/assets/timeline-definition-IT6M3QCI-DMgruDfK.js +61 -0
- pythinker_code/web/static/assets/tokyo-night-hegEt444.js +1 -0
- pythinker_code/web/static/assets/toml-vGWfd6FD.js +1 -0
- pythinker_code/web/static/assets/treemap-KMMF4GRG-Bo9ZkrAK.js +128 -0
- pythinker_code/web/static/assets/ts-tags-zn1MmPIZ.js +1 -0
- pythinker_code/web/static/assets/tsv-B_m7g4N7.js +1 -0
- pythinker_code/web/static/assets/tsx-COt5Ahok.js +1 -0
- pythinker_code/web/static/assets/turtle-BsS91CYL.js +1 -0
- pythinker_code/web/static/assets/twig-CO9l9SDP.js +1 -0
- pythinker_code/web/static/assets/typescript-BPQ3VLAy.js +1 -0
- pythinker_code/web/static/assets/typespec-BGHnOYBU.js +1 -0
- pythinker_code/web/static/assets/typst-DHCkPAjA.js +1 -0
- pythinker_code/web/static/assets/v-BcVCzyr7.js +1 -0
- pythinker_code/web/static/assets/vala-CsfeWuGM.js +1 -0
- pythinker_code/web/static/assets/vb-D17OF-Vu.js +1 -0
- pythinker_code/web/static/assets/verilog-BQ8w6xss.js +1 -0
- pythinker_code/web/static/assets/vesper-DU1UobuO.js +1 -0
- pythinker_code/web/static/assets/vhdl-CeAyd5Ju.js +1 -0
- pythinker_code/web/static/assets/viml-CJc9bBzg.js +1 -0
- pythinker_code/web/static/assets/vitesse-black-Bkuqu6BP.js +1 -0
- pythinker_code/web/static/assets/vitesse-dark-D0r3Knsf.js +1 -0
- pythinker_code/web/static/assets/vitesse-light-CVO1_9PV.js +1 -0
- pythinker_code/web/static/assets/vue-DN_0RTcg.js +1 -0
- pythinker_code/web/static/assets/vue-html-AaS7Mt5G.js +1 -0
- pythinker_code/web/static/assets/vue-vine-CQOfvN7w.js +1 -0
- pythinker_code/web/static/assets/vyper-CDx5xZoG.js +1 -0
- pythinker_code/web/static/assets/wasm-CG6Dc4jp.js +1 -0
- pythinker_code/web/static/assets/wasm-MzD3tlZU.js +1 -0
- pythinker_code/web/static/assets/wenyan-BV7otONQ.js +1 -0
- pythinker_code/web/static/assets/wgsl-Dx-B1_4e.js +1 -0
- pythinker_code/web/static/assets/wikitext-BhOHFoWU.js +1 -0
- pythinker_code/web/static/assets/wit-5i3qLPDT.js +1 -0
- pythinker_code/web/static/assets/wolfram-lXgVvXCa.js +1 -0
- pythinker_code/web/static/assets/xml-sdJ4AIDG.js +1 -0
- pythinker_code/web/static/assets/xsl-CtQFsRM5.js +1 -0
- pythinker_code/web/static/assets/xychartDiagram-PRI3JC2R-GeF2johi.js +7 -0
- pythinker_code/web/static/assets/yaml-Buea-lGh.js +1 -0
- pythinker_code/web/static/assets/zenscript-DVFEvuxE.js +1 -0
- pythinker_code/web/static/assets/zig-VOosw3JB.js +1 -0
- pythinker_code/web/static/brand/apple-touch-icon.png +0 -0
- pythinker_code/web/static/brand/arctecture.webp +0 -0
- pythinker_code/web/static/brand/bimi-logo.svg +46 -0
- pythinker_code/web/static/brand/favicon.ico +0 -0
- pythinker_code/web/static/brand/fonts/dm-sans-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/dm-sans-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/instrument-sans-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/instrument-sans-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/instrument-serif-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/instrument-serif-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/libre-baskerville-italic-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/libre-baskerville-italic-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/libre-baskerville-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/libre-baskerville-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/roboto-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/roboto-latin.woff2 +0 -0
- pythinker_code/web/static/brand/icon-192.png +0 -0
- pythinker_code/web/static/brand/icon-512.png +0 -0
- pythinker_code/web/static/brand/icon.svg +1 -0
- pythinker_code/web/static/brand/logo.png +0 -0
- pythinker_code/web/static/brand/pythinker_animated.svg +79 -0
- pythinker_code/web/static/brand/robots.txt +4 -0
- pythinker_code/web/static/index.html +15 -0
- pythinker_code/web/static/logo.png +0 -0
- pythinker_code/web/store/__init__.py +1 -0
- pythinker_code/web/store/sessions.py +432 -0
- pythinker_code/wire/__init__.py +148 -0
- pythinker_code/wire/file.py +151 -0
- pythinker_code/wire/jsonrpc.py +263 -0
- pythinker_code/wire/protocol.py +2 -0
- pythinker_code/wire/root_hub.py +27 -0
- pythinker_code/wire/serde.py +26 -0
- pythinker_code/wire/server.py +1069 -0
- pythinker_code/wire/types.py +698 -0
- pythinker_code-2.0.0.dist-info/METADATA +660 -0
- pythinker_code-2.0.0.dist-info/RECORD +731 -0
- pythinker_code-2.0.0.dist-info/WHEEL +4 -0
- pythinker_code-2.0.0.dist-info/entry_points.txt +4 -0
- pythinker_code-2.0.0.dist-info/licenses/LICENSE +202 -0
- pythinker_code-2.0.0.dist-info/licenses/NOTICE +14 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
5
|
+
|
|
6
|
+
import aiohttp
|
|
7
|
+
|
|
8
|
+
from pythinker_code.auth import OPENROUTER_PLATFORM_ID
|
|
9
|
+
from pythinker_code.ui.shell.usage_adapters.base import UsageReport, UsageRow
|
|
10
|
+
from pythinker_code.utils.aiohttp import new_client_session
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pythinker_code.auth.oauth import OAuthManager
|
|
14
|
+
from pythinker_code.config import LLMProvider
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
OPENROUTER_KEY_URL = "https://openrouter.ai/api/v1/key"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class OpenRouterAdapter:
|
|
21
|
+
platform_id = OPENROUTER_PLATFORM_ID
|
|
22
|
+
requires_admin_key = False
|
|
23
|
+
provider_label = "OpenRouter"
|
|
24
|
+
|
|
25
|
+
async def fetch(
|
|
26
|
+
self,
|
|
27
|
+
provider: LLMProvider,
|
|
28
|
+
oauth_mgr: OAuthManager,
|
|
29
|
+
) -> UsageReport:
|
|
30
|
+
api_key = oauth_mgr.resolve_api_key(provider.api_key, provider.oauth)
|
|
31
|
+
try:
|
|
32
|
+
async with (
|
|
33
|
+
new_client_session() as session,
|
|
34
|
+
session.get(
|
|
35
|
+
OPENROUTER_KEY_URL,
|
|
36
|
+
headers={"Authorization": f"Bearer {api_key}"},
|
|
37
|
+
timeout=aiohttp.ClientTimeout(total=5),
|
|
38
|
+
raise_for_status=True,
|
|
39
|
+
) as resp,
|
|
40
|
+
):
|
|
41
|
+
payload = await resp.json()
|
|
42
|
+
except aiohttp.ClientResponseError as e:
|
|
43
|
+
if e.status == 401:
|
|
44
|
+
message = "OpenRouter returned 401 — check your API key."
|
|
45
|
+
else:
|
|
46
|
+
message = f"OpenRouter usage fetch failed: HTTP {e.status}"
|
|
47
|
+
return UsageReport(self.provider_label, None, [], notes=[message])
|
|
48
|
+
except (TimeoutError, aiohttp.ClientError) as e:
|
|
49
|
+
return UsageReport(
|
|
50
|
+
self.provider_label,
|
|
51
|
+
None,
|
|
52
|
+
[],
|
|
53
|
+
notes=[f"OpenRouter usage fetch failed: {e}"],
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if not isinstance(payload, Mapping):
|
|
57
|
+
return UsageReport(self.provider_label, None, [], notes=["Unexpected response shape."])
|
|
58
|
+
return parse_openrouter_payload(cast(Mapping[str, Any], payload))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def parse_openrouter_payload(payload: Mapping[str, Any]) -> UsageReport:
|
|
62
|
+
data_raw = payload.get("data")
|
|
63
|
+
if not isinstance(data_raw, Mapping):
|
|
64
|
+
return UsageReport(
|
|
65
|
+
provider_label=OpenRouterAdapter.provider_label,
|
|
66
|
+
summary=None,
|
|
67
|
+
limits=[],
|
|
68
|
+
notes=["Unexpected response shape."],
|
|
69
|
+
unit_hint="USD",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
data = cast(Mapping[str, Any], data_raw)
|
|
73
|
+
limit_reset = data.get("limit_reset")
|
|
74
|
+
summary = UsageRow(
|
|
75
|
+
label="Credit balance",
|
|
76
|
+
used=_to_cents(data.get("usage")),
|
|
77
|
+
limit=_to_cents(data.get("limit")),
|
|
78
|
+
unit="USD",
|
|
79
|
+
reset_hint=f"resets {limit_reset}" if limit_reset else None,
|
|
80
|
+
)
|
|
81
|
+
limits = [
|
|
82
|
+
UsageRow("Today", _to_cents(data.get("usage_daily")), 0, unit="USD"),
|
|
83
|
+
UsageRow("This week", _to_cents(data.get("usage_weekly")), 0, unit="USD"),
|
|
84
|
+
UsageRow("This month", _to_cents(data.get("usage_monthly")), 0, unit="USD"),
|
|
85
|
+
]
|
|
86
|
+
notes = (
|
|
87
|
+
["Free tier key; OpenRouter may apply free-model limits."]
|
|
88
|
+
if data.get("is_free_tier")
|
|
89
|
+
else []
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return UsageReport(
|
|
93
|
+
provider_label=OpenRouterAdapter.provider_label,
|
|
94
|
+
summary=summary,
|
|
95
|
+
limits=limits,
|
|
96
|
+
notes=notes,
|
|
97
|
+
unit_hint="USD",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _to_cents(value: Any) -> int:
|
|
102
|
+
try:
|
|
103
|
+
return int(round(float(value) * 100))
|
|
104
|
+
except (OverflowError, TypeError, ValueError):
|
|
105
|
+
return 0
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping, Sequence
|
|
4
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
5
|
+
|
|
6
|
+
import aiohttp
|
|
7
|
+
|
|
8
|
+
from pythinker_code.auth import PYTHINKER_CODE_PLATFORM_ID
|
|
9
|
+
from pythinker_code.auth.platforms import get_platform_by_id
|
|
10
|
+
from pythinker_code.ui.shell.usage_adapters.base import UsageReport, UsageRow
|
|
11
|
+
from pythinker_code.utils.aiohttp import new_client_session
|
|
12
|
+
from pythinker_code.utils.datetime import format_duration
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from pythinker_code.auth.oauth import OAuthManager
|
|
16
|
+
from pythinker_code.config import LLMProvider
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PythinkerAdapter:
|
|
20
|
+
platform_id = PYTHINKER_CODE_PLATFORM_ID
|
|
21
|
+
requires_admin_key = False
|
|
22
|
+
provider_label = "Pythinker"
|
|
23
|
+
|
|
24
|
+
async def fetch(
|
|
25
|
+
self,
|
|
26
|
+
provider: LLMProvider,
|
|
27
|
+
oauth_mgr: OAuthManager,
|
|
28
|
+
) -> UsageReport:
|
|
29
|
+
platform = get_platform_by_id(self.platform_id)
|
|
30
|
+
if platform is None:
|
|
31
|
+
return UsageReport(
|
|
32
|
+
provider_label=self.provider_label,
|
|
33
|
+
summary=None,
|
|
34
|
+
limits=[],
|
|
35
|
+
notes=["Usage is available on Pythinker platform only."],
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
url = f"{platform.base_url.rstrip('/')}/usages"
|
|
39
|
+
api_key = oauth_mgr.resolve_api_key(provider.api_key, provider.oauth)
|
|
40
|
+
try:
|
|
41
|
+
async with (
|
|
42
|
+
new_client_session() as session,
|
|
43
|
+
session.get(
|
|
44
|
+
url,
|
|
45
|
+
headers={"Authorization": f"Bearer {api_key}"},
|
|
46
|
+
timeout=aiohttp.ClientTimeout(total=5),
|
|
47
|
+
raise_for_status=True,
|
|
48
|
+
) as resp,
|
|
49
|
+
):
|
|
50
|
+
payload = await resp.json()
|
|
51
|
+
except aiohttp.ClientResponseError as e:
|
|
52
|
+
message = "Failed to fetch usage."
|
|
53
|
+
if e.status == 401:
|
|
54
|
+
message = "Authorization failed. Please check your API key."
|
|
55
|
+
elif e.status == 404:
|
|
56
|
+
message = "Usage endpoint not available. Try Pythinker for Coding."
|
|
57
|
+
return UsageReport(self.provider_label, None, [], notes=[message])
|
|
58
|
+
except TimeoutError:
|
|
59
|
+
return UsageReport(
|
|
60
|
+
self.provider_label,
|
|
61
|
+
None,
|
|
62
|
+
[],
|
|
63
|
+
notes=["Failed to fetch usage: request timed out."],
|
|
64
|
+
)
|
|
65
|
+
except aiohttp.ClientError as e:
|
|
66
|
+
return UsageReport(self.provider_label, None, [], notes=[f"Failed to fetch usage: {e}"])
|
|
67
|
+
|
|
68
|
+
return parse_pythinker_payload(payload)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def parse_pythinker_payload(payload: Mapping[str, Any]) -> UsageReport:
|
|
72
|
+
summary: UsageRow | None = None
|
|
73
|
+
limits: list[UsageRow] = []
|
|
74
|
+
|
|
75
|
+
usage = payload.get("usage")
|
|
76
|
+
if isinstance(usage, Mapping):
|
|
77
|
+
usage_map: Mapping[str, Any] = cast(Mapping[str, Any], usage)
|
|
78
|
+
summary = _to_usage_row(usage_map, default_label="Weekly limit")
|
|
79
|
+
|
|
80
|
+
raw_limits_obj = payload.get("limits")
|
|
81
|
+
if isinstance(raw_limits_obj, Sequence):
|
|
82
|
+
limits_seq: Sequence[Any] = cast(Sequence[Any], raw_limits_obj)
|
|
83
|
+
for idx, item in enumerate(limits_seq):
|
|
84
|
+
if not isinstance(item, Mapping):
|
|
85
|
+
continue
|
|
86
|
+
item_map: Mapping[str, Any] = cast(Mapping[str, Any], item)
|
|
87
|
+
detail_raw = item_map.get("detail")
|
|
88
|
+
detail: Mapping[str, Any] = (
|
|
89
|
+
cast(Mapping[str, Any], detail_raw) if isinstance(detail_raw, Mapping) else item_map
|
|
90
|
+
)
|
|
91
|
+
window_raw = item_map.get("window")
|
|
92
|
+
window: Mapping[str, Any] = (
|
|
93
|
+
cast(Mapping[str, Any], window_raw) if isinstance(window_raw, Mapping) else {}
|
|
94
|
+
)
|
|
95
|
+
label = _limit_label(item_map, detail, window, idx)
|
|
96
|
+
row = _to_usage_row(detail, default_label=label)
|
|
97
|
+
if row:
|
|
98
|
+
limits.append(row)
|
|
99
|
+
|
|
100
|
+
return UsageReport(
|
|
101
|
+
provider_label=PythinkerAdapter.provider_label,
|
|
102
|
+
summary=summary,
|
|
103
|
+
limits=limits,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _to_usage_row(data: Mapping[str, Any], *, default_label: str) -> UsageRow | None:
|
|
108
|
+
limit = _to_int(data.get("limit"))
|
|
109
|
+
used = _to_int(data.get("used"))
|
|
110
|
+
if used is None:
|
|
111
|
+
remaining = _to_int(data.get("remaining"))
|
|
112
|
+
if remaining is not None and limit is not None:
|
|
113
|
+
used = limit - remaining
|
|
114
|
+
if used is None and limit is None:
|
|
115
|
+
return None
|
|
116
|
+
return UsageRow(
|
|
117
|
+
label=str(data.get("name") or data.get("title") or default_label),
|
|
118
|
+
used=used or 0,
|
|
119
|
+
limit=limit or 0,
|
|
120
|
+
reset_hint=_reset_hint(data),
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _limit_label(
|
|
125
|
+
item: Mapping[str, Any],
|
|
126
|
+
detail: Mapping[str, Any],
|
|
127
|
+
window: Mapping[str, Any],
|
|
128
|
+
idx: int,
|
|
129
|
+
) -> str:
|
|
130
|
+
for key in ("name", "title", "scope"):
|
|
131
|
+
if val := (item.get(key) or detail.get(key)):
|
|
132
|
+
return str(val)
|
|
133
|
+
|
|
134
|
+
duration = _to_int(window.get("duration") or item.get("duration") or detail.get("duration"))
|
|
135
|
+
time_unit = window.get("timeUnit") or item.get("timeUnit") or detail.get("timeUnit") or ""
|
|
136
|
+
if duration:
|
|
137
|
+
if "MINUTE" in time_unit:
|
|
138
|
+
if duration >= 60 and duration % 60 == 0:
|
|
139
|
+
return f"{duration // 60}h limit"
|
|
140
|
+
return f"{duration}m limit"
|
|
141
|
+
if "HOUR" in time_unit:
|
|
142
|
+
return f"{duration}h limit"
|
|
143
|
+
if "DAY" in time_unit:
|
|
144
|
+
return f"{duration}d limit"
|
|
145
|
+
return f"{duration}s limit"
|
|
146
|
+
|
|
147
|
+
return f"Limit #{idx + 1}"
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _reset_hint(data: Mapping[str, Any]) -> str | None:
|
|
151
|
+
for key in ("reset_at", "resetAt", "reset_time", "resetTime"):
|
|
152
|
+
if val := data.get(key):
|
|
153
|
+
return _format_reset_time(str(val))
|
|
154
|
+
|
|
155
|
+
for key in ("reset_in", "resetIn", "ttl", "window"):
|
|
156
|
+
seconds = _to_int(data.get(key))
|
|
157
|
+
if seconds:
|
|
158
|
+
return f"resets in {format_duration(seconds)}"
|
|
159
|
+
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _format_reset_time(val: str) -> str:
|
|
164
|
+
from datetime import UTC, datetime
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
if "." in val and val.endswith("Z"):
|
|
168
|
+
base, frac = val[:-1].split(".")
|
|
169
|
+
frac = frac[:6]
|
|
170
|
+
val = f"{base}.{frac}Z"
|
|
171
|
+
dt = datetime.fromisoformat(val.replace("Z", "+00:00"))
|
|
172
|
+
now = datetime.now(UTC)
|
|
173
|
+
delta = dt - now
|
|
174
|
+
|
|
175
|
+
if delta.total_seconds() <= 0:
|
|
176
|
+
return "reset"
|
|
177
|
+
return f"resets in {format_duration(int(delta.total_seconds()))}"
|
|
178
|
+
except (ValueError, TypeError):
|
|
179
|
+
return f"resets at {val}"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _to_int(value: Any) -> int | None:
|
|
183
|
+
try:
|
|
184
|
+
return int(value)
|
|
185
|
+
except (OverflowError, TypeError, ValueError):
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
to_int = _to_int
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Pythinker AI Open Platform usage adapter (notes-only).
|
|
2
|
+
|
|
3
|
+
Verified 2026-05-06 via context7 (`/websites/platform_minimax_io`,
|
|
4
|
+
`/websites/z_ai`) and tavily web search: there are no public docs and
|
|
5
|
+
no discoverable usage/billing endpoint for `api.pythinker-ai.ai` /
|
|
6
|
+
`api.pythinker-ai.cn`. Earlier drafts of this adapter speculatively
|
|
7
|
+
probed `/user/balance` (the DeepSeek convention) — that was a guess,
|
|
8
|
+
not a verified shape, so it's been removed to avoid surfacing
|
|
9
|
+
misleading errors against an endpoint that doesn't exist.
|
|
10
|
+
|
|
11
|
+
The adapter exists so `/usage` produces a clean panel for Pythinker AI
|
|
12
|
+
sessions and the Phase-5 rate-limit cache can fill in live limits from
|
|
13
|
+
chat-completion response headers.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
from pythinker_code.ui.shell.usage_adapters.base import UsageReport
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from pythinker_code.auth.oauth import OAuthManager
|
|
24
|
+
from pythinker_code.config import LLMProvider
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
PYTHINKER_AI_PLATFORM_ID = "pythinker-ai"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class PythinkerAIAdapter:
|
|
31
|
+
platform_id = PYTHINKER_AI_PLATFORM_ID
|
|
32
|
+
requires_admin_key = False
|
|
33
|
+
provider_label = "Pythinker AI"
|
|
34
|
+
|
|
35
|
+
async def fetch(
|
|
36
|
+
self,
|
|
37
|
+
provider: LLMProvider,
|
|
38
|
+
oauth_mgr: OAuthManager,
|
|
39
|
+
) -> UsageReport:
|
|
40
|
+
return UsageReport(
|
|
41
|
+
provider_label=self.provider_label,
|
|
42
|
+
summary=None,
|
|
43
|
+
limits=[],
|
|
44
|
+
notes=[
|
|
45
|
+
"Pythinker AI doesn't publish a usage endpoint. "
|
|
46
|
+
"Live rate-limit headers will appear here after sending a "
|
|
47
|
+
"chat message."
|
|
48
|
+
],
|
|
49
|
+
unit_hint="quota",
|
|
50
|
+
)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from rich.console import Group, RenderableType
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
from rich.progress_bar import ProgressBar
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
from rich.text import Text
|
|
8
|
+
|
|
9
|
+
from pythinker_code.ui.shell.usage_adapters.base import UsageReport, UsageRow
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def build_panel(report: UsageReport) -> Panel:
|
|
13
|
+
return _build_usage_panel(report.summary, report.limits, notes=report.notes)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _build_usage_panel(
|
|
17
|
+
summary: UsageRow | None,
|
|
18
|
+
limits: list[UsageRow],
|
|
19
|
+
*,
|
|
20
|
+
notes: list[str] | None = None,
|
|
21
|
+
) -> Panel:
|
|
22
|
+
rows = ([summary] if summary else []) + limits
|
|
23
|
+
if not rows and not notes:
|
|
24
|
+
return Panel(
|
|
25
|
+
Text("No usage data", style="grey50"), title="API Usage", border_style="wheat4"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
label_width = max((len(r.label) for r in rows), default=6)
|
|
29
|
+
label_width = max(label_width, 6)
|
|
30
|
+
|
|
31
|
+
lines: list[RenderableType] = []
|
|
32
|
+
for row in rows:
|
|
33
|
+
lines.append(_format_row(row, label_width))
|
|
34
|
+
for note in notes or []:
|
|
35
|
+
lines.append(Text(note, style="yellow"))
|
|
36
|
+
|
|
37
|
+
return Panel(
|
|
38
|
+
Group(*lines),
|
|
39
|
+
title="API Usage",
|
|
40
|
+
border_style="wheat4",
|
|
41
|
+
padding=(0, 2),
|
|
42
|
+
expand=False,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _format_row(row: UsageRow, label_width: int) -> RenderableType:
|
|
47
|
+
if row.limit <= 0 and row.unit is not None:
|
|
48
|
+
return _format_unbounded_row(row, label_width)
|
|
49
|
+
if row.unit == "%":
|
|
50
|
+
return _format_percent_row(row, label_width)
|
|
51
|
+
|
|
52
|
+
remaining, remaining_ratio, bar_total = _remaining_quota(row)
|
|
53
|
+
color = _ratio_color(remaining_ratio)
|
|
54
|
+
|
|
55
|
+
label = Text(f"{row.label:<{label_width}} ", style="cyan")
|
|
56
|
+
bar = ProgressBar(
|
|
57
|
+
total=bar_total,
|
|
58
|
+
completed=remaining,
|
|
59
|
+
width=20,
|
|
60
|
+
complete_style=color,
|
|
61
|
+
finished_style=color,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
detail = Text()
|
|
65
|
+
percent = remaining_ratio * 100
|
|
66
|
+
detail.append(f" {percent:.0f}% left", style="bold")
|
|
67
|
+
if row.reset_hint:
|
|
68
|
+
detail.append(f" ({row.reset_hint})", style="grey50")
|
|
69
|
+
|
|
70
|
+
return _row_table(label_width, label, bar, detail)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _format_percent_row(row: UsageRow, label_width: int) -> RenderableType:
|
|
74
|
+
percent_left = min(max(row.used, 0), 100)
|
|
75
|
+
color = _ratio_color(percent_left / 100)
|
|
76
|
+
label = Text(f"{row.label:<{label_width}} ", style="cyan")
|
|
77
|
+
bar = ProgressBar(
|
|
78
|
+
total=100,
|
|
79
|
+
completed=percent_left,
|
|
80
|
+
width=20,
|
|
81
|
+
complete_style=color,
|
|
82
|
+
finished_style=color,
|
|
83
|
+
)
|
|
84
|
+
detail = Text(f" {_format_value(percent_left, row.unit)} left", style="bold")
|
|
85
|
+
if row.reset_hint:
|
|
86
|
+
detail.append(f" ({row.reset_hint})", style="grey50")
|
|
87
|
+
return _row_table(label_width, label, bar, detail)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _format_unbounded_row(row: UsageRow, label_width: int) -> RenderableType:
|
|
91
|
+
label = Text(f"{row.label:<{label_width}} ", style="cyan")
|
|
92
|
+
detail = Text(f" {_format_value(row.used, row.unit)} used", style="bold")
|
|
93
|
+
if row.reset_hint:
|
|
94
|
+
detail.append(f" ({row.reset_hint})", style="grey50")
|
|
95
|
+
t = Table.grid(padding=0)
|
|
96
|
+
t.add_column(width=label_width + 2)
|
|
97
|
+
t.add_column()
|
|
98
|
+
t.add_row(label, detail)
|
|
99
|
+
return t
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _row_table(
|
|
103
|
+
label_width: int,
|
|
104
|
+
label: Text,
|
|
105
|
+
bar: ProgressBar,
|
|
106
|
+
detail: Text,
|
|
107
|
+
) -> Table:
|
|
108
|
+
t = Table.grid(padding=0)
|
|
109
|
+
t.add_column(width=label_width + 2)
|
|
110
|
+
t.add_column(width=20)
|
|
111
|
+
t.add_column()
|
|
112
|
+
t.add_row(label, bar, detail)
|
|
113
|
+
return t
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _remaining_quota(row: UsageRow) -> tuple[int, float, int]:
|
|
117
|
+
if row.limit <= 0:
|
|
118
|
+
return 0, 0, 1
|
|
119
|
+
|
|
120
|
+
remaining = min(max(row.limit - row.used, 0), row.limit)
|
|
121
|
+
return remaining, remaining / row.limit, row.limit
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _ratio_color(remaining_ratio: float) -> str:
|
|
125
|
+
if remaining_ratio <= 0.1:
|
|
126
|
+
return "red"
|
|
127
|
+
if remaining_ratio <= 0.3:
|
|
128
|
+
return "yellow"
|
|
129
|
+
return "green"
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _format_value(value: int, unit: str | None) -> str:
|
|
133
|
+
if unit is None:
|
|
134
|
+
return _format_count(value)
|
|
135
|
+
if unit == "%":
|
|
136
|
+
return f"{value}%"
|
|
137
|
+
if unit == "USD":
|
|
138
|
+
return f"${value / 100:.2f}"
|
|
139
|
+
if unit == "CNY":
|
|
140
|
+
return f"¥{value / 100:.2f}"
|
|
141
|
+
return f"{_format_count(value)} {unit}"
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _format_count(value: int) -> str:
|
|
145
|
+
return f"{value:,}"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
format_row = _format_row
|
|
149
|
+
remaining_quota = _remaining_quota
|
|
150
|
+
ratio_color = _ratio_color
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Bottom dynamic area rendering package.
|
|
2
|
+
|
|
3
|
+
This package contains all components for the terminal's bottom dynamic area:
|
|
4
|
+
event-driven streaming view, interactive overlays (approval, question, btw),
|
|
5
|
+
input routing, and renderable blocks.
|
|
6
|
+
|
|
7
|
+
All public names are re-exported here so external imports remain stable:
|
|
8
|
+
from pythinker_code.ui.shell.visualize import visualize, _PromptLiveView, ...
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# pyright: reportPrivateUsage=false
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
# Re-export Rich Live for test monkeypatching
|
|
19
|
+
from rich.live import Live as Live # noqa: F401
|
|
20
|
+
|
|
21
|
+
# --- Re-exports (keep all existing import paths working) -------------------
|
|
22
|
+
# Console (re-exported for test monkeypatching compatibility)
|
|
23
|
+
from pythinker_code.ui.shell.console import console as console # noqa: F401
|
|
24
|
+
from pythinker_code.ui.shell.keyboard import KeyEvent as KeyEvent # noqa: F401
|
|
25
|
+
from pythinker_code.ui.shell.prompt import CustomPromptSession, UserInput
|
|
26
|
+
|
|
27
|
+
# Approval panel (moved from ui/shell/approval_panel.py)
|
|
28
|
+
from pythinker_code.ui.shell.visualize._approval_panel import (
|
|
29
|
+
ApprovalPromptDelegate as ApprovalPromptDelegate,
|
|
30
|
+
)
|
|
31
|
+
from pythinker_code.ui.shell.visualize._approval_panel import (
|
|
32
|
+
ApprovalRequestPanel as ApprovalRequestPanel,
|
|
33
|
+
)
|
|
34
|
+
from pythinker_code.ui.shell.visualize._approval_panel import (
|
|
35
|
+
show_approval_in_pager as show_approval_in_pager,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Renderable blocks (+ helper functions used by tests)
|
|
39
|
+
from pythinker_code.ui.shell.visualize._blocks import (
|
|
40
|
+
_ContentBlock as _ContentBlock,
|
|
41
|
+
)
|
|
42
|
+
from pythinker_code.ui.shell.visualize._blocks import (
|
|
43
|
+
_estimate_tokens as _estimate_tokens,
|
|
44
|
+
)
|
|
45
|
+
from pythinker_code.ui.shell.visualize._blocks import (
|
|
46
|
+
_find_committed_boundary as _find_committed_boundary,
|
|
47
|
+
)
|
|
48
|
+
from pythinker_code.ui.shell.visualize._blocks import (
|
|
49
|
+
_NotificationBlock as _NotificationBlock,
|
|
50
|
+
)
|
|
51
|
+
from pythinker_code.ui.shell.visualize._blocks import (
|
|
52
|
+
_StatusBlock as _StatusBlock,
|
|
53
|
+
)
|
|
54
|
+
from pythinker_code.ui.shell.visualize._blocks import (
|
|
55
|
+
_tail_lines as _tail_lines,
|
|
56
|
+
)
|
|
57
|
+
from pythinker_code.ui.shell.visualize._blocks import (
|
|
58
|
+
_ToolCallBlock as _ToolCallBlock,
|
|
59
|
+
)
|
|
60
|
+
from pythinker_code.ui.shell.visualize._blocks import (
|
|
61
|
+
_truncate_to_display_width as _truncate_to_display_width,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# BTW panel
|
|
65
|
+
from pythinker_code.ui.shell.visualize._btw_panel import (
|
|
66
|
+
_BtwModalDelegate as _BtwModalDelegate,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Input routing
|
|
70
|
+
from pythinker_code.ui.shell.visualize._input_router import (
|
|
71
|
+
InputAction as InputAction,
|
|
72
|
+
)
|
|
73
|
+
from pythinker_code.ui.shell.visualize._input_router import (
|
|
74
|
+
classify_input as classify_input,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Interactive view
|
|
78
|
+
from pythinker_code.ui.shell.visualize._interactive import (
|
|
79
|
+
BtwRunner,
|
|
80
|
+
_PromptLiveView,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Base view
|
|
84
|
+
from pythinker_code.ui.shell.visualize._live_view import (
|
|
85
|
+
_keyboard_listener as _keyboard_listener,
|
|
86
|
+
)
|
|
87
|
+
from pythinker_code.ui.shell.visualize._live_view import (
|
|
88
|
+
_LiveView,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Question panel (moved from ui/shell/question_panel.py)
|
|
92
|
+
from pythinker_code.ui.shell.visualize._question_panel import (
|
|
93
|
+
QuestionPromptDelegate as QuestionPromptDelegate,
|
|
94
|
+
)
|
|
95
|
+
from pythinker_code.ui.shell.visualize._question_panel import (
|
|
96
|
+
QuestionRequestPanel as QuestionRequestPanel,
|
|
97
|
+
)
|
|
98
|
+
from pythinker_code.ui.shell.visualize._question_panel import (
|
|
99
|
+
prompt_other_input as prompt_other_input,
|
|
100
|
+
)
|
|
101
|
+
from pythinker_code.ui.shell.visualize._question_panel import (
|
|
102
|
+
show_question_body_in_pager as show_question_body_in_pager,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Wire types and utils (re-exported for test compatibility)
|
|
106
|
+
from pythinker_code.utils.aioqueue import QueueShutDown as QueueShutDown # noqa: F401
|
|
107
|
+
from pythinker_code.wire import WireUISide
|
|
108
|
+
from pythinker_code.wire.types import ContentPart, StatusUpdate
|
|
109
|
+
from pythinker_code.wire.types import TurnEnd as TurnEnd # noqa: F401
|
|
110
|
+
|
|
111
|
+
# --- Factory function ------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
async def visualize(
|
|
115
|
+
wire: WireUISide,
|
|
116
|
+
*,
|
|
117
|
+
initial_status: StatusUpdate,
|
|
118
|
+
cancel_event: asyncio.Event | None = None,
|
|
119
|
+
prompt_session: CustomPromptSession | None = None,
|
|
120
|
+
steer: Callable[[str | list[ContentPart]], None] | None = None,
|
|
121
|
+
btw_runner: BtwRunner | None = None,
|
|
122
|
+
bind_running_input: Callable[[Callable[[UserInput], None], Callable[[], None]], None]
|
|
123
|
+
| None = None,
|
|
124
|
+
unbind_running_input: Callable[[], None] | None = None,
|
|
125
|
+
on_view_ready: Callable[[Any], None] | None = None,
|
|
126
|
+
on_view_closed: Callable[[], None] | None = None,
|
|
127
|
+
show_thinking_stream: bool = False,
|
|
128
|
+
):
|
|
129
|
+
"""A loop to consume agent events and visualize the agent behavior.
|
|
130
|
+
|
|
131
|
+
Creates either a ``_LiveView`` (Rich Live, non-interactive) or a
|
|
132
|
+
``_PromptLiveView`` (prompt_toolkit, interactive) depending on whether
|
|
133
|
+
a prompt session is provided.
|
|
134
|
+
"""
|
|
135
|
+
if prompt_session is not None and steer is not None:
|
|
136
|
+
view = _PromptLiveView(
|
|
137
|
+
initial_status,
|
|
138
|
+
prompt_session=prompt_session,
|
|
139
|
+
steer=steer,
|
|
140
|
+
btw_runner=btw_runner,
|
|
141
|
+
cancel_event=cancel_event,
|
|
142
|
+
show_thinking_stream=show_thinking_stream,
|
|
143
|
+
)
|
|
144
|
+
prompt_session.attach_running_prompt(view)
|
|
145
|
+
|
|
146
|
+
def _cancel_running_input() -> None:
|
|
147
|
+
if cancel_event is not None:
|
|
148
|
+
cancel_event.set()
|
|
149
|
+
|
|
150
|
+
if bind_running_input is not None:
|
|
151
|
+
bind_running_input(view.handle_local_input, _cancel_running_input)
|
|
152
|
+
else:
|
|
153
|
+
view = _LiveView(initial_status, cancel_event, show_thinking_stream=show_thinking_stream)
|
|
154
|
+
if on_view_ready is not None:
|
|
155
|
+
on_view_ready(view)
|
|
156
|
+
try:
|
|
157
|
+
await view.visualize_loop(wire)
|
|
158
|
+
finally:
|
|
159
|
+
if prompt_session is not None and steer is not None:
|
|
160
|
+
if unbind_running_input is not None:
|
|
161
|
+
unbind_running_input()
|
|
162
|
+
if isinstance(view, _PromptLiveView):
|
|
163
|
+
prompt_session.detach_running_prompt(view)
|
|
164
|
+
if on_view_closed is not None:
|
|
165
|
+
on_view_closed()
|