agentengine-sdk-python 0.6.4__py3-none-any.whl → 0.7.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.
- agentengine_sdk_python-0.7.0.dist-info/METADATA +181 -0
- agentengine_sdk_python-0.7.0.dist-info/RECORD +482 -0
- {agentengine_sdk_python-0.6.4.dist-info → agentengine_sdk_python-0.7.0.dist-info}/WHEEL +1 -1
- agentengine_sdk_python-0.7.0.dist-info/entry_points.txt +3 -0
- agentengine_sdk_python-0.7.0.dist-info/licenses/LICENSE +175 -0
- agentengine_sdk_python-0.7.0.dist-info/top_level.txt +2 -0
- ksadk/__init__.py +13 -0
- ksadk/__main__.py +4 -0
- ksadk/a2a/__init__.py +15 -0
- ksadk/a2a/card_builder.py +64 -0
- ksadk/a2a/client.py +309 -0
- ksadk/a2a/executor.py +201 -0
- ksadk/a2a/server.py +79 -0
- ksadk/agents/__init__.py +20 -0
- ksadk/agents/base.py +370 -0
- ksadk/agents/context.py +38 -0
- ksadk/agents/event.py +35 -0
- ksadk/agents/loop_agent.py +71 -0
- ksadk/agents/parallel_agent.py +109 -0
- ksadk/agents/runner_adapter.py +24 -0
- ksadk/agents/sequential_agent.py +34 -0
- ksadk/api/__init__.py +3 -0
- ksadk/api/client.py +2246 -0
- ksadk/builders/__init__.py +20 -0
- ksadk/builders/base.py +66 -0
- ksadk/builders/code_builder.py +1990 -0
- ksadk/builders/container_builder.py +786 -0
- ksadk/builders/framework_requirements.py +59 -0
- ksadk/builders/ks3_uploader.py +389 -0
- ksadk/builders/mcp_builder.py +476 -0
- ksadk/builders/requirements_utils.py +75 -0
- ksadk/cli/__init__.py +531 -0
- ksadk/cli/__main__.py +4 -0
- ksadk/cli/agent_ref.py +204 -0
- ksadk/cli/cmd_a2a.py +167 -0
- ksadk/cli/cmd_agent.py +201 -0
- ksadk/cli/cmd_build.py +270 -0
- ksadk/cli/cmd_completion.py +304 -0
- ksadk/cli/cmd_config.py +758 -0
- ksadk/cli/cmd_create.py +2304 -0
- ksadk/cli/cmd_dashboard.py +900 -0
- ksadk/cli/cmd_deploy.py +704 -0
- ksadk/cli/cmd_destroy.py +345 -0
- ksadk/cli/cmd_files.py +1227 -0
- ksadk/cli/cmd_hermes.py +1263 -0
- ksadk/cli/cmd_invoke.py +1503 -0
- ksadk/cli/cmd_launch.py +564 -0
- ksadk/cli/cmd_mcp.py +1179 -0
- ksadk/cli/cmd_model.py +302 -0
- ksadk/cli/cmd_openclaw.py +3922 -0
- ksadk/cli/cmd_run.py +239 -0
- ksadk/cli/cmd_status.py +588 -0
- ksadk/cli/cmd_version.py +522 -0
- ksadk/cli/cmd_web.py +288 -0
- ksadk/cli/deploy_utils.py +87 -0
- ksadk/cli/dry_run.py +214 -0
- ksadk/cli/env_options.py +82 -0
- ksadk/cli/error_utils.py +525 -0
- ksadk/cli/global_options.py +31 -0
- ksadk/cli/local_runtime.py +97 -0
- ksadk/cli/model_catalog.py +136 -0
- ksadk/cli/network_options.py +412 -0
- ksadk/cli/resource_common.py +621 -0
- ksadk/cli/storage.py +84 -0
- ksadk/cli/ui.py +431 -0
- ksadk/cli/workflow_common.py +552 -0
- ksadk/common/__init__.py +14 -0
- ksadk/common/aicp_env.py +128 -0
- ksadk/common/auth.py +190 -0
- ksadk/common/constants.py +84 -0
- ksadk/common/llm_utils.py +61 -0
- ksadk/configs/__init__.py +61 -0
- ksadk/configs/env_registry.py +343 -0
- ksadk/configs/global_config.py +200 -0
- ksadk/configs/settings.py +706 -0
- ksadk/conversations/__init__.py +95 -0
- ksadk/conversations/attachment_storage.py +379 -0
- ksadk/conversations/attachments.py +774 -0
- ksadk/conversations/compaction_pipeline.py +387 -0
- ksadk/conversations/compaction_prompt.py +128 -0
- ksadk/conversations/context.py +303 -0
- ksadk/conversations/message_projection.py +269 -0
- ksadk/conversations/model_context.py +370 -0
- ksadk/conversations/model_options.py +136 -0
- ksadk/conversations/normalize.py +446 -0
- ksadk/conversations/reasoning_markup.py +91 -0
- ksadk/conversations/run_kinds.py +61 -0
- ksadk/conversations/run_status.py +53 -0
- ksadk/conversations/runtime.py +5276 -0
- ksadk/conversations/semantic_summary.py +359 -0
- ksadk/conversations/session_title.py +254 -0
- ksadk/deployment/__init__.py +83 -0
- ksadk/deployment/agent_access.py +226 -0
- ksadk/deployment/base.py +229 -0
- ksadk/deployment/manager.py +332 -0
- ksadk/deployment/providers/__init__.py +10 -0
- ksadk/deployment/providers/serverless.py +1115 -0
- ksadk/deployment/registry.py +120 -0
- ksadk/deployment/state.py +78 -0
- ksadk/deployment/ui_config.py +21 -0
- ksadk/detection/__init__.py +7 -0
- ksadk/detection/detector.py +431 -0
- ksadk/detection/mcp_detector.py +250 -0
- ksadk/hermes_terminal.py +467 -0
- ksadk/identity/__init__.py +17 -0
- ksadk/identity/resolver.py +385 -0
- ksadk/knowledge_base/__init__.py +62 -0
- ksadk/knowledge_base/adk_tool.py +47 -0
- ksadk/knowledge_base/client.py +297 -0
- ksadk/knowledge_base/langchain_tool.py +55 -0
- ksadk/knowledge_base/service.py +66 -0
- ksadk/knowledge_base/tool.py +50 -0
- ksadk/markdown.py +169 -0
- ksadk/mcp_runtime/__init__.py +231 -0
- ksadk/memory/__init__.py +57 -0
- ksadk/memory/adk/__init__.py +51 -0
- ksadk/memory/adk/backends/__init__.py +5 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +52 -0
- ksadk/memory/adk/backends/http_ltm_backend.py +183 -0
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +96 -0
- ksadk/memory/adk/backends/sdk_ltm_backend.py +456 -0
- ksadk/memory/adk/long_term_memory.py +273 -0
- ksadk/memory/adk/resilient_session_service.py +268 -0
- ksadk/memory/adk/short_term_memory.py +304 -0
- ksadk/memory/adk_tool.py +31 -0
- ksadk/memory/backends/__init__.py +6 -0
- ksadk/memory/backends/base.py +103 -0
- ksadk/memory/backends/memory.py +112 -0
- ksadk/memory/backends/redis.py +146 -0
- ksadk/memory/langchain_tool.py +39 -0
- ksadk/memory/ltm_backend_factory.py +24 -0
- ksadk/memory/manager.py +215 -0
- ksadk/memory/service.py +172 -0
- ksadk/memory/tool.py +96 -0
- ksadk/model_policy.py +223 -0
- ksadk/openclaw_gateway.py +378 -0
- ksadk/runners/__init__.py +8 -0
- ksadk/runners/adk_runner.py +1994 -0
- ksadk/runners/base_runner.py +305 -0
- ksadk/runners/deepagents_runner.py +13 -0
- ksadk/runners/factory.py +73 -0
- ksadk/runners/langchain_runner.py +751 -0
- ksadk/runners/langgraph_runner.py +985 -0
- ksadk/runners/patch_langchain.py +187 -0
- ksadk/runners/remote_runner.py +792 -0
- ksadk/runners/usage_accumulator.py +38 -0
- ksadk/runners/utils/__init__.py +19 -0
- ksadk/runners/utils/langfuse.py +230 -0
- ksadk/runners/utils/loader.py +62 -0
- ksadk/runtime_context.py +166 -0
- ksadk/runtime_state.py +25 -0
- ksadk/sandbox/__init__.py +28 -0
- ksadk/sandbox/backends/__init__.py +9 -0
- ksadk/sandbox/backends/e2b.py +154 -0
- ksadk/sandbox/backends/local_process.py +131 -0
- ksadk/sandbox/base.py +101 -0
- ksadk/sandbox/factory.py +53 -0
- ksadk/sandbox/registry.py +187 -0
- ksadk/server/__init__.py +7 -0
- ksadk/server/api_models.py +73 -0
- ksadk/server/app.py +3931 -0
- ksadk/server/static/assets/ArtifactsPanel-D-SSn2ee.js +1 -0
- ksadk/server/static/assets/CodeBlock-P16VOLYi.js +9 -0
- ksadk/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- ksadk/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- ksadk/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- ksadk/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- ksadk/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +8 -0
- ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +1 -0
- ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +303 -0
- ksadk/server/static/assets/NativeTerminalPanel-CHOd7Rch.css +1 -0
- ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +1 -0
- ksadk/server/static/assets/addon-fit-DthTIhi3.js +1 -0
- ksadk/server/static/assets/apl-CnwPGSsG.js +1 -0
- ksadk/server/static/assets/arc-BA13sHc9.js +1 -0
- ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +1 -0
- ksadk/server/static/assets/architectureDiagram-3BPJPVTR-DzJzgVoL.js +36 -0
- ksadk/server/static/assets/asciiarmor-qTkVPQu6.js +1 -0
- ksadk/server/static/assets/asn1-Dr8qZg38.js +1 -0
- ksadk/server/static/assets/asterisk-Bja0s6e1.js +1 -0
- ksadk/server/static/assets/blockDiagram-GPEHLZMM-UTdVcZhn.js +132 -0
- ksadk/server/static/assets/brainfuck-D5EjA2JK.js +1 -0
- ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dix0GD4m.js +10 -0
- ksadk/server/static/assets/channel-CTuydARX.js +1 -0
- ksadk/server/static/assets/chunk-2J33WTMH-C2JxuZ42.js +1 -0
- ksadk/server/static/assets/chunk-4BX2VUAB-Be57QPgD.js +1 -0
- ksadk/server/static/assets/chunk-55IACEB6-WjSuy4nv.js +1 -0
- ksadk/server/static/assets/chunk-727SXJPM-BOovP-b5.js +206 -0
- ksadk/server/static/assets/chunk-AQP2D5EJ-DOmZNmWj.js +231 -0
- ksadk/server/static/assets/chunk-FMBD7UC4-DzwlodkU.js +15 -0
- ksadk/server/static/assets/chunk-ND2GUHAM-DMqAikEU.js +1 -0
- ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +1 -0
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +1 -0
- ksadk/server/static/assets/clike-DHH8Ad3s.js +1 -0
- ksadk/server/static/assets/clojure-BflJGmDX.js +1 -0
- ksadk/server/static/assets/cmake-CyVbuzPu.js +1 -0
- ksadk/server/static/assets/cobol-B_OZ4V-R.js +1 -0
- ksadk/server/static/assets/coffeescript-B2pKbFk8.js +1 -0
- ksadk/server/static/assets/commonlisp-CcllspGY.js +1 -0
- ksadk/server/static/assets/cose-bilkent-S5V4N54A-Zhy2GBnP.js +1 -0
- ksadk/server/static/assets/crystal-M5-qzICs.js +1 -0
- ksadk/server/static/assets/css-CYpP4FRV.js +1 -0
- ksadk/server/static/assets/cypher-p9eYesGn.js +1 -0
- ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +321 -0
- ksadk/server/static/assets/d-BhMjBjQP.js +1 -0
- ksadk/server/static/assets/dagre-BM42HDAG-CbKrtIUz.js +4 -0
- ksadk/server/static/assets/dagre-Bx709z4p.js +1 -0
- ksadk/server/static/assets/defaultLocale-C8Fc0cco.js +1 -0
- ksadk/server/static/assets/diagram-2AECGRRQ-BRApgQRK.js +43 -0
- ksadk/server/static/assets/diagram-5GNKFQAL-D0xbnDiK.js +10 -0
- ksadk/server/static/assets/diagram-KO2AKTUF-CVugVI9L.js +3 -0
- ksadk/server/static/assets/diagram-LMA3HP47-DozUGgee.js +24 -0
- ksadk/server/static/assets/diagram-OG6HWLK6-ZOYsKlru.js +24 -0
- ksadk/server/static/assets/diff-ChtP43wD.js +1 -0
- ksadk/server/static/assets/dist-2hInLS_J.js +9 -0
- ksadk/server/static/assets/dist-8EEyGgDx.js +1 -0
- ksadk/server/static/assets/dist-8_SfK1IP.js +1 -0
- ksadk/server/static/assets/dist-B0NP_Z0z.js +23 -0
- ksadk/server/static/assets/dist-BIJVDMuB.js +1 -0
- ksadk/server/static/assets/dist-BmlMPsCc.js +2 -0
- ksadk/server/static/assets/dist-BrCcQ47T.js +1 -0
- ksadk/server/static/assets/dist-BssVmjIo.js +6 -0
- ksadk/server/static/assets/dist-C3HIIaN5.js +1 -0
- ksadk/server/static/assets/dist-CPBtqRTW.js +1 -0
- ksadk/server/static/assets/dist-CkEKJFtk.js +1 -0
- ksadk/server/static/assets/dist-D-JMdWPQ.js +1 -0
- ksadk/server/static/assets/dist-D-xOD048.js +1 -0
- ksadk/server/static/assets/dist-D57wnGWd.js +1 -0
- ksadk/server/static/assets/dist-DL_NKc_z.js +1 -0
- ksadk/server/static/assets/dist-DMezvBGJ.js +1 -0
- ksadk/server/static/assets/dist-DmFaq_Iy.js +1 -0
- ksadk/server/static/assets/dist-Dp0k7bWI.js +1 -0
- ksadk/server/static/assets/dist-DpKtt4Bo.js +1 -0
- ksadk/server/static/assets/dist-DyOkZmze.js +11 -0
- ksadk/server/static/assets/dist-DyWsb78Q.js +1 -0
- ksadk/server/static/assets/dist-gX6GOLKq.js +1 -0
- ksadk/server/static/assets/dockerfile-BLkNEvjs.js +1 -0
- ksadk/server/static/assets/dtd-DTF72YNO.js +1 -0
- ksadk/server/static/assets/dylan-C6jEEEk-.js +1 -0
- ksadk/server/static/assets/ebnf-D4c0_ac3.js +1 -0
- ksadk/server/static/assets/ecl-BSZaIHnp.js +1 -0
- ksadk/server/static/assets/eiffel-BEjRio4Q.js +1 -0
- ksadk/server/static/assets/elm-Cshzl8qu.js +1 -0
- ksadk/server/static/assets/erDiagram-TEJ5UH35-Bk-9bgE5.js +85 -0
- ksadk/server/static/assets/erlang-DaB2Rkuy.js +1 -0
- ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +1 -0
- ksadk/server/static/assets/factor-D7LVTn2l.js +1 -0
- ksadk/server/static/assets/fcl-ClOhbFR7.js +1 -0
- ksadk/server/static/assets/flowDiagram-I6XJVG4X-Dn9kZVuZ.js +162 -0
- ksadk/server/static/assets/forth-Cezjo90N.js +1 -0
- ksadk/server/static/assets/fortran-Bt6PBEDR.js +1 -0
- ksadk/server/static/assets/ganttDiagram-6RSMTGT7-BGxXlJqm.js +292 -0
- ksadk/server/static/assets/gas-BHEdbvp9.js +1 -0
- ksadk/server/static/assets/gherkin-oBAE_ms0.js +1 -0
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +1 -0
- ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-C7Q0X-wi.js +106 -0
- ksadk/server/static/assets/graphlib-B8gBHxth.js +1 -0
- ksadk/server/static/assets/groovy-BC3IOsC8.js +1 -0
- ksadk/server/static/assets/haskell-BRsoo5mP.js +1 -0
- ksadk/server/static/assets/haxe-DIz0ZZqd.js +1 -0
- ksadk/server/static/assets/http-CLVgA2GD.js +1 -0
- ksadk/server/static/assets/idl-BUZw3wgd.js +1 -0
- ksadk/server/static/assets/index-C00Lwg3L.js +165 -0
- ksadk/server/static/assets/index-DAURbCsP.css +1 -0
- ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +1 -0
- ksadk/server/static/assets/infoDiagram-5YYISTIA-BO_CSqq5.js +2 -0
- ksadk/server/static/assets/init-D6jRqBbL.js +1 -0
- ksadk/server/static/assets/ishikawaDiagram-YF4QCWOH-eYLPLd46.js +70 -0
- ksadk/server/static/assets/javascript-9Tg8ixDm.js +1 -0
- ksadk/server/static/assets/journeyDiagram-JHISSGLW-De9geSb0.js +139 -0
- ksadk/server/static/assets/julia-CQfgDRfP.js +1 -0
- ksadk/server/static/assets/kanban-definition-UN3LZRKU-Cs80kQto.js +89 -0
- ksadk/server/static/assets/katex-DSrCFD8n.js +265 -0
- ksadk/server/static/assets/linear-CN9sbKTF.js +1 -0
- ksadk/server/static/assets/livescript-BXxG0Yva.js +1 -0
- ksadk/server/static/assets/lua-CiA1ziua.js +1 -0
- ksadk/server/static/assets/mathematica-u8YMmbU0.js +1 -0
- ksadk/server/static/assets/mbox-BEMVcqjs.js +1 -0
- ksadk/server/static/assets/mermaid-parser.core-DlgSBU8l.js +161 -0
- ksadk/server/static/assets/mindmap-definition-RKZ34NQL-9afz7Oug.js +96 -0
- ksadk/server/static/assets/mirc-C9zpzAZU.js +1 -0
- ksadk/server/static/assets/mllike-B45xgp2S.js +1 -0
- ksadk/server/static/assets/modelica-CqHI_q-D.js +1 -0
- ksadk/server/static/assets/mscgen-qgSLujhx.js +1 -0
- ksadk/server/static/assets/mumps-CW_TBmxz.js +1 -0
- ksadk/server/static/assets/nginx-BMaDbqW3.js +1 -0
- ksadk/server/static/assets/nsis-AQ_alPln.js +1 -0
- ksadk/server/static/assets/ntriples-d28e9m0E.js +1 -0
- ksadk/server/static/assets/octave-D2Q8cUp1.js +1 -0
- ksadk/server/static/assets/ordinal-hYBb2elL.js +1 -0
- ksadk/server/static/assets/oz-BwTct_5T.js +1 -0
- ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +1 -0
- ksadk/server/static/assets/pascal-Dp_KdFgX.js +1 -0
- ksadk/server/static/assets/perl-CdEHsPfU.js +1 -0
- ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +1 -0
- ksadk/server/static/assets/pieDiagram-4H26LBE5-DPv_VstN.js +30 -0
- ksadk/server/static/assets/pig-AF4Hwhju.js +1 -0
- ksadk/server/static/assets/powershell-CzG71I4L.js +1 -0
- ksadk/server/static/assets/properties-C357ku5U.js +1 -0
- ksadk/server/static/assets/protobuf-D1ij_kNL.js +1 -0
- ksadk/server/static/assets/pug-Bugr-47h.js +1 -0
- ksadk/server/static/assets/puppet-B4hC2X4m.js +1 -0
- ksadk/server/static/assets/python-BqYw9LYJ.js +1 -0
- ksadk/server/static/assets/q-B9NhS7L_.js +1 -0
- ksadk/server/static/assets/quadrantDiagram-W4KKPZXB-o77wZ1XK.js +7 -0
- ksadk/server/static/assets/r-DADKenSm.js +1 -0
- ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +1 -0
- ksadk/server/static/assets/requirementDiagram-4Y6WPE33-BYVw81VC.js +84 -0
- ksadk/server/static/assets/rpm-gpDK5sbt.js +1 -0
- ksadk/server/static/assets/ruby-DsYpTuWg.js +1 -0
- ksadk/server/static/assets/sankeyDiagram-5OEKKPKP-B7nZFMKT.js +40 -0
- ksadk/server/static/assets/sas-C2OyD2Y6.js +1 -0
- ksadk/server/static/assets/scheme-CyDdOh7e.js +1 -0
- ksadk/server/static/assets/sequenceDiagram-3UESZ5HK-BGRRrFw5.js +162 -0
- ksadk/server/static/assets/shell-Du5Qg9im.js +1 -0
- ksadk/server/static/assets/sieve-BAxa3IjF.js +1 -0
- ksadk/server/static/assets/simple-mode-DRpGK0lJ.js +1 -0
- ksadk/server/static/assets/smalltalk-BLp5-jwC.js +1 -0
- ksadk/server/static/assets/solr-BBopId9w.js +1 -0
- ksadk/server/static/assets/sparql-Dz-mlCAC.js +1 -0
- ksadk/server/static/assets/spreadsheet-CTIncYxj.js +1 -0
- ksadk/server/static/assets/sql-DcCJ9jop.js +1 -0
- ksadk/server/static/assets/stateDiagram-AJRCARHV-BUfHCoPs.js +1 -0
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +1 -0
- ksadk/server/static/assets/stex-sDrdk2BW.js +1 -0
- ksadk/server/static/assets/stylus-DLLZ8dgm.js +1 -0
- ksadk/server/static/assets/swift-DKB6_1j6.js +1 -0
- ksadk/server/static/assets/tcl-BGfruO1u.js +1 -0
- ksadk/server/static/assets/textile-DWBqthVk.js +1 -0
- ksadk/server/static/assets/tiddlywiki-VlUiK86J.js +1 -0
- ksadk/server/static/assets/tiki-CxVlf5KZ.js +1 -0
- ksadk/server/static/assets/timeline-definition-PNZ67QCA-FbCTGrf9.js +120 -0
- ksadk/server/static/assets/toml-LvoKBwCs.js +1 -0
- ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +1 -0
- ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +1 -0
- ksadk/server/static/assets/troff-C2dAgh7P.js +1 -0
- ksadk/server/static/assets/ttcn-BePYh-hG.js +1 -0
- ksadk/server/static/assets/ttcn-cfg-CY0aot7Q.js +1 -0
- ksadk/server/static/assets/turtle-BDLWE2cD.js +1 -0
- ksadk/server/static/assets/vb-BthdM_4N.js +1 -0
- ksadk/server/static/assets/vbscript-D9f6rSsU.js +1 -0
- ksadk/server/static/assets/velocity-CqftRsjg.js +1 -0
- ksadk/server/static/assets/vennDiagram-CIIHVFJN-DWgwtPsJ.js +34 -0
- ksadk/server/static/assets/verilog-D-x6ne0Z.js +1 -0
- ksadk/server/static/assets/vhdl-CMrOq2q1.js +1 -0
- ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +1 -0
- ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-2x8G-tTM.js +78 -0
- ksadk/server/static/assets/webidl-D5jiJvOU.js +1 -0
- ksadk/server/static/assets/xquery-fj_R-kMw.js +1 -0
- ksadk/server/static/assets/xterm-DooSxjI5.js +36 -0
- ksadk/server/static/assets/xychartDiagram-2RQKCTM6-Drma3AYl.js +7 -0
- ksadk/server/static/assets/yacas-CXXgtw0p.js +1 -0
- ksadk/server/static/assets/z80-CL1naaMV.js +1 -0
- ksadk/server/static/favicon.svg +1 -0
- ksadk/server/static/icons.svg +24 -0
- ksadk/server/static/index.html +14 -0
- ksadk/server/terminal_sessions.py +551 -0
- ksadk/sessions/__init__.py +279 -0
- ksadk/sessions/base.py +354 -0
- ksadk/sessions/continuity.py +337 -0
- ksadk/sessions/errors.py +7 -0
- ksadk/sessions/in_memory.py +273 -0
- ksadk/sessions/local_service.py +949 -0
- ksadk/sessions/postgres_service.py +901 -0
- ksadk/sessions/resilience.py +52 -0
- ksadk/sessions/resilient.py +360 -0
- ksadk/sessions/sqlite_service.py +13 -0
- ksadk/skills/__init__.py +9 -0
- ksadk/skills/loader.py +46 -0
- ksadk/skills/models.py +120 -0
- ksadk/skills/package_store.py +104 -0
- ksadk/skills/runtime/__init__.py +17 -0
- ksadk/skills/runtime/agent.py +183 -0
- ksadk/skills/runtime/artifacts.py +39 -0
- ksadk/skills/runtime/backends/__init__.py +1 -0
- ksadk/skills/runtime/backends/disabled.py +8 -0
- ksadk/skills/runtime/backends/e2b.py +168 -0
- ksadk/skills/runtime/backends/local.py +95 -0
- ksadk/skills/runtime/base.py +103 -0
- ksadk/skills/runtime/executor.py +219 -0
- ksadk/skills/runtime/factory.py +37 -0
- ksadk/skills/runtime/loader.py +131 -0
- ksadk/skills/runtime/registry.py +150 -0
- ksadk/skills/runtime/request.py +67 -0
- ksadk/skills/service_client.py +239 -0
- ksadk/skills/service_env.py +58 -0
- ksadk/skills/tool_defs.py +221 -0
- ksadk/terminal_client.py +69 -0
- ksadk/terminal_exec_policy.py +229 -0
- ksadk/tools/__init__.py +17 -0
- ksadk/tools/gateway.py +230 -0
- ksadk/tools/result_budget.py +154 -0
- ksadk/toolsets/__init__.py +854 -0
- ksadk/toolsets/_langchain.py +11 -0
- ksadk/toolsets/platform.py +93 -0
- ksadk/toolsets/sandbox.py +310 -0
- ksadk/toolsets/skills.py +217 -0
- ksadk/toolsets/web.py +266 -0
- ksadk/toolsets/workspace.py +917 -0
- ksadk/toolsets/workspace_state.py +44 -0
- ksadk/tracing/__init__.py +37 -0
- ksadk/tracing/exporters/__init__.py +1 -0
- ksadk/tracing/exporters/inmemory_exporter.py +116 -0
- ksadk/tracing/exporters/langfuse_exporter.py +445 -0
- ksadk/tracing/setup.py +892 -0
- ksadk/tracing/span_utils.py +114 -0
- ksadk/tui/__init__.py +27 -0
- ksadk/tui/loop.py +1877 -0
- ksadk/tui/stream_render.py +68 -0
- ksadk/ui_config.py +168 -0
- ksadk/version.py +4 -0
- ksadk_runtime_common/__init__.py +20 -0
- ksadk_runtime_common/memory_backend/__init__.py +29 -0
- ksadk_runtime_common/memory_backend/manifest.py +79 -0
- ksadk_runtime_common/memory_backend/providers/__init__.py +6 -0
- ksadk_runtime_common/memory_backend/providers/lancedb.py +151 -0
- ksadk_runtime_common/memory_backend/providers/mem0.py +74 -0
- ksadk_runtime_common/memory_backend/registry.py +56 -0
- ksadk_runtime_common/memory_backend/render.py +71 -0
- ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -0
- ksadk_runtime_common/workspace_files/__init__.py +29 -0
- ksadk_runtime_common/workspace_files/bootstrap.py +56 -0
- ksadk_runtime_common/workspace_files/constants.py +9 -0
- ksadk_runtime_common/workspace_files/path_utils.py +71 -0
- ksadk_runtime_common/workspace_files/preview.py +96 -0
- ksadk_runtime_common/workspace_files/router.py +254 -0
- agentengine_sdk_python/__init__.py +0 -3
- agentengine_sdk_python-0.6.4.dist-info/METADATA +0 -48
- agentengine_sdk_python-0.6.4.dist-info/RECORD +0 -5
- agentengine_sdk_python-0.6.4.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import time
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ksadk.sandbox.base import (
|
|
8
|
+
SandboxCommandResult,
|
|
9
|
+
SandboxError,
|
|
10
|
+
SandboxInputFile,
|
|
11
|
+
SandboxSession,
|
|
12
|
+
SandboxSpec,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
_TRANSIENT_STARTUP_ERROR_NAMES = {
|
|
16
|
+
"NotFoundException",
|
|
17
|
+
"FileNotFoundException",
|
|
18
|
+
"SandboxNotFoundException",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _startup_retry_attempts() -> int:
|
|
23
|
+
raw = os.environ.get("KSADK_SANDBOX_STARTUP_RETRY_ATTEMPTS", "6")
|
|
24
|
+
try:
|
|
25
|
+
return max(1, int(raw))
|
|
26
|
+
except ValueError:
|
|
27
|
+
return 6
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _startup_retry_delay() -> float:
|
|
31
|
+
raw = os.environ.get("KSADK_SANDBOX_STARTUP_RETRY_DELAY", "0.2")
|
|
32
|
+
try:
|
|
33
|
+
return max(0.0, float(raw))
|
|
34
|
+
except ValueError:
|
|
35
|
+
return 0.2
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _is_transient_startup_error(exc: Exception) -> bool:
|
|
39
|
+
return type(exc).__name__ in _TRANSIENT_STARTUP_ERROR_NAMES
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _with_startup_retry(operation):
|
|
43
|
+
attempts = _startup_retry_attempts()
|
|
44
|
+
delay = _startup_retry_delay()
|
|
45
|
+
last_exc: Exception | None = None
|
|
46
|
+
for attempt in range(attempts):
|
|
47
|
+
try:
|
|
48
|
+
return operation()
|
|
49
|
+
except Exception as exc:
|
|
50
|
+
if not _is_transient_startup_error(exc) or attempt >= attempts - 1:
|
|
51
|
+
raise
|
|
52
|
+
last_exc = exc
|
|
53
|
+
time.sleep(min(delay * (2**attempt), 1.0))
|
|
54
|
+
if last_exc is not None:
|
|
55
|
+
raise last_exc
|
|
56
|
+
raise SandboxError("E2B sandbox startup retry failed unexpectedly")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class E2BSandboxSession:
|
|
60
|
+
def __init__(self, sandbox: Any):
|
|
61
|
+
self._sandbox = sandbox
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def sandbox_id(self) -> str:
|
|
65
|
+
return str(getattr(self._sandbox, "sandbox_id", "") or "")
|
|
66
|
+
|
|
67
|
+
def write_file(self, path: str, data: str | bytes) -> None:
|
|
68
|
+
self._sandbox.files.write(path, data)
|
|
69
|
+
|
|
70
|
+
def read_file(self, path: str) -> str:
|
|
71
|
+
return str(self._sandbox.files.read(path))
|
|
72
|
+
|
|
73
|
+
def run_command(
|
|
74
|
+
self,
|
|
75
|
+
command: str,
|
|
76
|
+
*,
|
|
77
|
+
timeout: int | None = None,
|
|
78
|
+
env: dict[str, str] | None = None,
|
|
79
|
+
cwd: str | None = None,
|
|
80
|
+
) -> SandboxCommandResult:
|
|
81
|
+
kwargs = {}
|
|
82
|
+
if timeout is not None:
|
|
83
|
+
kwargs["timeout"] = timeout
|
|
84
|
+
if env is not None:
|
|
85
|
+
kwargs["envs"] = env
|
|
86
|
+
if cwd is not None:
|
|
87
|
+
kwargs["cwd"] = cwd
|
|
88
|
+
result = self._sandbox.commands.run(command, **kwargs)
|
|
89
|
+
return SandboxCommandResult(
|
|
90
|
+
stdout=str(getattr(result, "stdout", "") or ""),
|
|
91
|
+
stderr=str(getattr(result, "stderr", "") or ""),
|
|
92
|
+
exit_code=getattr(result, "exit_code", None),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def get_host(self, port: int) -> str:
|
|
96
|
+
return str(self._sandbox.get_host(port))
|
|
97
|
+
|
|
98
|
+
def kill(self) -> None:
|
|
99
|
+
self._sandbox.kill()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class E2BSandboxBackend:
|
|
103
|
+
def __init__(
|
|
104
|
+
self,
|
|
105
|
+
*,
|
|
106
|
+
spec: SandboxSpec,
|
|
107
|
+
sandbox_cls: Any | None = None,
|
|
108
|
+
):
|
|
109
|
+
if not spec.template_id:
|
|
110
|
+
raise SandboxError("E2B sandbox backend requires a template id")
|
|
111
|
+
self.spec = spec
|
|
112
|
+
self.sandbox_cls = sandbox_cls
|
|
113
|
+
|
|
114
|
+
def create_session(
|
|
115
|
+
self,
|
|
116
|
+
*,
|
|
117
|
+
session_id: str,
|
|
118
|
+
env: dict[str, str] | None = None,
|
|
119
|
+
input_files: list[SandboxInputFile] | None = None,
|
|
120
|
+
) -> SandboxSession:
|
|
121
|
+
sandbox_cls = self.sandbox_cls
|
|
122
|
+
if sandbox_cls is None:
|
|
123
|
+
try:
|
|
124
|
+
from e2b import Sandbox
|
|
125
|
+
except ImportError as exc:
|
|
126
|
+
raise SandboxError("e2b>=2.0.0 is required for KSADK_SANDBOX_BACKEND=e2b") from exc
|
|
127
|
+
sandbox_cls = Sandbox
|
|
128
|
+
|
|
129
|
+
metadata = {
|
|
130
|
+
"runtime": "ksadk",
|
|
131
|
+
"sandbox_type": self.spec.sandbox_type.value,
|
|
132
|
+
**self.spec.metadata,
|
|
133
|
+
"session_id": session_id,
|
|
134
|
+
}
|
|
135
|
+
runtime_env = {**self.spec.env, **(env or {})}
|
|
136
|
+
sandbox = sandbox_cls.create(
|
|
137
|
+
template=self.spec.template_id,
|
|
138
|
+
timeout=self.spec.timeout,
|
|
139
|
+
metadata=metadata,
|
|
140
|
+
envs=runtime_env,
|
|
141
|
+
allow_internet_access=self.spec.allow_internet_access,
|
|
142
|
+
)
|
|
143
|
+
session = self._wrap_sandbox(sandbox)
|
|
144
|
+
self._wait_until_ready(session)
|
|
145
|
+
for item in input_files or []:
|
|
146
|
+
session.write_file(item.target_path, item.source.read_bytes())
|
|
147
|
+
return session
|
|
148
|
+
|
|
149
|
+
def _wrap_sandbox(self, sandbox: Any) -> E2BSandboxSession:
|
|
150
|
+
return E2BSandboxSession(sandbox)
|
|
151
|
+
|
|
152
|
+
def _wait_until_ready(self, session: E2BSandboxSession) -> None:
|
|
153
|
+
_with_startup_retry(lambda: session.run_command("true"))
|
|
154
|
+
_with_startup_retry(lambda: session.write_file("/tmp/.ksadk-sandbox-ready", ""))
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import signal
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from ksadk.sandbox.base import SandboxCommandResult, SandboxInputFile, SandboxSession
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LocalProcessSandboxSession:
|
|
12
|
+
def __init__(self, *, session_id: str, workspace_root: Path, backend_name: str = "local_process"):
|
|
13
|
+
self._session_id = session_id
|
|
14
|
+
self._workspace_root = workspace_root.expanduser().resolve()
|
|
15
|
+
self._workspace_root.mkdir(parents=True, exist_ok=True)
|
|
16
|
+
self._backend_name = backend_name
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def sandbox_id(self) -> str:
|
|
20
|
+
return f"{self._backend_name}:{self._session_id}"
|
|
21
|
+
|
|
22
|
+
def write_file(self, path: str, data: str | bytes) -> None:
|
|
23
|
+
target = self._resolve_workspace_path(path)
|
|
24
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
if isinstance(data, bytes):
|
|
26
|
+
target.write_bytes(data)
|
|
27
|
+
else:
|
|
28
|
+
target.write_text(data, encoding="utf-8")
|
|
29
|
+
|
|
30
|
+
def read_file(self, path: str) -> str:
|
|
31
|
+
return self._resolve_workspace_path(path).read_text(encoding="utf-8")
|
|
32
|
+
|
|
33
|
+
def run_command(
|
|
34
|
+
self,
|
|
35
|
+
command: str,
|
|
36
|
+
*,
|
|
37
|
+
timeout: int | None = None,
|
|
38
|
+
env: dict[str, str] | None = None,
|
|
39
|
+
cwd: str | None = None,
|
|
40
|
+
) -> SandboxCommandResult:
|
|
41
|
+
try:
|
|
42
|
+
resolved_cwd = self._resolve_cwd(cwd or (env or {}).get("KSADK_COMMAND_CWD"))
|
|
43
|
+
except ValueError as exc:
|
|
44
|
+
return SandboxCommandResult(stderr=str(exc), exit_code=126)
|
|
45
|
+
process_env = self._allowed_env(env or {})
|
|
46
|
+
try:
|
|
47
|
+
process = subprocess.Popen(
|
|
48
|
+
command,
|
|
49
|
+
shell=True,
|
|
50
|
+
cwd=resolved_cwd,
|
|
51
|
+
env=process_env,
|
|
52
|
+
text=True,
|
|
53
|
+
stdout=subprocess.PIPE,
|
|
54
|
+
stderr=subprocess.PIPE,
|
|
55
|
+
start_new_session=True,
|
|
56
|
+
)
|
|
57
|
+
stdout, stderr = process.communicate(timeout=timeout)
|
|
58
|
+
return SandboxCommandResult(
|
|
59
|
+
stdout=stdout,
|
|
60
|
+
stderr=stderr,
|
|
61
|
+
exit_code=process.returncode,
|
|
62
|
+
)
|
|
63
|
+
except subprocess.TimeoutExpired as exc:
|
|
64
|
+
try:
|
|
65
|
+
os.killpg(process.pid, signal.SIGKILL)
|
|
66
|
+
except Exception:
|
|
67
|
+
pass
|
|
68
|
+
stdout, stderr = process.communicate()
|
|
69
|
+
return SandboxCommandResult(
|
|
70
|
+
stdout=stdout or exc.stdout or "",
|
|
71
|
+
stderr=(stderr or exc.stderr or "") + "\ncommand timed out",
|
|
72
|
+
exit_code=124,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def get_host(self, port: int) -> str:
|
|
76
|
+
return f"http://127.0.0.1:{int(port)}"
|
|
77
|
+
|
|
78
|
+
def kill(self) -> None:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
def _resolve_cwd(self, cwd: str | None) -> Path:
|
|
82
|
+
if not cwd:
|
|
83
|
+
return self._workspace_root
|
|
84
|
+
candidate = Path(cwd)
|
|
85
|
+
if not candidate.is_absolute():
|
|
86
|
+
candidate = self._workspace_root / candidate
|
|
87
|
+
resolved = candidate.expanduser().resolve()
|
|
88
|
+
if resolved != self._workspace_root and self._workspace_root not in resolved.parents:
|
|
89
|
+
raise ValueError("cwd must stay inside the sandbox workspace")
|
|
90
|
+
return resolved
|
|
91
|
+
|
|
92
|
+
def _resolve_workspace_path(self, path: str) -> Path:
|
|
93
|
+
raw = str(path or "").strip().lstrip("/") or "."
|
|
94
|
+
target = (self._workspace_root / raw).resolve()
|
|
95
|
+
if target != self._workspace_root and self._workspace_root not in target.parents:
|
|
96
|
+
raise ValueError("path must stay inside the sandbox workspace")
|
|
97
|
+
return target
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def _allowed_env(env: dict[str, str]) -> dict[str, str]:
|
|
101
|
+
allowed = {"PATH": os.environ.get("PATH", ""), "HOME": os.environ.get("HOME", "")}
|
|
102
|
+
for key, value in env.items():
|
|
103
|
+
if key.startswith("KSADK_COMMAND_"):
|
|
104
|
+
continue
|
|
105
|
+
if key.startswith(("KSADK_SAFE_", "PYTHON", "NODE", "UV_")):
|
|
106
|
+
allowed[key] = str(value)
|
|
107
|
+
return allowed
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class LocalProcessSandboxBackend:
|
|
111
|
+
isolated = False
|
|
112
|
+
|
|
113
|
+
def __init__(self, *, workspace_root: Path, backend_name: str = "local_process"):
|
|
114
|
+
self.workspace_root = workspace_root
|
|
115
|
+
self.backend_name = backend_name
|
|
116
|
+
|
|
117
|
+
def create_session(
|
|
118
|
+
self,
|
|
119
|
+
*,
|
|
120
|
+
session_id: str,
|
|
121
|
+
env: dict[str, str] | None = None,
|
|
122
|
+
input_files: list[SandboxInputFile] | None = None,
|
|
123
|
+
) -> SandboxSession:
|
|
124
|
+
session = LocalProcessSandboxSession(
|
|
125
|
+
session_id=session_id,
|
|
126
|
+
workspace_root=self.workspace_root,
|
|
127
|
+
backend_name=self.backend_name,
|
|
128
|
+
)
|
|
129
|
+
for item in input_files or []:
|
|
130
|
+
session.write_file(item.target_path, item.source.read_bytes())
|
|
131
|
+
return session
|
ksadk/sandbox/base.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Protocol
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SandboxError(RuntimeError):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SandboxType(str, Enum):
|
|
14
|
+
AIO = "aio"
|
|
15
|
+
CODE = "code"
|
|
16
|
+
BROWSER = "browser"
|
|
17
|
+
PRIVATE = "private"
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def from_value(cls, value: str | "SandboxType" | None) -> "SandboxType":
|
|
21
|
+
if isinstance(value, SandboxType):
|
|
22
|
+
return value
|
|
23
|
+
normalized = (value or "").strip().lower().replace("_", "").replace("-", "").replace(" ", "")
|
|
24
|
+
aliases = {
|
|
25
|
+
"": cls.AIO,
|
|
26
|
+
"aio": cls.AIO,
|
|
27
|
+
"allinone": cls.AIO,
|
|
28
|
+
"code": cls.CODE,
|
|
29
|
+
"codeinterpreter": cls.CODE,
|
|
30
|
+
"codesandbox": cls.CODE,
|
|
31
|
+
"browser": cls.BROWSER,
|
|
32
|
+
"browsersandbox": cls.BROWSER,
|
|
33
|
+
"private": cls.PRIVATE,
|
|
34
|
+
"custom": cls.PRIVATE,
|
|
35
|
+
}
|
|
36
|
+
try:
|
|
37
|
+
return aliases[normalized]
|
|
38
|
+
except KeyError as exc:
|
|
39
|
+
raise SandboxError(f"Unsupported sandbox type: {value}") from exc
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(frozen=True)
|
|
43
|
+
class SandboxInputFile:
|
|
44
|
+
source: Path
|
|
45
|
+
target_path: str
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass(frozen=True)
|
|
49
|
+
class SandboxCommandResult:
|
|
50
|
+
stdout: str = ""
|
|
51
|
+
stderr: str = ""
|
|
52
|
+
exit_code: int | None = None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(frozen=True)
|
|
56
|
+
class SandboxSpec:
|
|
57
|
+
template_id: str
|
|
58
|
+
sandbox_type: SandboxType = SandboxType.AIO
|
|
59
|
+
timeout: int = 900
|
|
60
|
+
allow_internet_access: bool = True
|
|
61
|
+
metadata: dict[str, str] = field(default_factory=dict)
|
|
62
|
+
env: dict[str, str] = field(default_factory=dict)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class SandboxSession(Protocol):
|
|
66
|
+
@property
|
|
67
|
+
def sandbox_id(self) -> str:
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
def write_file(self, path: str, data: str | bytes) -> None:
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
def read_file(self, path: str) -> str:
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
def run_command(
|
|
77
|
+
self,
|
|
78
|
+
command: str,
|
|
79
|
+
*,
|
|
80
|
+
timeout: int | None = None,
|
|
81
|
+
env: dict[str, str] | None = None,
|
|
82
|
+
cwd: str | None = None,
|
|
83
|
+
) -> SandboxCommandResult:
|
|
84
|
+
...
|
|
85
|
+
|
|
86
|
+
def get_host(self, port: int) -> str:
|
|
87
|
+
...
|
|
88
|
+
|
|
89
|
+
def kill(self) -> None:
|
|
90
|
+
...
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class SandboxBackend(Protocol):
|
|
94
|
+
def create_session(
|
|
95
|
+
self,
|
|
96
|
+
*,
|
|
97
|
+
session_id: str,
|
|
98
|
+
env: dict[str, str] | None = None,
|
|
99
|
+
input_files: list[SandboxInputFile] | None = None,
|
|
100
|
+
) -> SandboxSession:
|
|
101
|
+
...
|
ksadk/sandbox/factory.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from ksadk.sandbox.backends.e2b import E2BSandboxBackend
|
|
7
|
+
from ksadk.sandbox.backends.local_process import LocalProcessSandboxBackend
|
|
8
|
+
from ksadk.sandbox.base import SandboxBackend, SandboxError, SandboxSpec, SandboxType
|
|
9
|
+
from ksadk.sessions.local_service import resolve_local_session_dir
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def bool_env(name: str, default: bool = True) -> bool:
|
|
13
|
+
raw = os.environ.get(name)
|
|
14
|
+
if raw is None:
|
|
15
|
+
return default
|
|
16
|
+
return raw.strip().lower() in {"1", "true", "yes", "on"}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_sandbox_backend(
|
|
20
|
+
backend: str | None = None,
|
|
21
|
+
*,
|
|
22
|
+
sandbox_cls: Any | None = None,
|
|
23
|
+
) -> SandboxBackend:
|
|
24
|
+
resolved = (backend or os.environ.get("KSADK_SANDBOX_BACKEND") or "e2b").strip().lower()
|
|
25
|
+
if resolved in {"local", "local_process"}:
|
|
26
|
+
return LocalProcessSandboxBackend(workspace_root=resolve_local_session_dir() / "workspace", backend_name="local_process")
|
|
27
|
+
if resolved in {"pod", "pod_process"}:
|
|
28
|
+
if not bool_env("KSADK_ALLOW_POD_PROCESS_TOOLS", False):
|
|
29
|
+
raise SandboxError("KSADK_ALLOW_POD_PROCESS_TOOLS=true is required for pod_process backend")
|
|
30
|
+
return LocalProcessSandboxBackend(workspace_root=resolve_local_session_dir() / "workspace", backend_name="pod_process")
|
|
31
|
+
if resolved != "e2b":
|
|
32
|
+
raise SandboxError(f"Unsupported sandbox backend: {resolved}")
|
|
33
|
+
return E2BSandboxBackend(spec=sandbox_spec_from_env(), sandbox_cls=sandbox_cls)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def sandbox_spec_from_env() -> SandboxSpec:
|
|
37
|
+
template_id = (
|
|
38
|
+
os.environ.get("KSADK_SANDBOX_TEMPLATE_ID")
|
|
39
|
+
or os.environ.get("KSADK_SKILL_RUNTIME_TEMPLATE_ID")
|
|
40
|
+
or ""
|
|
41
|
+
)
|
|
42
|
+
timeout = int(os.environ.get("KSADK_SANDBOX_TIMEOUT") or os.environ.get("KSADK_SKILL_RUNTIME_TIMEOUT") or "900")
|
|
43
|
+
allow_internet_access = bool_env(
|
|
44
|
+
"KSADK_SANDBOX_ALLOW_INTERNET_ACCESS",
|
|
45
|
+
bool_env("KSADK_SKILL_RUNTIME_ALLOW_INTERNET_ACCESS", True),
|
|
46
|
+
)
|
|
47
|
+
sandbox_type = SandboxType.from_value(os.environ.get("KSADK_SANDBOX_TYPE", "aio"))
|
|
48
|
+
return SandboxSpec(
|
|
49
|
+
template_id=template_id,
|
|
50
|
+
sandbox_type=sandbox_type,
|
|
51
|
+
timeout=timeout,
|
|
52
|
+
allow_internet_access=allow_internet_access,
|
|
53
|
+
)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import atexit
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import threading
|
|
7
|
+
import time
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from ksadk.sandbox.base import SandboxBackend, SandboxSession
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
# 后台 sweep 默认间隔(秒)。0 表示禁用后台 sweep,仅靠 get_or_create 时的惰性 sweep。
|
|
15
|
+
_DEFAULT_SWEEP_INTERVAL_SECONDS = 60
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class SandboxRegistryEntry:
|
|
20
|
+
key: str
|
|
21
|
+
backend: str
|
|
22
|
+
session: SandboxSession
|
|
23
|
+
created_at: float
|
|
24
|
+
last_used_at: float
|
|
25
|
+
expires_at: float
|
|
26
|
+
isolated: bool
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def sandbox_id(self) -> str:
|
|
30
|
+
return self.session.sandbox_id
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SandboxRegistry:
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self._entries: dict[str, SandboxRegistryEntry] = {}
|
|
36
|
+
# RLock 可重入:get_or_create 内部会调 sweep/kill/_enforce_quota。
|
|
37
|
+
self._lock = threading.RLock()
|
|
38
|
+
# idle_ttl 由 toolset 层在 get_or_create 时传入,后台 sweep 复用该值。
|
|
39
|
+
self._idle_ttl_seconds: int = 0
|
|
40
|
+
self._sweep_thread: threading.Thread | None = None
|
|
41
|
+
self._sweep_stop = threading.Event()
|
|
42
|
+
self._sweep_interval = self._resolve_sweep_interval()
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _resolve_sweep_interval() -> int:
|
|
46
|
+
raw = os.environ.get("KSADK_SANDBOX_SWEEP_INTERVAL_SECONDS", str(_DEFAULT_SWEEP_INTERVAL_SECONDS))
|
|
47
|
+
try:
|
|
48
|
+
value = int(raw)
|
|
49
|
+
except (TypeError, ValueError):
|
|
50
|
+
return _DEFAULT_SWEEP_INTERVAL_SECONDS
|
|
51
|
+
return value if value > 0 else 0
|
|
52
|
+
|
|
53
|
+
def get_or_create(
|
|
54
|
+
self,
|
|
55
|
+
*,
|
|
56
|
+
key: str,
|
|
57
|
+
backend_name: str,
|
|
58
|
+
backend: SandboxBackend,
|
|
59
|
+
ttl_seconds: int,
|
|
60
|
+
isolated: bool,
|
|
61
|
+
idle_ttl_seconds: int | None = None,
|
|
62
|
+
max_sessions: int | None = None,
|
|
63
|
+
input_files: list | None = None,
|
|
64
|
+
now: float | None = None,
|
|
65
|
+
) -> tuple[SandboxRegistryEntry, bool]:
|
|
66
|
+
current = time.time() if now is None else now
|
|
67
|
+
if idle_ttl_seconds is not None:
|
|
68
|
+
self._idle_ttl_seconds = int(idle_ttl_seconds or 0)
|
|
69
|
+
with self._lock:
|
|
70
|
+
self.sweep(now=current, idle_ttl_seconds=self._idle_ttl_seconds)
|
|
71
|
+
entry = self._entries.get(key)
|
|
72
|
+
if entry is not None and entry.expires_at > current:
|
|
73
|
+
entry.last_used_at = current
|
|
74
|
+
return entry, False
|
|
75
|
+
if entry is not None:
|
|
76
|
+
self.kill(key)
|
|
77
|
+
self._enforce_quota(max_sessions=max_sessions, keep_key=key)
|
|
78
|
+
session = backend.create_session(session_id=key, input_files=input_files or None)
|
|
79
|
+
entry = SandboxRegistryEntry(
|
|
80
|
+
key=key,
|
|
81
|
+
backend=backend_name,
|
|
82
|
+
session=session,
|
|
83
|
+
created_at=current,
|
|
84
|
+
last_used_at=current,
|
|
85
|
+
expires_at=current + max(1, int(ttl_seconds or 900)),
|
|
86
|
+
isolated=isolated,
|
|
87
|
+
)
|
|
88
|
+
self._entries[key] = entry
|
|
89
|
+
# 锁外启动后台线程,避免持锁创建线程。
|
|
90
|
+
self._start_sweep_thread()
|
|
91
|
+
return entry, True
|
|
92
|
+
|
|
93
|
+
def latest(self) -> SandboxRegistryEntry | None:
|
|
94
|
+
with self._lock:
|
|
95
|
+
if not self._entries:
|
|
96
|
+
return None
|
|
97
|
+
return max(self._entries.values(), key=lambda item: item.last_used_at)
|
|
98
|
+
|
|
99
|
+
def sweep(self, *, now: float | None = None, idle_ttl_seconds: int | None = None) -> int:
|
|
100
|
+
current = time.time() if now is None else now
|
|
101
|
+
idle_ttl = int(idle_ttl_seconds or 0)
|
|
102
|
+
with self._lock:
|
|
103
|
+
expired = [
|
|
104
|
+
key
|
|
105
|
+
for key, entry in self._entries.items()
|
|
106
|
+
if entry.expires_at <= current or (idle_ttl > 0 and current - entry.last_used_at > idle_ttl)
|
|
107
|
+
]
|
|
108
|
+
for key in expired:
|
|
109
|
+
self.kill(key)
|
|
110
|
+
return len(expired)
|
|
111
|
+
|
|
112
|
+
def entries(self) -> list[SandboxRegistryEntry]:
|
|
113
|
+
with self._lock:
|
|
114
|
+
return list(self._entries.values())
|
|
115
|
+
|
|
116
|
+
def kill(self, key: str) -> bool:
|
|
117
|
+
with self._lock:
|
|
118
|
+
entry = self._entries.pop(key, None)
|
|
119
|
+
if entry is None:
|
|
120
|
+
return False
|
|
121
|
+
# session.kill() 是 E2B 网络 IO,放锁外避免持锁阻塞并发 get_or_create。
|
|
122
|
+
try:
|
|
123
|
+
entry.session.kill()
|
|
124
|
+
except Exception:
|
|
125
|
+
logger.exception("sandbox session kill failed for key=%s", key)
|
|
126
|
+
return True
|
|
127
|
+
|
|
128
|
+
def clear(self) -> None:
|
|
129
|
+
with self._lock:
|
|
130
|
+
keys = list(self._entries)
|
|
131
|
+
for key in keys:
|
|
132
|
+
self.kill(key)
|
|
133
|
+
|
|
134
|
+
def _enforce_quota(self, *, max_sessions: int | None, keep_key: str) -> None:
|
|
135
|
+
if not max_sessions or max_sessions < 1:
|
|
136
|
+
return
|
|
137
|
+
to_kill: list[str] = []
|
|
138
|
+
with self._lock:
|
|
139
|
+
while len(self._entries) - len(to_kill) >= max_sessions:
|
|
140
|
+
candidates = [
|
|
141
|
+
entry for entry in self._entries.values()
|
|
142
|
+
if entry.key != keep_key and entry.key not in to_kill
|
|
143
|
+
]
|
|
144
|
+
if not candidates:
|
|
145
|
+
break
|
|
146
|
+
oldest = min(candidates, key=lambda item: item.last_used_at)
|
|
147
|
+
to_kill.append(oldest.key)
|
|
148
|
+
for key in to_kill:
|
|
149
|
+
self.kill(key)
|
|
150
|
+
|
|
151
|
+
def _start_sweep_thread(self) -> None:
|
|
152
|
+
if self._sweep_interval <= 0:
|
|
153
|
+
return
|
|
154
|
+
with self._lock:
|
|
155
|
+
if self._sweep_thread is not None and self._sweep_thread.is_alive():
|
|
156
|
+
return
|
|
157
|
+
self._sweep_stop.clear()
|
|
158
|
+
self._sweep_thread = threading.Thread(
|
|
159
|
+
target=self._sweep_loop,
|
|
160
|
+
name="ksadk-sandbox-sweep",
|
|
161
|
+
daemon=True,
|
|
162
|
+
)
|
|
163
|
+
self._sweep_thread.start()
|
|
164
|
+
|
|
165
|
+
def _sweep_loop(self) -> None:
|
|
166
|
+
while not self._sweep_stop.wait(timeout=self._sweep_interval):
|
|
167
|
+
try:
|
|
168
|
+
self.sweep(idle_ttl_seconds=self._idle_ttl_seconds)
|
|
169
|
+
except Exception:
|
|
170
|
+
logger.exception("sandbox background sweep failed")
|
|
171
|
+
|
|
172
|
+
def reset_for_tests(self) -> None:
|
|
173
|
+
"""停后台 sweep 线程并清空所有 entry,用于测试隔离。"""
|
|
174
|
+
self._sweep_stop.set()
|
|
175
|
+
thread = self._sweep_thread
|
|
176
|
+
if thread is not None and thread.is_alive():
|
|
177
|
+
thread.join(timeout=2.0)
|
|
178
|
+
self._sweep_thread = None
|
|
179
|
+
self.clear()
|
|
180
|
+
self._idle_ttl_seconds = 0
|
|
181
|
+
self._sweep_stop.clear()
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
GLOBAL_SANDBOX_REGISTRY = SandboxRegistry()
|
|
185
|
+
# 进程退出时清理 sandbox,避免 E2B sandbox 活到服务端 timeout 才销毁(按秒计费)。
|
|
186
|
+
# clear() 幂等,与 server lifespan shutdown 重复调用安全。kill -9 不触发 atexit,只能靠 E2B 兜底。
|
|
187
|
+
atexit.register(GLOBAL_SANDBOX_REGISTRY.clear)
|