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,318 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import override
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
from pythinker_core.tooling import CallableTool2, ToolError, ToolReturnValue
|
|
7
|
+
|
|
8
|
+
from pythinker_code.background import TaskView, format_task, format_task_list, list_task_views
|
|
9
|
+
from pythinker_code.soul.agent import Runtime
|
|
10
|
+
from pythinker_code.soul.approval import Approval
|
|
11
|
+
from pythinker_code.tools.display import BackgroundTaskDisplayBlock
|
|
12
|
+
from pythinker_code.tools.utils import load_desc
|
|
13
|
+
|
|
14
|
+
TASK_OUTPUT_PREVIEW_BYTES = 32 << 10
|
|
15
|
+
TASK_OUTPUT_READ_HINT_LINES = 300
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _ensure_root(runtime: Runtime) -> ToolError | None:
|
|
19
|
+
if runtime.role != "root":
|
|
20
|
+
return ToolError(
|
|
21
|
+
message="Background tasks can only be managed by the root agent.",
|
|
22
|
+
brief="Background task unavailable",
|
|
23
|
+
)
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _task_display(runtime: Runtime, task_id: str) -> BackgroundTaskDisplayBlock:
|
|
28
|
+
view = runtime.background_tasks.store.merged_view(task_id)
|
|
29
|
+
return BackgroundTaskDisplayBlock(
|
|
30
|
+
task_id=view.spec.id,
|
|
31
|
+
kind=view.spec.kind,
|
|
32
|
+
status=view.runtime.status,
|
|
33
|
+
description=view.spec.description,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _format_task_output(
|
|
38
|
+
view: TaskView,
|
|
39
|
+
*,
|
|
40
|
+
retrieval_status: str,
|
|
41
|
+
output: str,
|
|
42
|
+
output_path: Path,
|
|
43
|
+
full_output_available: bool,
|
|
44
|
+
output_size_bytes: int,
|
|
45
|
+
output_preview_bytes: int,
|
|
46
|
+
output_truncated: bool,
|
|
47
|
+
) -> str:
|
|
48
|
+
terminal_reason = "timed_out" if view.runtime.timed_out else view.runtime.status
|
|
49
|
+
output_path_str = str(output_path.resolve())
|
|
50
|
+
lines = [
|
|
51
|
+
f"retrieval_status: {retrieval_status}",
|
|
52
|
+
f"task_id: {view.spec.id}",
|
|
53
|
+
f"kind: {view.spec.kind}",
|
|
54
|
+
f"status: {view.runtime.status}",
|
|
55
|
+
f"description: {view.spec.description}",
|
|
56
|
+
]
|
|
57
|
+
if view.spec.kind == "agent" and view.spec.kind_payload:
|
|
58
|
+
if agent_id := view.spec.kind_payload.get("agent_id"):
|
|
59
|
+
lines.append(f"agent_id: {agent_id}")
|
|
60
|
+
if subagent_type := view.spec.kind_payload.get("subagent_type"):
|
|
61
|
+
lines.append(f"subagent_type: {subagent_type}")
|
|
62
|
+
if view.spec.command:
|
|
63
|
+
lines.append(f"command: {view.spec.command}")
|
|
64
|
+
lines.extend(
|
|
65
|
+
[
|
|
66
|
+
f"interrupted: {str(view.runtime.interrupted).lower()}",
|
|
67
|
+
f"timed_out: {str(view.runtime.timed_out).lower()}",
|
|
68
|
+
f"terminal_reason: {terminal_reason}",
|
|
69
|
+
]
|
|
70
|
+
)
|
|
71
|
+
if view.runtime.exit_code is not None:
|
|
72
|
+
lines.append(f"exit_code: {view.runtime.exit_code}")
|
|
73
|
+
if view.runtime.failure_reason:
|
|
74
|
+
lines.append(f"reason: {view.runtime.failure_reason}")
|
|
75
|
+
full_output_hint = (
|
|
76
|
+
(
|
|
77
|
+
"full_output_hint: "
|
|
78
|
+
f'Use ReadFile(path="{output_path_str}", line_offset=1, '
|
|
79
|
+
f"n_lines={TASK_OUTPUT_READ_HINT_LINES}) to inspect the full log. "
|
|
80
|
+
"Increase line_offset to continue paging through the file."
|
|
81
|
+
)
|
|
82
|
+
if full_output_available
|
|
83
|
+
else "full_output_hint: No output file is currently available for this task."
|
|
84
|
+
)
|
|
85
|
+
lines.extend(
|
|
86
|
+
[
|
|
87
|
+
"",
|
|
88
|
+
f"output_path: {output_path_str}",
|
|
89
|
+
f"output_size_bytes: {output_size_bytes}",
|
|
90
|
+
f"output_preview_bytes: {output_preview_bytes}",
|
|
91
|
+
f"output_truncated: {str(output_truncated).lower()}",
|
|
92
|
+
"",
|
|
93
|
+
f"full_output_available: {str(full_output_available).lower()}",
|
|
94
|
+
"full_output_tool: ReadFile",
|
|
95
|
+
full_output_hint,
|
|
96
|
+
]
|
|
97
|
+
)
|
|
98
|
+
rendered_output = output or "[no output available]"
|
|
99
|
+
if output_truncated:
|
|
100
|
+
rendered_output = f"[Truncated. Full output: {output_path_str}]\n\n{rendered_output}"
|
|
101
|
+
return "\n".join(
|
|
102
|
+
lines
|
|
103
|
+
+ [
|
|
104
|
+
"",
|
|
105
|
+
"[output]",
|
|
106
|
+
rendered_output,
|
|
107
|
+
]
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class TaskOutputParams(BaseModel):
|
|
112
|
+
task_id: str = Field(description="The background task ID to inspect.")
|
|
113
|
+
block: bool = Field(
|
|
114
|
+
default=False,
|
|
115
|
+
description="Whether to wait for the task to finish before returning.",
|
|
116
|
+
)
|
|
117
|
+
timeout: int = Field(
|
|
118
|
+
default=30,
|
|
119
|
+
ge=0,
|
|
120
|
+
le=3600,
|
|
121
|
+
description="Maximum number of seconds to wait when block=true.",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TaskStopParams(BaseModel):
|
|
126
|
+
task_id: str = Field(description="The background task ID to stop.")
|
|
127
|
+
reason: str = Field(
|
|
128
|
+
default="Stopped by TaskStop",
|
|
129
|
+
description="Short reason recorded when the task is stopped.",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class TaskListParams(BaseModel):
|
|
134
|
+
active_only: bool = Field(
|
|
135
|
+
default=True,
|
|
136
|
+
description="Whether to list only non-terminal background tasks.",
|
|
137
|
+
)
|
|
138
|
+
limit: int = Field(
|
|
139
|
+
default=20,
|
|
140
|
+
ge=1,
|
|
141
|
+
le=100,
|
|
142
|
+
description="Maximum number of tasks to return.",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class TaskList(CallableTool2[TaskListParams]):
|
|
147
|
+
name: str = "TaskList"
|
|
148
|
+
description: str = load_desc(Path(__file__).parent / "list.md")
|
|
149
|
+
params: type[TaskListParams] = TaskListParams
|
|
150
|
+
|
|
151
|
+
def __init__(self, runtime: Runtime):
|
|
152
|
+
super().__init__()
|
|
153
|
+
self._runtime = runtime
|
|
154
|
+
|
|
155
|
+
@override
|
|
156
|
+
async def __call__(self, params: TaskListParams) -> ToolReturnValue:
|
|
157
|
+
if err := _ensure_root(self._runtime):
|
|
158
|
+
return err
|
|
159
|
+
|
|
160
|
+
views = list_task_views(
|
|
161
|
+
self._runtime.background_tasks,
|
|
162
|
+
active_only=params.active_only,
|
|
163
|
+
limit=params.limit,
|
|
164
|
+
)
|
|
165
|
+
display = [
|
|
166
|
+
BackgroundTaskDisplayBlock(
|
|
167
|
+
task_id=view.spec.id,
|
|
168
|
+
kind=view.spec.kind,
|
|
169
|
+
status=view.runtime.status,
|
|
170
|
+
description=view.spec.description,
|
|
171
|
+
)
|
|
172
|
+
for view in views
|
|
173
|
+
]
|
|
174
|
+
return ToolReturnValue(
|
|
175
|
+
is_error=False,
|
|
176
|
+
output=format_task_list(views, active_only=params.active_only),
|
|
177
|
+
message="Task list retrieved.",
|
|
178
|
+
display=list(display),
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class TaskOutput(CallableTool2[TaskOutputParams]):
|
|
183
|
+
name: str = "TaskOutput"
|
|
184
|
+
description: str = load_desc(Path(__file__).parent / "output.md")
|
|
185
|
+
params: type[TaskOutputParams] = TaskOutputParams
|
|
186
|
+
|
|
187
|
+
def __init__(self, runtime: Runtime):
|
|
188
|
+
super().__init__()
|
|
189
|
+
self._runtime = runtime
|
|
190
|
+
|
|
191
|
+
def _render_output_preview(self, task_id: str) -> tuple[str, bool, int, int, bool, Path]:
|
|
192
|
+
manager = self._runtime.background_tasks
|
|
193
|
+
output_path = manager.resolve_output_path(task_id)
|
|
194
|
+
try:
|
|
195
|
+
output_size = output_path.stat().st_size if output_path.exists() else 0
|
|
196
|
+
except OSError:
|
|
197
|
+
output_size = 0
|
|
198
|
+
preview_offset = max(0, output_size - TASK_OUTPUT_PREVIEW_BYTES)
|
|
199
|
+
chunk = manager.read_output(
|
|
200
|
+
task_id,
|
|
201
|
+
offset=preview_offset,
|
|
202
|
+
max_bytes=TASK_OUTPUT_PREVIEW_BYTES,
|
|
203
|
+
)
|
|
204
|
+
return (
|
|
205
|
+
chunk.text.rstrip("\n"),
|
|
206
|
+
output_size > 0,
|
|
207
|
+
output_size,
|
|
208
|
+
chunk.next_offset - chunk.offset,
|
|
209
|
+
preview_offset > 0,
|
|
210
|
+
output_path,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
@override
|
|
214
|
+
async def __call__(self, params: TaskOutputParams) -> ToolReturnValue:
|
|
215
|
+
if err := _ensure_root(self._runtime):
|
|
216
|
+
return err
|
|
217
|
+
|
|
218
|
+
view = self._runtime.background_tasks.get_task(params.task_id)
|
|
219
|
+
if view is None:
|
|
220
|
+
return ToolError(message=f"Task not found: {params.task_id}", brief="Task not found")
|
|
221
|
+
|
|
222
|
+
if params.block:
|
|
223
|
+
view = await self._runtime.background_tasks.wait(
|
|
224
|
+
params.task_id,
|
|
225
|
+
timeout_s=params.timeout,
|
|
226
|
+
)
|
|
227
|
+
retrieval_status = (
|
|
228
|
+
"success"
|
|
229
|
+
if view.runtime.status in {"completed", "failed", "killed", "lost"}
|
|
230
|
+
else "timeout"
|
|
231
|
+
)
|
|
232
|
+
else:
|
|
233
|
+
retrieval_status = (
|
|
234
|
+
"success"
|
|
235
|
+
if view.runtime.status in {"completed", "failed", "killed", "lost"}
|
|
236
|
+
else "not_ready"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
(
|
|
240
|
+
output,
|
|
241
|
+
full_output_available,
|
|
242
|
+
output_size,
|
|
243
|
+
output_preview_bytes,
|
|
244
|
+
output_truncated,
|
|
245
|
+
output_path,
|
|
246
|
+
) = self._render_output_preview(params.task_id)
|
|
247
|
+
consumer = view.consumer.model_copy(
|
|
248
|
+
update={
|
|
249
|
+
"last_seen_output_size": output_size,
|
|
250
|
+
"last_viewed_at": time.time(),
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
self._runtime.background_tasks.store.write_consumer(params.task_id, consumer)
|
|
254
|
+
|
|
255
|
+
return ToolReturnValue(
|
|
256
|
+
is_error=False,
|
|
257
|
+
output=_format_task_output(
|
|
258
|
+
view,
|
|
259
|
+
retrieval_status=retrieval_status,
|
|
260
|
+
output=output,
|
|
261
|
+
output_path=output_path,
|
|
262
|
+
full_output_available=full_output_available,
|
|
263
|
+
output_size_bytes=output_size,
|
|
264
|
+
output_preview_bytes=output_preview_bytes,
|
|
265
|
+
output_truncated=output_truncated,
|
|
266
|
+
),
|
|
267
|
+
message=(
|
|
268
|
+
"Task snapshot retrieved."
|
|
269
|
+
if not params.block and retrieval_status == "not_ready"
|
|
270
|
+
else "Task output retrieved."
|
|
271
|
+
),
|
|
272
|
+
display=[_task_display(self._runtime, params.task_id)],
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class TaskStop(CallableTool2[TaskStopParams]):
|
|
277
|
+
name: str = "TaskStop"
|
|
278
|
+
description: str = load_desc(Path(__file__).parent / "stop.md")
|
|
279
|
+
params: type[TaskStopParams] = TaskStopParams
|
|
280
|
+
|
|
281
|
+
def __init__(self, runtime: Runtime, approval: Approval):
|
|
282
|
+
super().__init__()
|
|
283
|
+
self._runtime = runtime
|
|
284
|
+
self._approval = approval
|
|
285
|
+
|
|
286
|
+
@override
|
|
287
|
+
async def __call__(self, params: TaskStopParams) -> ToolReturnValue:
|
|
288
|
+
if err := _ensure_root(self._runtime):
|
|
289
|
+
return err
|
|
290
|
+
if self._runtime.session.state.plan_mode:
|
|
291
|
+
return ToolError(
|
|
292
|
+
message="TaskStop is not available in plan mode.",
|
|
293
|
+
brief="Blocked in plan mode",
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
view = self._runtime.background_tasks.get_task(params.task_id)
|
|
297
|
+
if view is None:
|
|
298
|
+
return ToolError(message=f"Task not found: {params.task_id}", brief="Task not found")
|
|
299
|
+
|
|
300
|
+
result = await self._approval.request(
|
|
301
|
+
self.name,
|
|
302
|
+
"stop background task",
|
|
303
|
+
f"Stop background task `{params.task_id}`",
|
|
304
|
+
display=[_task_display(self._runtime, params.task_id)],
|
|
305
|
+
)
|
|
306
|
+
if not result:
|
|
307
|
+
return result.rejection_error()
|
|
308
|
+
|
|
309
|
+
view = self._runtime.background_tasks.kill(
|
|
310
|
+
params.task_id,
|
|
311
|
+
reason=params.reason.strip() or "Stopped by TaskStop",
|
|
312
|
+
)
|
|
313
|
+
return ToolReturnValue(
|
|
314
|
+
is_error=False,
|
|
315
|
+
output=format_task(view, include_command=True),
|
|
316
|
+
message="Task stop requested.",
|
|
317
|
+
display=[_task_display(self._runtime, params.task_id)],
|
|
318
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
List background tasks from the current session.
|
|
2
|
+
|
|
3
|
+
Use this when you need to re-enumerate which background tasks still exist, especially after context compaction or when you are no longer confident which task IDs are still active.
|
|
4
|
+
|
|
5
|
+
Guidelines:
|
|
6
|
+
|
|
7
|
+
- Prefer the default `active_only=true` unless you specifically need completed or failed tasks.
|
|
8
|
+
- Use `TaskOutput` to inspect one task in detail after you have identified the correct task ID.
|
|
9
|
+
- Do not guess which tasks are still running when you can call this tool directly.
|
|
10
|
+
- This tool is read-only and safe to use in plan mode.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Retrieve output from a running or completed background task.
|
|
2
|
+
|
|
3
|
+
Use this after `Shell(run_in_background=true)` when you need to inspect progress or explicitly wait for completion.
|
|
4
|
+
|
|
5
|
+
Guidelines:
|
|
6
|
+
- Prefer relying on automatic completion notifications. Use this tool only when you need task output before the automatic notification arrives.
|
|
7
|
+
- By default this tool is non-blocking and returns a current status/output snapshot.
|
|
8
|
+
- Use `block=true` only when you intentionally want to wait for completion or timeout.
|
|
9
|
+
- This tool returns structured task metadata, a fixed-size output preview, and an `output_path` for the full log.
|
|
10
|
+
- When the preview is truncated, use `ReadFile` with the returned `output_path` to inspect the full log in pages.
|
|
11
|
+
- This tool works with the generic background task system and should remain the primary read path for future task types, not just bash.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Stop a running background task.
|
|
2
|
+
|
|
3
|
+
Use this only when a background task must be cancelled. For normal task completion, prefer waiting for the automatic notification or using `TaskOutput`.
|
|
4
|
+
|
|
5
|
+
Guidelines:
|
|
6
|
+
- This is a generic task stop capability, not a bash-specific kill tool.
|
|
7
|
+
- Use it sparingly because stopping a task is destructive and may leave partial side effects.
|
|
8
|
+
- If the task is already complete, this tool will simply return its current state.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
from pythinker_core.tooling import DisplayBlock
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DiffDisplayBlock(DisplayBlock):
|
|
8
|
+
"""Display block describing a file diff."""
|
|
9
|
+
|
|
10
|
+
type: str = "diff"
|
|
11
|
+
path: str
|
|
12
|
+
old_text: str
|
|
13
|
+
new_text: str
|
|
14
|
+
old_start: int = 1
|
|
15
|
+
new_start: int = 1
|
|
16
|
+
is_summary: bool = False
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TodoDisplayItem(BaseModel):
|
|
20
|
+
title: str
|
|
21
|
+
status: Literal["pending", "in_progress", "done"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TodoDisplayBlock(DisplayBlock):
|
|
25
|
+
"""Display block describing a todo list update."""
|
|
26
|
+
|
|
27
|
+
type: str = "todo"
|
|
28
|
+
items: list[TodoDisplayItem]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ShellDisplayBlock(DisplayBlock):
|
|
32
|
+
"""Display block describing a shell command."""
|
|
33
|
+
|
|
34
|
+
type: str = "shell"
|
|
35
|
+
language: str
|
|
36
|
+
command: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class BackgroundTaskDisplayBlock(DisplayBlock):
|
|
40
|
+
"""Display block describing a background task."""
|
|
41
|
+
|
|
42
|
+
type: str = "background_task"
|
|
43
|
+
task_id: str
|
|
44
|
+
kind: str
|
|
45
|
+
status: str
|
|
46
|
+
description: str
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import override
|
|
3
|
+
|
|
4
|
+
from pythinker_core.tooling import CallableTool2, ToolError, ToolOk, ToolReturnValue
|
|
5
|
+
|
|
6
|
+
from pythinker_code.soul.denwarenji import DenwaRenji, DenwaRenjiError, DMail
|
|
7
|
+
from pythinker_code.tools.utils import load_desc
|
|
8
|
+
|
|
9
|
+
NAME = "SendDMail"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SendDMail(CallableTool2[DMail]):
|
|
13
|
+
name: str = NAME
|
|
14
|
+
description: str = load_desc(Path(__file__).parent / "dmail.md")
|
|
15
|
+
params: type[DMail] = DMail
|
|
16
|
+
|
|
17
|
+
def __init__(self, denwa_renji: DenwaRenji) -> None:
|
|
18
|
+
super().__init__()
|
|
19
|
+
self._denwa_renji = denwa_renji
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
async def __call__(self, params: DMail) -> ToolReturnValue:
|
|
23
|
+
try:
|
|
24
|
+
self._denwa_renji.send_dmail(params)
|
|
25
|
+
except DenwaRenjiError as e:
|
|
26
|
+
return ToolError(
|
|
27
|
+
output="",
|
|
28
|
+
message=f"Failed to send D-Mail. Error: {str(e)}",
|
|
29
|
+
brief="Failed to send D-Mail",
|
|
30
|
+
)
|
|
31
|
+
return ToolOk(
|
|
32
|
+
output="",
|
|
33
|
+
message=(
|
|
34
|
+
"If you see this message, the D-Mail was NOT sent successfully. "
|
|
35
|
+
"This may be because some other tool that needs approval was rejected."
|
|
36
|
+
),
|
|
37
|
+
brief="El Psy Kongroo",
|
|
38
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Send a message to the past, just like sending a D-Mail in Steins;Gate.
|
|
2
|
+
|
|
3
|
+
This tool is provided to enable you to proactively manage the context. You can see some `user` messages with text `CHECKPOINT {checkpoint_id}` wrapped in `<system>` tags in the context. When you feel there is too much irrelevant information in the current context, you can send a D-Mail to revert the context to a previous checkpoint with a message containing only the useful information. When you send a D-Mail, you must specify an existing checkpoint ID from the before-mentioned messages.
|
|
4
|
+
|
|
5
|
+
Typical scenarios you may want to send a D-Mail:
|
|
6
|
+
|
|
7
|
+
- You read a file, found it very large and most of the content is not relevant to the current task. In this case you can send a D-Mail immediately to the checkpoint before you read the file and give your past self only the useful part.
|
|
8
|
+
- You searched the web, the result is large.
|
|
9
|
+
- If you got what you need, you may send a D-Mail to the checkpoint before you searched the web and put only the useful result in the mail message.
|
|
10
|
+
- If you did not get what you need, you may send a D-Mail to tell your past self to try another query.
|
|
11
|
+
- You wrote some code and it did not work as expected. You spent many struggling steps to fix it but the process is not relevant to the ultimate goal. In this case you can send a D-Mail to the checkpoint before you wrote the code and give your past self the fixed version of the code and tell yourself no need to write it again because you already wrote to the filesystem.
|
|
12
|
+
|
|
13
|
+
After a D-Mail is sent, the system will revert the current context to the specified checkpoint, after which, you will no longer see any messages which you can now see after that checkpoint. The message in the D-Mail will be appended to the end of the context. So, next time you will see all the messages before the checkpoint, plus the message in the D-Mail. You must make it very clear in the message, tell your past self what you have done/changed, what you have learned and any other information that may be useful, so that your past self can continue the task without confusion and will not repeat the steps you have already done.
|
|
14
|
+
|
|
15
|
+
You must understand that, unlike D-Mail in Steins;Gate, the D-Mail you send here will not revert the filesystem or any external state. That means, you are basically folding the recent messages in your context into a single message, which can significantly reduce the waste of context window.
|
|
16
|
+
|
|
17
|
+
When sending a D-Mail, DO NOT explain to the user. The user do not care about this. Just explain to your past self.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class FileOpsWindow:
|
|
5
|
+
"""Maintains a window of file operations."""
|
|
6
|
+
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FileActions(StrEnum):
|
|
11
|
+
READ = "read file"
|
|
12
|
+
EDIT = "edit file"
|
|
13
|
+
EDIT_OUTSIDE = "edit file outside of working directory"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from .glob import Glob # noqa: E402
|
|
17
|
+
from .grep_local import Grep # noqa: E402
|
|
18
|
+
from .read import ReadFile # noqa: E402
|
|
19
|
+
from .read_media import ReadMediaFile # noqa: E402
|
|
20
|
+
from .replace import StrReplaceFile # noqa: E402
|
|
21
|
+
from .write import WriteFile # noqa: E402
|
|
22
|
+
|
|
23
|
+
__all__ = (
|
|
24
|
+
"ReadFile",
|
|
25
|
+
"ReadMediaFile",
|
|
26
|
+
"Glob",
|
|
27
|
+
"Grep",
|
|
28
|
+
"WriteFile",
|
|
29
|
+
"StrReplaceFile",
|
|
30
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Find files and directories using glob patterns. This tool supports standard glob syntax like `*`, `?`, and `**` for recursive searches.
|
|
2
|
+
|
|
3
|
+
**When to use:**
|
|
4
|
+
- Find files matching specific patterns (e.g., all Python files: `*.py`)
|
|
5
|
+
- Search for files recursively in subdirectories (e.g., `src/**/*.js`)
|
|
6
|
+
- Locate configuration files (e.g., `*.config.*`, `*.json`)
|
|
7
|
+
- Find test files (e.g., `test_*.py`, `*_test.go`)
|
|
8
|
+
|
|
9
|
+
**Example patterns:**
|
|
10
|
+
- `*.py` - All Python files in current directory
|
|
11
|
+
- `src/**/*.js` - All JavaScript files in src directory recursively
|
|
12
|
+
- `test_*.py` - Python test files starting with "test_"
|
|
13
|
+
- `*.config.{js,ts}` - Config files with .js or .ts extension
|
|
14
|
+
|
|
15
|
+
**Bad example patterns:**
|
|
16
|
+
- `**`, `**/*.py` - Any pattern starting with '**' will be rejected. Because it would recursively search all directories and subdirectories, which is very likely to yield large result that exceeds your context size. Always use more specific patterns like `src/**/*.py` instead.
|
|
17
|
+
- `node_modules/**/*.js` - Although this does not start with '**', it would still highly possible to yield large result because `node_modules` is well-known to contain too many directories and files. Avoid recursively searching in such directories, other examples include `venv`, `.venv`, `__pycache__`, `target`. If you really need to search in a dependency, use more specific patterns like `node_modules/react/src/*` instead.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Glob tool implementation."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import override
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
from pythinker_core.tooling import CallableTool2, ToolError, ToolOk, ToolReturnValue
|
|
8
|
+
from pythinker_host.path import HostPath
|
|
9
|
+
|
|
10
|
+
from pythinker_code.soul.agent import Runtime
|
|
11
|
+
from pythinker_code.tools.utils import load_desc
|
|
12
|
+
from pythinker_code.utils.logging import logger
|
|
13
|
+
from pythinker_code.utils.path import is_within_directory, is_within_workspace, list_directory
|
|
14
|
+
|
|
15
|
+
MAX_MATCHES = 1000
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Params(BaseModel):
|
|
19
|
+
pattern: str = Field(description=("Glob pattern to match files/directories."))
|
|
20
|
+
directory: str | None = Field(
|
|
21
|
+
description=(
|
|
22
|
+
"Absolute path to the directory to search in (defaults to working directory)."
|
|
23
|
+
),
|
|
24
|
+
default=None,
|
|
25
|
+
)
|
|
26
|
+
include_dirs: bool = Field(
|
|
27
|
+
description="Whether to include directories in results.",
|
|
28
|
+
default=True,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Glob(CallableTool2[Params]):
|
|
33
|
+
name: str = "Glob"
|
|
34
|
+
description: str = load_desc(
|
|
35
|
+
Path(__file__).parent / "glob.md",
|
|
36
|
+
{
|
|
37
|
+
"MAX_MATCHES": str(MAX_MATCHES),
|
|
38
|
+
},
|
|
39
|
+
)
|
|
40
|
+
params: type[Params] = Params
|
|
41
|
+
|
|
42
|
+
def __init__(self, runtime: Runtime) -> None:
|
|
43
|
+
super().__init__()
|
|
44
|
+
self._work_dir = runtime.builtin_args.PYTHINKER_WORK_DIR
|
|
45
|
+
self._additional_dirs = runtime.additional_dirs
|
|
46
|
+
self._skills_dirs = runtime.skills_dirs
|
|
47
|
+
|
|
48
|
+
async def _validate_pattern(self, pattern: str) -> ToolError | None:
|
|
49
|
+
"""Validate that the pattern is safe to use."""
|
|
50
|
+
if pattern.startswith("**"):
|
|
51
|
+
ls_result = await list_directory(self._work_dir)
|
|
52
|
+
return ToolError(
|
|
53
|
+
output=ls_result,
|
|
54
|
+
message=(
|
|
55
|
+
f"Pattern `{pattern}` starts with '**' which is not allowed. "
|
|
56
|
+
"This would recursively search all directories and may include large "
|
|
57
|
+
"directories like `node_modules`. Use more specific patterns instead. "
|
|
58
|
+
"For your convenience, a list of all files and directories in the "
|
|
59
|
+
"top level of the working directory is provided below."
|
|
60
|
+
),
|
|
61
|
+
brief="Unsafe pattern",
|
|
62
|
+
)
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
async def _validate_directory(self, directory: HostPath) -> ToolError | None:
|
|
66
|
+
"""Validate that the directory is safe to search."""
|
|
67
|
+
resolved_dir = directory.canonical()
|
|
68
|
+
|
|
69
|
+
# Allow directories within the workspace (work_dir or additional dirs)
|
|
70
|
+
if is_within_workspace(resolved_dir, self._work_dir, self._additional_dirs):
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
# Allow directories within any discovered skills root
|
|
74
|
+
if any(is_within_directory(resolved_dir, d) for d in self._skills_dirs):
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
return ToolError(
|
|
78
|
+
message=(
|
|
79
|
+
f"`{directory}` is outside the workspace. "
|
|
80
|
+
"You can only search within the working directory, "
|
|
81
|
+
"additional directories, and skills directories."
|
|
82
|
+
),
|
|
83
|
+
brief="Directory outside workspace",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
@override
|
|
87
|
+
async def __call__(self, params: Params) -> ToolReturnValue:
|
|
88
|
+
try:
|
|
89
|
+
# Validate pattern safety
|
|
90
|
+
pattern_error = await self._validate_pattern(params.pattern)
|
|
91
|
+
if pattern_error:
|
|
92
|
+
return pattern_error
|
|
93
|
+
|
|
94
|
+
dir_path = (
|
|
95
|
+
HostPath(params.directory).expanduser() if params.directory else self._work_dir
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if not dir_path.is_absolute():
|
|
99
|
+
return ToolError(
|
|
100
|
+
message=(
|
|
101
|
+
f"`{params.directory}` is not an absolute path. "
|
|
102
|
+
"You must provide an absolute path to search."
|
|
103
|
+
),
|
|
104
|
+
brief="Invalid directory",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Validate directory safety
|
|
108
|
+
dir_error = await self._validate_directory(dir_path)
|
|
109
|
+
if dir_error:
|
|
110
|
+
return dir_error
|
|
111
|
+
|
|
112
|
+
if not await dir_path.exists():
|
|
113
|
+
return ToolError(
|
|
114
|
+
message=f"`{params.directory}` does not exist.",
|
|
115
|
+
brief="Directory not found",
|
|
116
|
+
)
|
|
117
|
+
if not await dir_path.is_dir():
|
|
118
|
+
return ToolError(
|
|
119
|
+
message=f"`{params.directory}` is not a directory.",
|
|
120
|
+
brief="Invalid directory",
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Perform the glob search - users can use ** directly in pattern
|
|
124
|
+
matches: list[HostPath] = []
|
|
125
|
+
async for match in dir_path.glob(params.pattern):
|
|
126
|
+
matches.append(match)
|
|
127
|
+
|
|
128
|
+
# Filter out directories if not requested
|
|
129
|
+
if not params.include_dirs:
|
|
130
|
+
matches = [p for p in matches if await p.is_file()]
|
|
131
|
+
|
|
132
|
+
# Sort for consistent output
|
|
133
|
+
matches.sort()
|
|
134
|
+
|
|
135
|
+
# Limit matches
|
|
136
|
+
message = (
|
|
137
|
+
f"Found {len(matches)} matches for pattern `{params.pattern}`."
|
|
138
|
+
if len(matches) > 0
|
|
139
|
+
else f"No matches found for pattern `{params.pattern}`."
|
|
140
|
+
)
|
|
141
|
+
if len(matches) > MAX_MATCHES:
|
|
142
|
+
matches = matches[:MAX_MATCHES]
|
|
143
|
+
message += (
|
|
144
|
+
f" Only the first {MAX_MATCHES} matches are returned. "
|
|
145
|
+
"You may want to use a more specific pattern."
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
return ToolOk(
|
|
149
|
+
output="\n".join(str(p.relative_to(dir_path)) for p in matches),
|
|
150
|
+
message=message,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.warning(
|
|
155
|
+
"Glob failed: pattern={pattern}: {error}", pattern=params.pattern, error=e
|
|
156
|
+
)
|
|
157
|
+
return ToolError(
|
|
158
|
+
message=f"Failed to search for pattern {params.pattern}. Error: {e}",
|
|
159
|
+
brief="Glob failed",
|
|
160
|
+
)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
A powerful search tool based-on ripgrep.
|
|
2
|
+
|
|
3
|
+
**Tips:**
|
|
4
|
+
- ALWAYS use Grep tool instead of running `grep` or `rg` command with Shell tool.
|
|
5
|
+
- Use the ripgrep pattern syntax, not grep syntax. E.g. you need to escape braces like `\\{` to search for `{`.
|
|
6
|
+
- Hidden files (dotfiles like `.gitlab-ci.yml`, `.eslintrc.json`) are always searched. To also search files excluded by `.gitignore` (e.g. `node_modules`, build outputs), set `include_ignored` to `true`. Sensitive files (such as `.env`) are still skipped for safety, even when `include_ignored` is `true`.
|