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
|
+
import json
|
|
2
|
+
from typing import cast
|
|
3
|
+
|
|
4
|
+
import streamingjson # type: ignore[reportMissingTypeStubs]
|
|
5
|
+
from pythinker_core.utils.typing import JsonType
|
|
6
|
+
from pythinker_host.path import HostPath
|
|
7
|
+
|
|
8
|
+
from pythinker_code.utils.string import shorten_middle
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SkipThisTool(Exception):
|
|
12
|
+
"""Raised when a tool decides to skip itself from the loading process."""
|
|
13
|
+
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def extract_key_argument(json_content: str | streamingjson.Lexer, tool_name: str) -> str | None:
|
|
18
|
+
if isinstance(json_content, streamingjson.Lexer):
|
|
19
|
+
json_str = json_content.complete_json()
|
|
20
|
+
else:
|
|
21
|
+
json_str = json_content
|
|
22
|
+
try:
|
|
23
|
+
curr_args: JsonType = json.loads(json_str, strict=False)
|
|
24
|
+
except json.JSONDecodeError:
|
|
25
|
+
return None
|
|
26
|
+
if not curr_args:
|
|
27
|
+
return None
|
|
28
|
+
key_argument: str = ""
|
|
29
|
+
match tool_name:
|
|
30
|
+
case "Agent":
|
|
31
|
+
if not isinstance(curr_args, dict) or not curr_args.get("description"):
|
|
32
|
+
return None
|
|
33
|
+
key_argument = str(curr_args["description"])
|
|
34
|
+
case "SendDMail":
|
|
35
|
+
return None
|
|
36
|
+
case "Think":
|
|
37
|
+
if not isinstance(curr_args, dict) or not curr_args.get("thought"):
|
|
38
|
+
return None
|
|
39
|
+
key_argument = str(curr_args["thought"])
|
|
40
|
+
case "SetTodoList":
|
|
41
|
+
return None
|
|
42
|
+
case "Shell":
|
|
43
|
+
if not isinstance(curr_args, dict) or not curr_args.get("command"):
|
|
44
|
+
return None
|
|
45
|
+
key_argument = str(curr_args["command"])
|
|
46
|
+
case "TaskOutput":
|
|
47
|
+
if not isinstance(curr_args, dict) or not curr_args.get("task_id"):
|
|
48
|
+
return None
|
|
49
|
+
key_argument = str(curr_args["task_id"])
|
|
50
|
+
case "TaskList":
|
|
51
|
+
if not isinstance(curr_args, dict):
|
|
52
|
+
return None
|
|
53
|
+
key_argument = "active" if curr_args.get("active_only", True) else "all"
|
|
54
|
+
case "TaskStop":
|
|
55
|
+
if not isinstance(curr_args, dict) or not curr_args.get("task_id"):
|
|
56
|
+
return None
|
|
57
|
+
key_argument = str(curr_args["task_id"])
|
|
58
|
+
case "ReadFile":
|
|
59
|
+
if not isinstance(curr_args, dict) or not curr_args.get("path"):
|
|
60
|
+
return None
|
|
61
|
+
key_argument = _normalize_path(str(curr_args["path"]))
|
|
62
|
+
case "ReadMediaFile":
|
|
63
|
+
if not isinstance(curr_args, dict) or not curr_args.get("path"):
|
|
64
|
+
return None
|
|
65
|
+
key_argument = _normalize_path(str(curr_args["path"]))
|
|
66
|
+
case "Glob":
|
|
67
|
+
if not isinstance(curr_args, dict) or not curr_args.get("pattern"):
|
|
68
|
+
return None
|
|
69
|
+
key_argument = str(curr_args["pattern"])
|
|
70
|
+
case "Grep":
|
|
71
|
+
if not isinstance(curr_args, dict) or not curr_args.get("pattern"):
|
|
72
|
+
return None
|
|
73
|
+
key_argument = str(curr_args["pattern"])
|
|
74
|
+
case "WriteFile":
|
|
75
|
+
if not isinstance(curr_args, dict) or not curr_args.get("path"):
|
|
76
|
+
return None
|
|
77
|
+
key_argument = _normalize_path(str(curr_args["path"]))
|
|
78
|
+
case "StrReplaceFile":
|
|
79
|
+
if not isinstance(curr_args, dict) or not curr_args.get("path"):
|
|
80
|
+
return None
|
|
81
|
+
key_argument = _normalize_path(str(curr_args["path"]))
|
|
82
|
+
case "SearchWeb":
|
|
83
|
+
if not isinstance(curr_args, dict) or not curr_args.get("query"):
|
|
84
|
+
return None
|
|
85
|
+
key_argument = str(curr_args["query"])
|
|
86
|
+
case "FetchURL":
|
|
87
|
+
if not isinstance(curr_args, dict) or not curr_args.get("url"):
|
|
88
|
+
return None
|
|
89
|
+
key_argument = str(curr_args["url"])
|
|
90
|
+
case _:
|
|
91
|
+
if isinstance(json_content, streamingjson.Lexer):
|
|
92
|
+
# lexer.json_content is list[str] based on streamingjson source code
|
|
93
|
+
content: list[str] = cast(list[str], json_content.json_content) # type: ignore[reportUnknownMemberType]
|
|
94
|
+
key_argument = "".join(content)
|
|
95
|
+
else:
|
|
96
|
+
key_argument = json_content
|
|
97
|
+
key_argument = shorten_middle(key_argument, width=50)
|
|
98
|
+
return key_argument
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _normalize_path(path: str) -> str:
|
|
102
|
+
cwd = str(HostPath.cwd().canonical())
|
|
103
|
+
if path.startswith(cwd):
|
|
104
|
+
path = path[len(cwd) :].lstrip("/\\")
|
|
105
|
+
return path
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import asyncio
|
|
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.soul.agent import Runtime
|
|
9
|
+
from pythinker_code.soul.toolset import get_current_tool_call_or_none
|
|
10
|
+
from pythinker_code.subagents.models import AgentLaunchSpec, AgentTypeDefinition
|
|
11
|
+
from pythinker_code.subagents.runner import ForegroundRunRequest, ForegroundSubagentRunner
|
|
12
|
+
from pythinker_code.tools.utils import load_desc
|
|
13
|
+
from pythinker_code.utils.logging import logger
|
|
14
|
+
|
|
15
|
+
NAME = "Agent"
|
|
16
|
+
|
|
17
|
+
MAX_FOREGROUND_TIMEOUT = 60 * 60 # 1 hour
|
|
18
|
+
MAX_BACKGROUND_TIMEOUT = 60 * 60 # 1 hour
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Params(BaseModel):
|
|
22
|
+
description: str = Field(description="A short (3-5 word) description of the task")
|
|
23
|
+
prompt: str = Field(description="The task for the agent to perform")
|
|
24
|
+
subagent_type: str = Field(
|
|
25
|
+
default="coder",
|
|
26
|
+
description="The built-in agent type to use. Defaults to `coder`.",
|
|
27
|
+
)
|
|
28
|
+
model: str | None = Field(
|
|
29
|
+
default=None,
|
|
30
|
+
description=(
|
|
31
|
+
"Optional model override. Selection priority is: this parameter, then the built-in "
|
|
32
|
+
"type default model, then the parent agent's current model."
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
resume: str | None = Field(
|
|
36
|
+
default=None,
|
|
37
|
+
description="Optional agent ID to resume instead of creating a new instance.",
|
|
38
|
+
)
|
|
39
|
+
run_in_background: bool = Field(
|
|
40
|
+
default=False,
|
|
41
|
+
description=(
|
|
42
|
+
"Whether to run the agent in the background. Prefer false unless the task can "
|
|
43
|
+
"continue independently and there is a clear benefit to returning control before "
|
|
44
|
+
"the result is needed."
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
timeout: int | None = Field(
|
|
48
|
+
default=None,
|
|
49
|
+
description=(
|
|
50
|
+
"Timeout in seconds for the agent task. "
|
|
51
|
+
"Foreground: no default timeout (runs until completion), max 3600s (1hr). "
|
|
52
|
+
"Background: default from config (15min), max 3600s (1hr). "
|
|
53
|
+
"The agent is stopped if it exceeds this limit."
|
|
54
|
+
),
|
|
55
|
+
ge=30,
|
|
56
|
+
le=MAX_BACKGROUND_TIMEOUT,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def effective_timeout(self) -> int | None:
|
|
61
|
+
"""Return the user-specified timeout, or None to use the system default."""
|
|
62
|
+
return self.timeout
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class AgentTool(CallableTool2[Params]):
|
|
66
|
+
name: str = NAME
|
|
67
|
+
params: type[Params] = Params
|
|
68
|
+
|
|
69
|
+
def __init__(self, runtime: Runtime):
|
|
70
|
+
super().__init__(
|
|
71
|
+
description=load_desc(
|
|
72
|
+
Path(__file__).parent / "description.md",
|
|
73
|
+
{
|
|
74
|
+
"BUILTIN_AGENT_TYPES_MD": self._builtin_type_lines(runtime),
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
self._runtime = runtime
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def _builtin_type_lines(runtime: Runtime) -> str:
|
|
82
|
+
lines: list[str] = []
|
|
83
|
+
for name, type_def in runtime.labor_market.builtin_types.items():
|
|
84
|
+
tool_names = AgentTool._tool_summary(type_def)
|
|
85
|
+
model = type_def.default_model or "inherit"
|
|
86
|
+
suffix = (
|
|
87
|
+
f" When to use: {AgentTool._normalize_summary(type_def.when_to_use)}"
|
|
88
|
+
if type_def.when_to_use
|
|
89
|
+
else ""
|
|
90
|
+
)
|
|
91
|
+
background = "yes" if type_def.supports_background else "no"
|
|
92
|
+
lines.append(
|
|
93
|
+
f"- `{name}`: {type_def.description} "
|
|
94
|
+
f"(Tools: {tool_names}, Model: {model}, Background: {background}).{suffix}"
|
|
95
|
+
)
|
|
96
|
+
return "\n".join(lines)
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def _normalize_summary(text: str) -> str:
|
|
100
|
+
return " ".join(text.split())
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _tool_summary(type_def: AgentTypeDefinition) -> str:
|
|
104
|
+
if type_def.tool_policy.mode != "allowlist":
|
|
105
|
+
return "*"
|
|
106
|
+
if not type_def.tool_policy.tools:
|
|
107
|
+
return "(none)"
|
|
108
|
+
return ", ".join(AgentTool._unique_tool_names(type_def.tool_policy.tools))
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
def _unique_tool_names(tool_paths: tuple[str, ...]) -> list[str]:
|
|
112
|
+
names: list[str] = []
|
|
113
|
+
for path in tool_paths:
|
|
114
|
+
name = path.split(":")[-1]
|
|
115
|
+
if name not in names:
|
|
116
|
+
names.append(name)
|
|
117
|
+
return names
|
|
118
|
+
|
|
119
|
+
@override
|
|
120
|
+
async def __call__(self, params: Params) -> ToolReturnValue:
|
|
121
|
+
if self._runtime.role != "root":
|
|
122
|
+
return ToolError(
|
|
123
|
+
message="Subagents cannot launch other subagents.",
|
|
124
|
+
brief="Agent unavailable",
|
|
125
|
+
)
|
|
126
|
+
if params.model is not None and params.model not in self._runtime.config.models:
|
|
127
|
+
return ToolError(
|
|
128
|
+
message=f"Unknown model alias: {params.model}",
|
|
129
|
+
brief="Invalid model alias",
|
|
130
|
+
)
|
|
131
|
+
if params.run_in_background:
|
|
132
|
+
return await self._run_in_background(params)
|
|
133
|
+
timeout = params.effective_timeout
|
|
134
|
+
try:
|
|
135
|
+
runner = ForegroundSubagentRunner(self._runtime)
|
|
136
|
+
req = ForegroundRunRequest(
|
|
137
|
+
description=params.description,
|
|
138
|
+
prompt=params.prompt,
|
|
139
|
+
requested_type=params.subagent_type or "coder",
|
|
140
|
+
model=params.model,
|
|
141
|
+
resume=params.resume,
|
|
142
|
+
)
|
|
143
|
+
if timeout is not None:
|
|
144
|
+
return await asyncio.wait_for(runner.run(req), timeout=timeout)
|
|
145
|
+
return await runner.run(req)
|
|
146
|
+
except TimeoutError as exc:
|
|
147
|
+
# Note: TimeoutError from run_soul internals (e.g. aiohttp) is now caught
|
|
148
|
+
# by run_soul_checked and converted to SoulRunFailure. This handler mainly
|
|
149
|
+
# covers wait_for's task-level timeout and pre-run_soul TimeoutErrors.
|
|
150
|
+
if isinstance(exc.__cause__, asyncio.CancelledError):
|
|
151
|
+
logger.warning("Foreground agent timed out after {t}s", t=timeout)
|
|
152
|
+
return ToolError(
|
|
153
|
+
message=f"Agent timed out after {timeout}s.",
|
|
154
|
+
brief=f"Agent timed out ({timeout}s)",
|
|
155
|
+
)
|
|
156
|
+
# Internal timeout (e.g. aiohttp request) — treat as generic failure
|
|
157
|
+
logger.exception("Foreground agent run failed")
|
|
158
|
+
return ToolError(message=f"Failed to run agent: {exc}", brief="Agent failed")
|
|
159
|
+
except Exception as exc:
|
|
160
|
+
logger.exception("Foreground agent run failed")
|
|
161
|
+
return ToolError(message=f"Failed to run agent: {exc}", brief="Agent failed")
|
|
162
|
+
|
|
163
|
+
async def _run_in_background(self, params: Params) -> ToolReturnValue:
|
|
164
|
+
assert self._runtime.subagent_store is not None
|
|
165
|
+
try:
|
|
166
|
+
tool_call = get_current_tool_call_or_none()
|
|
167
|
+
if tool_call is None:
|
|
168
|
+
return ToolError(
|
|
169
|
+
message="Background agent requires a tool call context.",
|
|
170
|
+
brief="No tool call context",
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
requested_type = params.subagent_type or "coder"
|
|
174
|
+
if params.resume:
|
|
175
|
+
record = self._runtime.subagent_store.require_instance(params.resume)
|
|
176
|
+
if record.status in {"running_foreground", "running_background"}:
|
|
177
|
+
return ToolError(
|
|
178
|
+
message=(
|
|
179
|
+
f"Agent instance {record.agent_id} is still {record.status} and cannot "
|
|
180
|
+
"be resumed concurrently."
|
|
181
|
+
),
|
|
182
|
+
brief="Agent already running",
|
|
183
|
+
)
|
|
184
|
+
actual_type = record.subagent_type
|
|
185
|
+
agent_id = record.agent_id
|
|
186
|
+
# Validate the effective model for resumed instances — the model
|
|
187
|
+
# stored in the launch spec may have been removed from config since
|
|
188
|
+
# the instance was created. params.model is already validated in
|
|
189
|
+
# __call__, so only check the stored effective_model fallback here.
|
|
190
|
+
if params.model is None:
|
|
191
|
+
type_def = self._runtime.labor_market.require_builtin_type(actual_type)
|
|
192
|
+
effective = record.launch_spec.effective_model or type_def.default_model
|
|
193
|
+
if effective is not None and effective not in self._runtime.config.models:
|
|
194
|
+
return ToolError(
|
|
195
|
+
message=f"Unknown model alias: {effective}",
|
|
196
|
+
brief="Invalid model alias",
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
actual_type = requested_type
|
|
200
|
+
import uuid
|
|
201
|
+
|
|
202
|
+
agent_id = f"a{uuid.uuid4().hex[:8]}"
|
|
203
|
+
record = None
|
|
204
|
+
|
|
205
|
+
created_instance = False
|
|
206
|
+
if not params.resume:
|
|
207
|
+
type_def = self._runtime.labor_market.require_builtin_type(actual_type)
|
|
208
|
+
self._runtime.subagent_store.create_instance(
|
|
209
|
+
agent_id=agent_id,
|
|
210
|
+
description=params.description.strip(),
|
|
211
|
+
launch_spec=AgentLaunchSpec(
|
|
212
|
+
agent_id=agent_id,
|
|
213
|
+
subagent_type=actual_type,
|
|
214
|
+
model_override=params.model,
|
|
215
|
+
effective_model=params.model or type_def.default_model,
|
|
216
|
+
),
|
|
217
|
+
)
|
|
218
|
+
created_instance = True
|
|
219
|
+
|
|
220
|
+
# Mark running_background synchronously before dispatching the
|
|
221
|
+
# async task so that concurrent resume attempts see the guard
|
|
222
|
+
# immediately (asyncio.create_task only queues the coroutine).
|
|
223
|
+
self._runtime.subagent_store.update_instance(
|
|
224
|
+
agent_id,
|
|
225
|
+
status="running_background",
|
|
226
|
+
)
|
|
227
|
+
try:
|
|
228
|
+
view = self._runtime.background_tasks.create_agent_task(
|
|
229
|
+
agent_id=agent_id,
|
|
230
|
+
subagent_type=actual_type,
|
|
231
|
+
prompt=params.prompt,
|
|
232
|
+
description=params.description.strip(),
|
|
233
|
+
tool_call_id=tool_call.id,
|
|
234
|
+
model_override=params.model,
|
|
235
|
+
timeout_s=params.effective_timeout,
|
|
236
|
+
resumed=params.resume is not None,
|
|
237
|
+
)
|
|
238
|
+
except Exception:
|
|
239
|
+
self._runtime.subagent_store.update_instance(
|
|
240
|
+
agent_id,
|
|
241
|
+
status="idle",
|
|
242
|
+
)
|
|
243
|
+
if created_instance:
|
|
244
|
+
self._runtime.subagent_store.delete_instance(agent_id)
|
|
245
|
+
raise
|
|
246
|
+
lines = [
|
|
247
|
+
f"task_id: {view.spec.id}",
|
|
248
|
+
f"kind: {view.spec.kind}",
|
|
249
|
+
f"status: {view.runtime.status}",
|
|
250
|
+
f"description: {view.spec.description}",
|
|
251
|
+
f"agent_id: {agent_id}",
|
|
252
|
+
f"actual_subagent_type: {actual_type}",
|
|
253
|
+
"automatic_notification: true",
|
|
254
|
+
"next_step: You will be automatically notified when it completes.",
|
|
255
|
+
(
|
|
256
|
+
"next_step: Use TaskOutput with this task_id for a non-blocking status/output "
|
|
257
|
+
"snapshot. Only set block=true when you intentionally want to wait."
|
|
258
|
+
),
|
|
259
|
+
f'resume_hint: Use Agent(resume="{agent_id}", prompt="...") to continue this '
|
|
260
|
+
"instance later.",
|
|
261
|
+
]
|
|
262
|
+
return ToolReturnValue(
|
|
263
|
+
is_error=False,
|
|
264
|
+
output="\n".join(lines),
|
|
265
|
+
message="Background task started.",
|
|
266
|
+
display=[],
|
|
267
|
+
)
|
|
268
|
+
except FileNotFoundError as exc:
|
|
269
|
+
return ToolError(message=str(exc), brief="Agent not found")
|
|
270
|
+
except KeyError as exc:
|
|
271
|
+
return ToolError(message=str(exc), brief="Invalid subagent type")
|
|
272
|
+
except RuntimeError as exc:
|
|
273
|
+
logger.exception("Background agent launch failed")
|
|
274
|
+
return ToolError(message=str(exc), brief="Background start failed")
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
Agent = AgentTool
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Start a subagent instance to work on a focused task.
|
|
2
|
+
|
|
3
|
+
The Agent tool can either create a new subagent instance or resume an existing one by `agent_id`.
|
|
4
|
+
Each instance keeps its own context history under the current session, so repeated use of the same
|
|
5
|
+
instance can preserve previous findings and work.
|
|
6
|
+
|
|
7
|
+
**Available Built-in Agent Types**
|
|
8
|
+
|
|
9
|
+
${BUILTIN_AGENT_TYPES_MD}
|
|
10
|
+
|
|
11
|
+
**Usage**
|
|
12
|
+
|
|
13
|
+
- Always provide a short `description` (3-5 words).
|
|
14
|
+
- Use `subagent_type` to select a built-in agent type. If omitted, `coder` is used.
|
|
15
|
+
- Use `model` when you need to override the built-in type's default model or the parent agent's current model.
|
|
16
|
+
- Use `resume` when you want to continue an existing instance instead of starting a new one.
|
|
17
|
+
- If an existing subagent already has relevant context or the task is a continuation of its prior work, prefer `resume` over creating a new instance.
|
|
18
|
+
- Default to foreground execution. Use `run_in_background=true` only when the task can continue independently, you do not need the result immediately, and there is a clear benefit to returning control before it finishes.
|
|
19
|
+
- Be explicit about whether the subagent should write code or only do research.
|
|
20
|
+
- The subagent result is only visible to you. If the user should see it, summarize it yourself.
|
|
21
|
+
|
|
22
|
+
**Explore Agent — Preferred for Codebase Research**
|
|
23
|
+
|
|
24
|
+
When you need to understand the codebase before making changes, fixing bugs, or planning features,
|
|
25
|
+
prefer `subagent_type="explore"` over doing the search yourself. The explore agent is optimized for
|
|
26
|
+
fast, read-only codebase investigation. Use it when:
|
|
27
|
+
- Your task will clearly require more than 3 search queries
|
|
28
|
+
- You need to understand how a module, feature, or code path works
|
|
29
|
+
- You are about to enter plan mode and want to gather context first
|
|
30
|
+
- You want to investigate multiple independent questions — launch multiple explore agents concurrently
|
|
31
|
+
|
|
32
|
+
When calling explore, specify the desired thoroughness in the prompt:
|
|
33
|
+
- "quick": targeted lookups — find a specific file, function, or config value
|
|
34
|
+
- "medium": understand a module — how does auth work, what calls this API
|
|
35
|
+
- "thorough": cross-cutting analysis — architecture overview, dependency mapping, multi-module investigation
|
|
36
|
+
|
|
37
|
+
**When Not To Use Agent**
|
|
38
|
+
|
|
39
|
+
- Reading a known file path
|
|
40
|
+
- Searching a small number of known files
|
|
41
|
+
- Tasks that can be completed in one or two direct tool calls
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import override
|
|
8
|
+
from uuid import uuid4
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
from pythinker_core.tooling import BriefDisplayBlock, CallableTool2, ToolError, ToolReturnValue
|
|
12
|
+
|
|
13
|
+
from pythinker_code.soul import get_wire_or_none, wire_send
|
|
14
|
+
from pythinker_code.soul.toolset import get_current_tool_call_or_none
|
|
15
|
+
from pythinker_code.tools.utils import load_desc
|
|
16
|
+
from pythinker_code.wire.types import (
|
|
17
|
+
QuestionItem,
|
|
18
|
+
QuestionNotSupported,
|
|
19
|
+
QuestionOption,
|
|
20
|
+
QuestionRequest,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
NAME = "AskUserQuestion"
|
|
26
|
+
|
|
27
|
+
_BASE_DESCRIPTION = load_desc(Path(__file__).parent / "description.md")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class QuestionOptionParam(BaseModel):
|
|
31
|
+
label: str = Field(
|
|
32
|
+
description="Concise display text (1-5 words). If recommended, append '(Recommended)'."
|
|
33
|
+
)
|
|
34
|
+
description: str = Field(
|
|
35
|
+
default="",
|
|
36
|
+
description="Brief explanation of trade-offs or implications of choosing this option.",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class QuestionParam(BaseModel):
|
|
41
|
+
question: str = Field(description="A specific, actionable question. End with '?'.")
|
|
42
|
+
header: str = Field(
|
|
43
|
+
default="", description="Short category tag (max 12 chars, e.g. 'Auth', 'Style')."
|
|
44
|
+
)
|
|
45
|
+
options: list[QuestionOptionParam] = Field(
|
|
46
|
+
description=(
|
|
47
|
+
"2-4 meaningful, distinct options. Do NOT include an 'Other' option — "
|
|
48
|
+
"the system adds one automatically."
|
|
49
|
+
),
|
|
50
|
+
min_length=2,
|
|
51
|
+
max_length=4,
|
|
52
|
+
)
|
|
53
|
+
multi_select: bool = Field(
|
|
54
|
+
default=False,
|
|
55
|
+
description="Whether the user can select multiple options.",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class Params(BaseModel):
|
|
60
|
+
questions: list[QuestionParam] = Field(
|
|
61
|
+
description="The questions to ask the user (1-4 questions).",
|
|
62
|
+
min_length=1,
|
|
63
|
+
max_length=4,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AskUserQuestion(CallableTool2[Params]):
|
|
68
|
+
name: str = NAME
|
|
69
|
+
description: str = _BASE_DESCRIPTION
|
|
70
|
+
params: type[Params] = Params
|
|
71
|
+
|
|
72
|
+
def __init__(self) -> None:
|
|
73
|
+
super().__init__()
|
|
74
|
+
self._is_auto: Callable[[], bool] | None = None
|
|
75
|
+
|
|
76
|
+
def bind_auto(self, is_auto: Callable[[], bool]) -> None:
|
|
77
|
+
"""Late-bind auto-mode checker so we can auto-dismiss when no user is present."""
|
|
78
|
+
self._is_auto = is_auto
|
|
79
|
+
|
|
80
|
+
@override
|
|
81
|
+
async def __call__(self, params: Params) -> ToolReturnValue:
|
|
82
|
+
if self._is_auto and self._is_auto():
|
|
83
|
+
return ToolReturnValue(
|
|
84
|
+
is_error=False,
|
|
85
|
+
output=(
|
|
86
|
+
'{"answers": {}, "note": "Running in auto mode.'
|
|
87
|
+
' No user is present. Make your own decision."}'
|
|
88
|
+
),
|
|
89
|
+
message="Auto mode, auto-dismissed.",
|
|
90
|
+
display=[BriefDisplayBlock(text="Auto-dismissed (auto mode)")],
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
wire = get_wire_or_none()
|
|
94
|
+
if wire is None:
|
|
95
|
+
return ToolError(
|
|
96
|
+
message="Cannot ask user questions: Wire is not available.",
|
|
97
|
+
brief="Wire unavailable",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
tool_call = get_current_tool_call_or_none()
|
|
101
|
+
if tool_call is None:
|
|
102
|
+
return ToolError(
|
|
103
|
+
message="AskUserQuestion must be called from a tool call context.",
|
|
104
|
+
brief="Invalid context",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
questions = [
|
|
108
|
+
QuestionItem(
|
|
109
|
+
question=q.question,
|
|
110
|
+
header=q.header,
|
|
111
|
+
options=[
|
|
112
|
+
QuestionOption(label=o.label, description=o.description) for o in q.options
|
|
113
|
+
],
|
|
114
|
+
multi_select=q.multi_select,
|
|
115
|
+
)
|
|
116
|
+
for q in params.questions
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
request = QuestionRequest(
|
|
120
|
+
id=str(uuid4()),
|
|
121
|
+
tool_call_id=tool_call.id,
|
|
122
|
+
questions=questions,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
wire_send(request)
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
answers = await request.wait()
|
|
129
|
+
except QuestionNotSupported:
|
|
130
|
+
return ToolError(
|
|
131
|
+
message=(
|
|
132
|
+
"The connected client does not support interactive questions. "
|
|
133
|
+
"Do NOT call this tool again. "
|
|
134
|
+
"Ask the user directly in your text response instead."
|
|
135
|
+
),
|
|
136
|
+
brief="Client unsupported",
|
|
137
|
+
)
|
|
138
|
+
except Exception:
|
|
139
|
+
logger.exception("Failed to get user response for question %s", request.id)
|
|
140
|
+
return ToolError(
|
|
141
|
+
message="Failed to get user response.",
|
|
142
|
+
brief="Question failed",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
if not answers:
|
|
146
|
+
return ToolReturnValue(
|
|
147
|
+
is_error=False,
|
|
148
|
+
output='{"answers": {}, "note": "User dismissed the question without answering."}',
|
|
149
|
+
message="User dismissed the question without answering.",
|
|
150
|
+
display=[BriefDisplayBlock(text="User dismissed")],
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
formatted = json.dumps({"answers": answers}, ensure_ascii=False)
|
|
154
|
+
return ToolReturnValue(
|
|
155
|
+
is_error=False,
|
|
156
|
+
output=formatted,
|
|
157
|
+
message="User has answered.",
|
|
158
|
+
display=[BriefDisplayBlock(text="User answered")],
|
|
159
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Use this tool when you need to ask the user questions with structured options during execution. This allows you to:
|
|
2
|
+
1. Collect user preferences or requirements before proceeding
|
|
3
|
+
2. Resolve ambiguous or underspecified instructions
|
|
4
|
+
3. Let the user decide between implementation approaches as you work
|
|
5
|
+
4. Present concrete options when multiple valid directions exist
|
|
6
|
+
|
|
7
|
+
**When NOT to use:**
|
|
8
|
+
- When you can infer the answer from context — be decisive and proceed
|
|
9
|
+
- Trivial decisions that don't materially affect the outcome
|
|
10
|
+
|
|
11
|
+
Overusing this tool interrupts the user's flow. Only use it when the user's input genuinely changes your next action.
|
|
12
|
+
|
|
13
|
+
**Usage notes:**
|
|
14
|
+
- Users always have an "Other" option for custom input — don't create one yourself
|
|
15
|
+
- Use multi_select to allow multiple answers to be selected for a question
|
|
16
|
+
- Keep option labels concise (1-5 words), use descriptions for trade-offs and details
|
|
17
|
+
- Each question should have 2-4 meaningful, distinct options
|
|
18
|
+
- You can ask 1-4 questions at a time; group related questions to minimize interruptions
|
|
19
|
+
- If you recommend a specific option, list it first and append "(Recommended)" to its label
|