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.
Files changed (486) hide show
  1. agentengine_sdk_python-0.7.0.dist-info/METADATA +181 -0
  2. agentengine_sdk_python-0.7.0.dist-info/RECORD +482 -0
  3. {agentengine_sdk_python-0.6.4.dist-info → agentengine_sdk_python-0.7.0.dist-info}/WHEEL +1 -1
  4. agentengine_sdk_python-0.7.0.dist-info/entry_points.txt +3 -0
  5. agentengine_sdk_python-0.7.0.dist-info/licenses/LICENSE +175 -0
  6. agentengine_sdk_python-0.7.0.dist-info/top_level.txt +2 -0
  7. ksadk/__init__.py +13 -0
  8. ksadk/__main__.py +4 -0
  9. ksadk/a2a/__init__.py +15 -0
  10. ksadk/a2a/card_builder.py +64 -0
  11. ksadk/a2a/client.py +309 -0
  12. ksadk/a2a/executor.py +201 -0
  13. ksadk/a2a/server.py +79 -0
  14. ksadk/agents/__init__.py +20 -0
  15. ksadk/agents/base.py +370 -0
  16. ksadk/agents/context.py +38 -0
  17. ksadk/agents/event.py +35 -0
  18. ksadk/agents/loop_agent.py +71 -0
  19. ksadk/agents/parallel_agent.py +109 -0
  20. ksadk/agents/runner_adapter.py +24 -0
  21. ksadk/agents/sequential_agent.py +34 -0
  22. ksadk/api/__init__.py +3 -0
  23. ksadk/api/client.py +2246 -0
  24. ksadk/builders/__init__.py +20 -0
  25. ksadk/builders/base.py +66 -0
  26. ksadk/builders/code_builder.py +1990 -0
  27. ksadk/builders/container_builder.py +786 -0
  28. ksadk/builders/framework_requirements.py +59 -0
  29. ksadk/builders/ks3_uploader.py +389 -0
  30. ksadk/builders/mcp_builder.py +476 -0
  31. ksadk/builders/requirements_utils.py +75 -0
  32. ksadk/cli/__init__.py +531 -0
  33. ksadk/cli/__main__.py +4 -0
  34. ksadk/cli/agent_ref.py +204 -0
  35. ksadk/cli/cmd_a2a.py +167 -0
  36. ksadk/cli/cmd_agent.py +201 -0
  37. ksadk/cli/cmd_build.py +270 -0
  38. ksadk/cli/cmd_completion.py +304 -0
  39. ksadk/cli/cmd_config.py +758 -0
  40. ksadk/cli/cmd_create.py +2304 -0
  41. ksadk/cli/cmd_dashboard.py +900 -0
  42. ksadk/cli/cmd_deploy.py +704 -0
  43. ksadk/cli/cmd_destroy.py +345 -0
  44. ksadk/cli/cmd_files.py +1227 -0
  45. ksadk/cli/cmd_hermes.py +1263 -0
  46. ksadk/cli/cmd_invoke.py +1503 -0
  47. ksadk/cli/cmd_launch.py +564 -0
  48. ksadk/cli/cmd_mcp.py +1179 -0
  49. ksadk/cli/cmd_model.py +302 -0
  50. ksadk/cli/cmd_openclaw.py +3922 -0
  51. ksadk/cli/cmd_run.py +239 -0
  52. ksadk/cli/cmd_status.py +588 -0
  53. ksadk/cli/cmd_version.py +522 -0
  54. ksadk/cli/cmd_web.py +288 -0
  55. ksadk/cli/deploy_utils.py +87 -0
  56. ksadk/cli/dry_run.py +214 -0
  57. ksadk/cli/env_options.py +82 -0
  58. ksadk/cli/error_utils.py +525 -0
  59. ksadk/cli/global_options.py +31 -0
  60. ksadk/cli/local_runtime.py +97 -0
  61. ksadk/cli/model_catalog.py +136 -0
  62. ksadk/cli/network_options.py +412 -0
  63. ksadk/cli/resource_common.py +621 -0
  64. ksadk/cli/storage.py +84 -0
  65. ksadk/cli/ui.py +431 -0
  66. ksadk/cli/workflow_common.py +552 -0
  67. ksadk/common/__init__.py +14 -0
  68. ksadk/common/aicp_env.py +128 -0
  69. ksadk/common/auth.py +190 -0
  70. ksadk/common/constants.py +84 -0
  71. ksadk/common/llm_utils.py +61 -0
  72. ksadk/configs/__init__.py +61 -0
  73. ksadk/configs/env_registry.py +343 -0
  74. ksadk/configs/global_config.py +200 -0
  75. ksadk/configs/settings.py +706 -0
  76. ksadk/conversations/__init__.py +95 -0
  77. ksadk/conversations/attachment_storage.py +379 -0
  78. ksadk/conversations/attachments.py +774 -0
  79. ksadk/conversations/compaction_pipeline.py +387 -0
  80. ksadk/conversations/compaction_prompt.py +128 -0
  81. ksadk/conversations/context.py +303 -0
  82. ksadk/conversations/message_projection.py +269 -0
  83. ksadk/conversations/model_context.py +370 -0
  84. ksadk/conversations/model_options.py +136 -0
  85. ksadk/conversations/normalize.py +446 -0
  86. ksadk/conversations/reasoning_markup.py +91 -0
  87. ksadk/conversations/run_kinds.py +61 -0
  88. ksadk/conversations/run_status.py +53 -0
  89. ksadk/conversations/runtime.py +5276 -0
  90. ksadk/conversations/semantic_summary.py +359 -0
  91. ksadk/conversations/session_title.py +254 -0
  92. ksadk/deployment/__init__.py +83 -0
  93. ksadk/deployment/agent_access.py +226 -0
  94. ksadk/deployment/base.py +229 -0
  95. ksadk/deployment/manager.py +332 -0
  96. ksadk/deployment/providers/__init__.py +10 -0
  97. ksadk/deployment/providers/serverless.py +1115 -0
  98. ksadk/deployment/registry.py +120 -0
  99. ksadk/deployment/state.py +78 -0
  100. ksadk/deployment/ui_config.py +21 -0
  101. ksadk/detection/__init__.py +7 -0
  102. ksadk/detection/detector.py +431 -0
  103. ksadk/detection/mcp_detector.py +250 -0
  104. ksadk/hermes_terminal.py +467 -0
  105. ksadk/identity/__init__.py +17 -0
  106. ksadk/identity/resolver.py +385 -0
  107. ksadk/knowledge_base/__init__.py +62 -0
  108. ksadk/knowledge_base/adk_tool.py +47 -0
  109. ksadk/knowledge_base/client.py +297 -0
  110. ksadk/knowledge_base/langchain_tool.py +55 -0
  111. ksadk/knowledge_base/service.py +66 -0
  112. ksadk/knowledge_base/tool.py +50 -0
  113. ksadk/markdown.py +169 -0
  114. ksadk/mcp_runtime/__init__.py +231 -0
  115. ksadk/memory/__init__.py +57 -0
  116. ksadk/memory/adk/__init__.py +51 -0
  117. ksadk/memory/adk/backends/__init__.py +5 -0
  118. ksadk/memory/adk/backends/base_ltm_backend.py +52 -0
  119. ksadk/memory/adk/backends/http_ltm_backend.py +183 -0
  120. ksadk/memory/adk/backends/inmemory_ltm_backend.py +96 -0
  121. ksadk/memory/adk/backends/sdk_ltm_backend.py +456 -0
  122. ksadk/memory/adk/long_term_memory.py +273 -0
  123. ksadk/memory/adk/resilient_session_service.py +268 -0
  124. ksadk/memory/adk/short_term_memory.py +304 -0
  125. ksadk/memory/adk_tool.py +31 -0
  126. ksadk/memory/backends/__init__.py +6 -0
  127. ksadk/memory/backends/base.py +103 -0
  128. ksadk/memory/backends/memory.py +112 -0
  129. ksadk/memory/backends/redis.py +146 -0
  130. ksadk/memory/langchain_tool.py +39 -0
  131. ksadk/memory/ltm_backend_factory.py +24 -0
  132. ksadk/memory/manager.py +215 -0
  133. ksadk/memory/service.py +172 -0
  134. ksadk/memory/tool.py +96 -0
  135. ksadk/model_policy.py +223 -0
  136. ksadk/openclaw_gateway.py +378 -0
  137. ksadk/runners/__init__.py +8 -0
  138. ksadk/runners/adk_runner.py +1994 -0
  139. ksadk/runners/base_runner.py +305 -0
  140. ksadk/runners/deepagents_runner.py +13 -0
  141. ksadk/runners/factory.py +73 -0
  142. ksadk/runners/langchain_runner.py +751 -0
  143. ksadk/runners/langgraph_runner.py +985 -0
  144. ksadk/runners/patch_langchain.py +187 -0
  145. ksadk/runners/remote_runner.py +792 -0
  146. ksadk/runners/usage_accumulator.py +38 -0
  147. ksadk/runners/utils/__init__.py +19 -0
  148. ksadk/runners/utils/langfuse.py +230 -0
  149. ksadk/runners/utils/loader.py +62 -0
  150. ksadk/runtime_context.py +166 -0
  151. ksadk/runtime_state.py +25 -0
  152. ksadk/sandbox/__init__.py +28 -0
  153. ksadk/sandbox/backends/__init__.py +9 -0
  154. ksadk/sandbox/backends/e2b.py +154 -0
  155. ksadk/sandbox/backends/local_process.py +131 -0
  156. ksadk/sandbox/base.py +101 -0
  157. ksadk/sandbox/factory.py +53 -0
  158. ksadk/sandbox/registry.py +187 -0
  159. ksadk/server/__init__.py +7 -0
  160. ksadk/server/api_models.py +73 -0
  161. ksadk/server/app.py +3931 -0
  162. ksadk/server/static/assets/ArtifactsPanel-D-SSn2ee.js +1 -0
  163. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +9 -0
  164. ksadk/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  165. ksadk/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  166. ksadk/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  167. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  168. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  169. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  170. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  171. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  172. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  173. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  174. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  175. ksadk/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  176. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  177. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  178. ksadk/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  179. ksadk/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  180. ksadk/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  181. ksadk/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  182. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  183. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  184. ksadk/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  185. ksadk/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  186. ksadk/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  187. ksadk/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  188. ksadk/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  189. ksadk/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  190. ksadk/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  191. ksadk/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  192. ksadk/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  193. ksadk/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  194. ksadk/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  195. ksadk/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  196. ksadk/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  197. ksadk/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  198. ksadk/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  199. ksadk/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  200. ksadk/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  201. ksadk/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  202. ksadk/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  203. ksadk/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  204. ksadk/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  205. ksadk/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  206. ksadk/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  207. ksadk/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  208. ksadk/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  209. ksadk/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  210. ksadk/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  211. ksadk/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  212. ksadk/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  213. ksadk/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  214. ksadk/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  215. ksadk/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  216. ksadk/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  217. ksadk/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  218. ksadk/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  219. ksadk/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  220. ksadk/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  221. ksadk/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  222. ksadk/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +8 -0
  224. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +1 -0
  225. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +303 -0
  226. ksadk/server/static/assets/NativeTerminalPanel-CHOd7Rch.css +1 -0
  227. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +1 -0
  228. ksadk/server/static/assets/addon-fit-DthTIhi3.js +1 -0
  229. ksadk/server/static/assets/apl-CnwPGSsG.js +1 -0
  230. ksadk/server/static/assets/arc-BA13sHc9.js +1 -0
  231. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +1 -0
  232. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-DzJzgVoL.js +36 -0
  233. ksadk/server/static/assets/asciiarmor-qTkVPQu6.js +1 -0
  234. ksadk/server/static/assets/asn1-Dr8qZg38.js +1 -0
  235. ksadk/server/static/assets/asterisk-Bja0s6e1.js +1 -0
  236. ksadk/server/static/assets/blockDiagram-GPEHLZMM-UTdVcZhn.js +132 -0
  237. ksadk/server/static/assets/brainfuck-D5EjA2JK.js +1 -0
  238. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dix0GD4m.js +10 -0
  239. ksadk/server/static/assets/channel-CTuydARX.js +1 -0
  240. ksadk/server/static/assets/chunk-2J33WTMH-C2JxuZ42.js +1 -0
  241. ksadk/server/static/assets/chunk-4BX2VUAB-Be57QPgD.js +1 -0
  242. ksadk/server/static/assets/chunk-55IACEB6-WjSuy4nv.js +1 -0
  243. ksadk/server/static/assets/chunk-727SXJPM-BOovP-b5.js +206 -0
  244. ksadk/server/static/assets/chunk-AQP2D5EJ-DOmZNmWj.js +231 -0
  245. ksadk/server/static/assets/chunk-FMBD7UC4-DzwlodkU.js +15 -0
  246. ksadk/server/static/assets/chunk-ND2GUHAM-DMqAikEU.js +1 -0
  247. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +1 -0
  248. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +1 -0
  249. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +1 -0
  250. ksadk/server/static/assets/clike-DHH8Ad3s.js +1 -0
  251. ksadk/server/static/assets/clojure-BflJGmDX.js +1 -0
  252. ksadk/server/static/assets/cmake-CyVbuzPu.js +1 -0
  253. ksadk/server/static/assets/cobol-B_OZ4V-R.js +1 -0
  254. ksadk/server/static/assets/coffeescript-B2pKbFk8.js +1 -0
  255. ksadk/server/static/assets/commonlisp-CcllspGY.js +1 -0
  256. ksadk/server/static/assets/cose-bilkent-S5V4N54A-Zhy2GBnP.js +1 -0
  257. ksadk/server/static/assets/crystal-M5-qzICs.js +1 -0
  258. ksadk/server/static/assets/css-CYpP4FRV.js +1 -0
  259. ksadk/server/static/assets/cypher-p9eYesGn.js +1 -0
  260. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +321 -0
  261. ksadk/server/static/assets/d-BhMjBjQP.js +1 -0
  262. ksadk/server/static/assets/dagre-BM42HDAG-CbKrtIUz.js +4 -0
  263. ksadk/server/static/assets/dagre-Bx709z4p.js +1 -0
  264. ksadk/server/static/assets/defaultLocale-C8Fc0cco.js +1 -0
  265. ksadk/server/static/assets/diagram-2AECGRRQ-BRApgQRK.js +43 -0
  266. ksadk/server/static/assets/diagram-5GNKFQAL-D0xbnDiK.js +10 -0
  267. ksadk/server/static/assets/diagram-KO2AKTUF-CVugVI9L.js +3 -0
  268. ksadk/server/static/assets/diagram-LMA3HP47-DozUGgee.js +24 -0
  269. ksadk/server/static/assets/diagram-OG6HWLK6-ZOYsKlru.js +24 -0
  270. ksadk/server/static/assets/diff-ChtP43wD.js +1 -0
  271. ksadk/server/static/assets/dist-2hInLS_J.js +9 -0
  272. ksadk/server/static/assets/dist-8EEyGgDx.js +1 -0
  273. ksadk/server/static/assets/dist-8_SfK1IP.js +1 -0
  274. ksadk/server/static/assets/dist-B0NP_Z0z.js +23 -0
  275. ksadk/server/static/assets/dist-BIJVDMuB.js +1 -0
  276. ksadk/server/static/assets/dist-BmlMPsCc.js +2 -0
  277. ksadk/server/static/assets/dist-BrCcQ47T.js +1 -0
  278. ksadk/server/static/assets/dist-BssVmjIo.js +6 -0
  279. ksadk/server/static/assets/dist-C3HIIaN5.js +1 -0
  280. ksadk/server/static/assets/dist-CPBtqRTW.js +1 -0
  281. ksadk/server/static/assets/dist-CkEKJFtk.js +1 -0
  282. ksadk/server/static/assets/dist-D-JMdWPQ.js +1 -0
  283. ksadk/server/static/assets/dist-D-xOD048.js +1 -0
  284. ksadk/server/static/assets/dist-D57wnGWd.js +1 -0
  285. ksadk/server/static/assets/dist-DL_NKc_z.js +1 -0
  286. ksadk/server/static/assets/dist-DMezvBGJ.js +1 -0
  287. ksadk/server/static/assets/dist-DmFaq_Iy.js +1 -0
  288. ksadk/server/static/assets/dist-Dp0k7bWI.js +1 -0
  289. ksadk/server/static/assets/dist-DpKtt4Bo.js +1 -0
  290. ksadk/server/static/assets/dist-DyOkZmze.js +11 -0
  291. ksadk/server/static/assets/dist-DyWsb78Q.js +1 -0
  292. ksadk/server/static/assets/dist-gX6GOLKq.js +1 -0
  293. ksadk/server/static/assets/dockerfile-BLkNEvjs.js +1 -0
  294. ksadk/server/static/assets/dtd-DTF72YNO.js +1 -0
  295. ksadk/server/static/assets/dylan-C6jEEEk-.js +1 -0
  296. ksadk/server/static/assets/ebnf-D4c0_ac3.js +1 -0
  297. ksadk/server/static/assets/ecl-BSZaIHnp.js +1 -0
  298. ksadk/server/static/assets/eiffel-BEjRio4Q.js +1 -0
  299. ksadk/server/static/assets/elm-Cshzl8qu.js +1 -0
  300. ksadk/server/static/assets/erDiagram-TEJ5UH35-Bk-9bgE5.js +85 -0
  301. ksadk/server/static/assets/erlang-DaB2Rkuy.js +1 -0
  302. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +1 -0
  303. ksadk/server/static/assets/factor-D7LVTn2l.js +1 -0
  304. ksadk/server/static/assets/fcl-ClOhbFR7.js +1 -0
  305. ksadk/server/static/assets/flowDiagram-I6XJVG4X-Dn9kZVuZ.js +162 -0
  306. ksadk/server/static/assets/forth-Cezjo90N.js +1 -0
  307. ksadk/server/static/assets/fortran-Bt6PBEDR.js +1 -0
  308. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-BGxXlJqm.js +292 -0
  309. ksadk/server/static/assets/gas-BHEdbvp9.js +1 -0
  310. ksadk/server/static/assets/gherkin-oBAE_ms0.js +1 -0
  311. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +1 -0
  312. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-C7Q0X-wi.js +106 -0
  313. ksadk/server/static/assets/graphlib-B8gBHxth.js +1 -0
  314. ksadk/server/static/assets/groovy-BC3IOsC8.js +1 -0
  315. ksadk/server/static/assets/haskell-BRsoo5mP.js +1 -0
  316. ksadk/server/static/assets/haxe-DIz0ZZqd.js +1 -0
  317. ksadk/server/static/assets/http-CLVgA2GD.js +1 -0
  318. ksadk/server/static/assets/idl-BUZw3wgd.js +1 -0
  319. ksadk/server/static/assets/index-C00Lwg3L.js +165 -0
  320. ksadk/server/static/assets/index-DAURbCsP.css +1 -0
  321. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +1 -0
  322. ksadk/server/static/assets/infoDiagram-5YYISTIA-BO_CSqq5.js +2 -0
  323. ksadk/server/static/assets/init-D6jRqBbL.js +1 -0
  324. ksadk/server/static/assets/ishikawaDiagram-YF4QCWOH-eYLPLd46.js +70 -0
  325. ksadk/server/static/assets/javascript-9Tg8ixDm.js +1 -0
  326. ksadk/server/static/assets/journeyDiagram-JHISSGLW-De9geSb0.js +139 -0
  327. ksadk/server/static/assets/julia-CQfgDRfP.js +1 -0
  328. ksadk/server/static/assets/kanban-definition-UN3LZRKU-Cs80kQto.js +89 -0
  329. ksadk/server/static/assets/katex-DSrCFD8n.js +265 -0
  330. ksadk/server/static/assets/linear-CN9sbKTF.js +1 -0
  331. ksadk/server/static/assets/livescript-BXxG0Yva.js +1 -0
  332. ksadk/server/static/assets/lua-CiA1ziua.js +1 -0
  333. ksadk/server/static/assets/mathematica-u8YMmbU0.js +1 -0
  334. ksadk/server/static/assets/mbox-BEMVcqjs.js +1 -0
  335. ksadk/server/static/assets/mermaid-parser.core-DlgSBU8l.js +161 -0
  336. ksadk/server/static/assets/mindmap-definition-RKZ34NQL-9afz7Oug.js +96 -0
  337. ksadk/server/static/assets/mirc-C9zpzAZU.js +1 -0
  338. ksadk/server/static/assets/mllike-B45xgp2S.js +1 -0
  339. ksadk/server/static/assets/modelica-CqHI_q-D.js +1 -0
  340. ksadk/server/static/assets/mscgen-qgSLujhx.js +1 -0
  341. ksadk/server/static/assets/mumps-CW_TBmxz.js +1 -0
  342. ksadk/server/static/assets/nginx-BMaDbqW3.js +1 -0
  343. ksadk/server/static/assets/nsis-AQ_alPln.js +1 -0
  344. ksadk/server/static/assets/ntriples-d28e9m0E.js +1 -0
  345. ksadk/server/static/assets/octave-D2Q8cUp1.js +1 -0
  346. ksadk/server/static/assets/ordinal-hYBb2elL.js +1 -0
  347. ksadk/server/static/assets/oz-BwTct_5T.js +1 -0
  348. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +1 -0
  349. ksadk/server/static/assets/pascal-Dp_KdFgX.js +1 -0
  350. ksadk/server/static/assets/perl-CdEHsPfU.js +1 -0
  351. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +1 -0
  352. ksadk/server/static/assets/pieDiagram-4H26LBE5-DPv_VstN.js +30 -0
  353. ksadk/server/static/assets/pig-AF4Hwhju.js +1 -0
  354. ksadk/server/static/assets/powershell-CzG71I4L.js +1 -0
  355. ksadk/server/static/assets/properties-C357ku5U.js +1 -0
  356. ksadk/server/static/assets/protobuf-D1ij_kNL.js +1 -0
  357. ksadk/server/static/assets/pug-Bugr-47h.js +1 -0
  358. ksadk/server/static/assets/puppet-B4hC2X4m.js +1 -0
  359. ksadk/server/static/assets/python-BqYw9LYJ.js +1 -0
  360. ksadk/server/static/assets/q-B9NhS7L_.js +1 -0
  361. ksadk/server/static/assets/quadrantDiagram-W4KKPZXB-o77wZ1XK.js +7 -0
  362. ksadk/server/static/assets/r-DADKenSm.js +1 -0
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +1 -0
  364. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-BYVw81VC.js +84 -0
  365. ksadk/server/static/assets/rpm-gpDK5sbt.js +1 -0
  366. ksadk/server/static/assets/ruby-DsYpTuWg.js +1 -0
  367. ksadk/server/static/assets/sankeyDiagram-5OEKKPKP-B7nZFMKT.js +40 -0
  368. ksadk/server/static/assets/sas-C2OyD2Y6.js +1 -0
  369. ksadk/server/static/assets/scheme-CyDdOh7e.js +1 -0
  370. ksadk/server/static/assets/sequenceDiagram-3UESZ5HK-BGRRrFw5.js +162 -0
  371. ksadk/server/static/assets/shell-Du5Qg9im.js +1 -0
  372. ksadk/server/static/assets/sieve-BAxa3IjF.js +1 -0
  373. ksadk/server/static/assets/simple-mode-DRpGK0lJ.js +1 -0
  374. ksadk/server/static/assets/smalltalk-BLp5-jwC.js +1 -0
  375. ksadk/server/static/assets/solr-BBopId9w.js +1 -0
  376. ksadk/server/static/assets/sparql-Dz-mlCAC.js +1 -0
  377. ksadk/server/static/assets/spreadsheet-CTIncYxj.js +1 -0
  378. ksadk/server/static/assets/sql-DcCJ9jop.js +1 -0
  379. ksadk/server/static/assets/stateDiagram-AJRCARHV-BUfHCoPs.js +1 -0
  380. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +1 -0
  381. ksadk/server/static/assets/stex-sDrdk2BW.js +1 -0
  382. ksadk/server/static/assets/stylus-DLLZ8dgm.js +1 -0
  383. ksadk/server/static/assets/swift-DKB6_1j6.js +1 -0
  384. ksadk/server/static/assets/tcl-BGfruO1u.js +1 -0
  385. ksadk/server/static/assets/textile-DWBqthVk.js +1 -0
  386. ksadk/server/static/assets/tiddlywiki-VlUiK86J.js +1 -0
  387. ksadk/server/static/assets/tiki-CxVlf5KZ.js +1 -0
  388. ksadk/server/static/assets/timeline-definition-PNZ67QCA-FbCTGrf9.js +120 -0
  389. ksadk/server/static/assets/toml-LvoKBwCs.js +1 -0
  390. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +1 -0
  391. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +1 -0
  392. ksadk/server/static/assets/troff-C2dAgh7P.js +1 -0
  393. ksadk/server/static/assets/ttcn-BePYh-hG.js +1 -0
  394. ksadk/server/static/assets/ttcn-cfg-CY0aot7Q.js +1 -0
  395. ksadk/server/static/assets/turtle-BDLWE2cD.js +1 -0
  396. ksadk/server/static/assets/vb-BthdM_4N.js +1 -0
  397. ksadk/server/static/assets/vbscript-D9f6rSsU.js +1 -0
  398. ksadk/server/static/assets/velocity-CqftRsjg.js +1 -0
  399. ksadk/server/static/assets/vennDiagram-CIIHVFJN-DWgwtPsJ.js +34 -0
  400. ksadk/server/static/assets/verilog-D-x6ne0Z.js +1 -0
  401. ksadk/server/static/assets/vhdl-CMrOq2q1.js +1 -0
  402. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +1 -0
  403. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-2x8G-tTM.js +78 -0
  404. ksadk/server/static/assets/webidl-D5jiJvOU.js +1 -0
  405. ksadk/server/static/assets/xquery-fj_R-kMw.js +1 -0
  406. ksadk/server/static/assets/xterm-DooSxjI5.js +36 -0
  407. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-Drma3AYl.js +7 -0
  408. ksadk/server/static/assets/yacas-CXXgtw0p.js +1 -0
  409. ksadk/server/static/assets/z80-CL1naaMV.js +1 -0
  410. ksadk/server/static/favicon.svg +1 -0
  411. ksadk/server/static/icons.svg +24 -0
  412. ksadk/server/static/index.html +14 -0
  413. ksadk/server/terminal_sessions.py +551 -0
  414. ksadk/sessions/__init__.py +279 -0
  415. ksadk/sessions/base.py +354 -0
  416. ksadk/sessions/continuity.py +337 -0
  417. ksadk/sessions/errors.py +7 -0
  418. ksadk/sessions/in_memory.py +273 -0
  419. ksadk/sessions/local_service.py +949 -0
  420. ksadk/sessions/postgres_service.py +901 -0
  421. ksadk/sessions/resilience.py +52 -0
  422. ksadk/sessions/resilient.py +360 -0
  423. ksadk/sessions/sqlite_service.py +13 -0
  424. ksadk/skills/__init__.py +9 -0
  425. ksadk/skills/loader.py +46 -0
  426. ksadk/skills/models.py +120 -0
  427. ksadk/skills/package_store.py +104 -0
  428. ksadk/skills/runtime/__init__.py +17 -0
  429. ksadk/skills/runtime/agent.py +183 -0
  430. ksadk/skills/runtime/artifacts.py +39 -0
  431. ksadk/skills/runtime/backends/__init__.py +1 -0
  432. ksadk/skills/runtime/backends/disabled.py +8 -0
  433. ksadk/skills/runtime/backends/e2b.py +168 -0
  434. ksadk/skills/runtime/backends/local.py +95 -0
  435. ksadk/skills/runtime/base.py +103 -0
  436. ksadk/skills/runtime/executor.py +219 -0
  437. ksadk/skills/runtime/factory.py +37 -0
  438. ksadk/skills/runtime/loader.py +131 -0
  439. ksadk/skills/runtime/registry.py +150 -0
  440. ksadk/skills/runtime/request.py +67 -0
  441. ksadk/skills/service_client.py +239 -0
  442. ksadk/skills/service_env.py +58 -0
  443. ksadk/skills/tool_defs.py +221 -0
  444. ksadk/terminal_client.py +69 -0
  445. ksadk/terminal_exec_policy.py +229 -0
  446. ksadk/tools/__init__.py +17 -0
  447. ksadk/tools/gateway.py +230 -0
  448. ksadk/tools/result_budget.py +154 -0
  449. ksadk/toolsets/__init__.py +854 -0
  450. ksadk/toolsets/_langchain.py +11 -0
  451. ksadk/toolsets/platform.py +93 -0
  452. ksadk/toolsets/sandbox.py +310 -0
  453. ksadk/toolsets/skills.py +217 -0
  454. ksadk/toolsets/web.py +266 -0
  455. ksadk/toolsets/workspace.py +917 -0
  456. ksadk/toolsets/workspace_state.py +44 -0
  457. ksadk/tracing/__init__.py +37 -0
  458. ksadk/tracing/exporters/__init__.py +1 -0
  459. ksadk/tracing/exporters/inmemory_exporter.py +116 -0
  460. ksadk/tracing/exporters/langfuse_exporter.py +445 -0
  461. ksadk/tracing/setup.py +892 -0
  462. ksadk/tracing/span_utils.py +114 -0
  463. ksadk/tui/__init__.py +27 -0
  464. ksadk/tui/loop.py +1877 -0
  465. ksadk/tui/stream_render.py +68 -0
  466. ksadk/ui_config.py +168 -0
  467. ksadk/version.py +4 -0
  468. ksadk_runtime_common/__init__.py +20 -0
  469. ksadk_runtime_common/memory_backend/__init__.py +29 -0
  470. ksadk_runtime_common/memory_backend/manifest.py +79 -0
  471. ksadk_runtime_common/memory_backend/providers/__init__.py +6 -0
  472. ksadk_runtime_common/memory_backend/providers/lancedb.py +151 -0
  473. ksadk_runtime_common/memory_backend/providers/mem0.py +74 -0
  474. ksadk_runtime_common/memory_backend/registry.py +56 -0
  475. ksadk_runtime_common/memory_backend/render.py +71 -0
  476. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -0
  477. ksadk_runtime_common/workspace_files/__init__.py +29 -0
  478. ksadk_runtime_common/workspace_files/bootstrap.py +56 -0
  479. ksadk_runtime_common/workspace_files/constants.py +9 -0
  480. ksadk_runtime_common/workspace_files/path_utils.py +71 -0
  481. ksadk_runtime_common/workspace_files/preview.py +96 -0
  482. ksadk_runtime_common/workspace_files/router.py +254 -0
  483. agentengine_sdk_python/__init__.py +0 -3
  484. agentengine_sdk_python-0.6.4.dist-info/METADATA +0 -48
  485. agentengine_sdk_python-0.6.4.dist-info/RECORD +0 -5
  486. agentengine_sdk_python-0.6.4.dist-info/top_level.txt +0 -1
@@ -0,0 +1,229 @@
1
+ """Shared remote terminal exec command policy."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import re
7
+ from collections.abc import Iterable, Sequence
8
+ from dataclasses import dataclass
9
+
10
+ SHELL_METACHARS = set("|&;<>()$`\\\n\r")
11
+ FORBIDDEN_LAUNCHERS = {
12
+ "bash",
13
+ "sh",
14
+ "zsh",
15
+ "fish",
16
+ "python",
17
+ "python3",
18
+ "node",
19
+ "npx",
20
+ "pnpm",
21
+ "npm",
22
+ "yarn",
23
+ "uv",
24
+ "uvx",
25
+ "hermes",
26
+ }
27
+
28
+ TERMINAL_EXEC_ALLOWLIST_ENV = "KSADK_TERMINAL_EXEC_SUBCOMMAND_ALLOWLIST"
29
+
30
+ COMMON_REMOTE_EXEC_PREFIXES: tuple[tuple[str, ...], ...] = (
31
+ ("cat",),
32
+ ("date",),
33
+ ("df",),
34
+ ("du",),
35
+ ("find",),
36
+ ("git", "diff"),
37
+ ("git", "log"),
38
+ ("git", "rev-parse"),
39
+ ("git", "show"),
40
+ ("git", "status"),
41
+ ("head",),
42
+ ("id",),
43
+ ("ls",),
44
+ ("ps",),
45
+ ("pwd",),
46
+ ("stat",),
47
+ ("tail",),
48
+ ("uname",),
49
+ ("wc",),
50
+ ("whoami",),
51
+ )
52
+
53
+
54
+ @dataclass(frozen=True)
55
+ class TerminalExecPolicy:
56
+ name: str
57
+ default_exact: tuple[tuple[str, ...], ...] = ()
58
+ default_prefixes: tuple[tuple[str, ...], ...] = ()
59
+ default_bounded_prefixes: tuple[tuple[tuple[str, ...], int, int], ...] = ()
60
+ env_names: tuple[str, ...] = (TERMINAL_EXEC_ALLOWLIST_ENV,)
61
+
62
+
63
+ GENERIC_TERMINAL_EXEC_POLICY = TerminalExecPolicy(
64
+ name="terminal",
65
+ default_prefixes=COMMON_REMOTE_EXEC_PREFIXES,
66
+ )
67
+
68
+ HERMES_TERMINAL_EXEC_POLICY = TerminalExecPolicy(
69
+ name="Hermes",
70
+ default_exact=(
71
+ ("cron", "list"),
72
+ ("cron", "status"),
73
+ ("config", "check"),
74
+ ("config", "env-path"),
75
+ ("config", "path"),
76
+ ("config", "show"),
77
+ ("doctor",),
78
+ ("gateway", "status"),
79
+ ("insights",),
80
+ ("sessions", "list"),
81
+ ("skills", "audit"),
82
+ ("skills", "check"),
83
+ ("skills", "list"),
84
+ ("status",),
85
+ ("tools", "list"),
86
+ ("version",),
87
+ ),
88
+ default_bounded_prefixes=(
89
+ (("sessions", "export"), 3, 3),
90
+ (("sessions", "show"), 3, 3),
91
+ ),
92
+ )
93
+
94
+ OPENCLAW_TERMINAL_EXEC_POLICY = TerminalExecPolicy(
95
+ name="OpenClaw",
96
+ default_prefixes=(
97
+ *COMMON_REMOTE_EXEC_PREFIXES,
98
+ ("openclaw", "channels", "login"),
99
+ ),
100
+ )
101
+
102
+ _ALLOWLIST_ENTRY_SPLIT_RE = re.compile(r"[\n;,]+")
103
+ _ALLOWLIST_TOKEN_SPLIT_RE = re.compile(r"\s+")
104
+
105
+
106
+ def normalize_exec_argv(
107
+ argv: Iterable[str],
108
+ *,
109
+ policy_name: str = "terminal",
110
+ allow_shell_metachars: bool = False,
111
+ allow_forbidden_launchers: bool = False,
112
+ ) -> list[str]:
113
+ normalized = [str(item).strip() for item in argv]
114
+ if not normalized:
115
+ raise ValueError(f"{policy_name} exec requires argv")
116
+ for index, item in enumerate(normalized):
117
+ if not item:
118
+ raise ValueError(f"{policy_name} exec argv contains an empty argument")
119
+ if not allow_shell_metachars and any(char in SHELL_METACHARS for char in item):
120
+ raise ValueError(f"{policy_name} exec does not allow shell metacharacters: {item}")
121
+ if index == 0 and item.startswith("-"):
122
+ raise ValueError(f"{policy_name} exec command is invalid: {item}")
123
+ if not allow_forbidden_launchers and index == 0 and item in FORBIDDEN_LAUNCHERS:
124
+ raise ValueError(f"{policy_name} exec launcher is not allowed: {item}")
125
+ return normalized
126
+
127
+
128
+ def validate_terminal_exec_argv(
129
+ argv: Iterable[str],
130
+ *,
131
+ policy: TerminalExecPolicy = GENERIC_TERMINAL_EXEC_POLICY,
132
+ ) -> list[str]:
133
+ if _env_allowlist_all(policy.env_names):
134
+ return normalize_exec_argv(
135
+ argv,
136
+ policy_name=policy.name,
137
+ allow_shell_metachars=True,
138
+ allow_forbidden_launchers=True,
139
+ )
140
+
141
+ normalized = normalize_exec_argv(argv, policy_name=policy.name)
142
+ allowed_exact = tuple(tuple(item) for item in policy.default_exact)
143
+ allowed_prefixes = (
144
+ tuple(tuple(item) for item in policy.default_prefixes)
145
+ + _env_allowlist_prefixes(policy.env_names, policy_name=policy.name)
146
+ )
147
+
148
+ if _matches_exact_or_prefix(
149
+ normalized,
150
+ allowed_exact=allowed_exact,
151
+ allowed_prefixes=allowed_prefixes,
152
+ allowed_bounded_prefixes=policy.default_bounded_prefixes,
153
+ ):
154
+ return normalized
155
+ suggested_prefix = normalized[0]
156
+ raise ValueError(
157
+ f"{policy.name} exec subcommand is not allowed: {' '.join(normalized)}. "
158
+ f"Set {TERMINAL_EXEC_ALLOWLIST_ENV}='{suggested_prefix}' to allow this prefix, "
159
+ f"or {TERMINAL_EXEC_ALLOWLIST_ENV}='*' to allow all remote exec commands."
160
+ )
161
+
162
+
163
+ def _env_allowlist_prefixes(
164
+ env_names: Sequence[str],
165
+ *,
166
+ policy_name: str,
167
+ ) -> tuple[tuple[str, ...], ...]:
168
+ prefixes: list[tuple[str, ...]] = []
169
+ seen: set[tuple[str, ...]] = set()
170
+ for env_name in env_names:
171
+ for prefix in _parse_allowlist_prefixes(os.getenv(env_name), policy_name=policy_name):
172
+ if prefix not in seen:
173
+ prefixes.append(prefix)
174
+ seen.add(prefix)
175
+ return tuple(prefixes)
176
+
177
+
178
+ def _env_allowlist_all(env_names: Sequence[str]) -> bool:
179
+ for env_name in env_names:
180
+ raw = os.getenv(env_name)
181
+ if not raw:
182
+ continue
183
+ for entry in _ALLOWLIST_ENTRY_SPLIT_RE.split(raw):
184
+ if entry.strip() == "*":
185
+ return True
186
+ return False
187
+
188
+
189
+ def _parse_allowlist_prefixes(raw: str | None, *, policy_name: str) -> tuple[tuple[str, ...], ...]:
190
+ if not raw:
191
+ return ()
192
+ prefixes: list[tuple[str, ...]] = []
193
+ for entry in _ALLOWLIST_ENTRY_SPLIT_RE.split(raw):
194
+ entry = entry.strip()
195
+ if not entry:
196
+ continue
197
+ if entry == "*":
198
+ continue
199
+ tokens = tuple(token for token in _ALLOWLIST_TOKEN_SPLIT_RE.split(entry) if token)
200
+ normalize_exec_argv(tokens, policy_name=policy_name)
201
+ prefixes.append(tokens)
202
+ return tuple(prefixes)
203
+
204
+
205
+ def _matches_exact_or_prefix(
206
+ argv: Sequence[str],
207
+ *,
208
+ allowed_exact: Sequence[Sequence[str]],
209
+ allowed_prefixes: Sequence[Sequence[str]],
210
+ allowed_bounded_prefixes: Sequence[tuple[Sequence[str], int, int]],
211
+ ) -> bool:
212
+ argv_tuple = tuple(argv)
213
+ for item in allowed_exact:
214
+ if argv_tuple == tuple(item):
215
+ return True
216
+ for prefix in allowed_prefixes:
217
+ prefix_tuple = tuple(prefix)
218
+ if prefix_tuple and argv_tuple[: len(prefix_tuple)] == prefix_tuple:
219
+ return True
220
+ for prefix, min_len, max_len in allowed_bounded_prefixes:
221
+ prefix_tuple = tuple(prefix)
222
+ if (
223
+ prefix_tuple
224
+ and argv_tuple[: len(prefix_tuple)] == prefix_tuple
225
+ and len(argv_tuple) >= min_len
226
+ and len(argv_tuple) <= max_len
227
+ ):
228
+ return True
229
+ return False
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from ksadk.tools.gateway import (
4
+ ToolGateway,
5
+ ToolPolicy,
6
+ approval_interrupt_info_from_result,
7
+ check_command_policy,
8
+ default_tool_gateway,
9
+ )
10
+
11
+ __all__ = [
12
+ "ToolGateway",
13
+ "ToolPolicy",
14
+ "approval_interrupt_info_from_result",
15
+ "check_command_policy",
16
+ "default_tool_gateway",
17
+ ]
ksadk/tools/gateway.py ADDED
@@ -0,0 +1,230 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import hashlib
5
+ import json
6
+ import shlex
7
+ from collections.abc import Callable, Mapping, Sequence
8
+ from dataclasses import dataclass, field
9
+ from typing import Any
10
+ from uuid import uuid4
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class ToolPolicy:
15
+ risk_level: str = "low"
16
+ side_effects: Sequence[str] = field(default_factory=tuple)
17
+ requires_approval: bool | None = None
18
+
19
+
20
+ _READ_ONLY_GIT_COMMANDS = {"status", "diff", "log", "show", "branch", "ls-files"}
21
+ _DANGEROUS_COMMAND_TOKENS = {
22
+ "sudo",
23
+ "kubectl",
24
+ "docker",
25
+ }
26
+ _DANGEROUS_GIT_COMMANDS = {"reset", "clean", "push", "checkout"}
27
+
28
+
29
+ class ToolGateway:
30
+ def __init__(self, policies: Mapping[str, ToolPolicy] | None = None):
31
+ self._policies = dict(policies or {})
32
+
33
+ def invoke(
34
+ self,
35
+ tool_name: str,
36
+ func: Callable[..., Any],
37
+ *args: Any,
38
+ approval: Mapping[str, Any] | None = None,
39
+ **kwargs: Any,
40
+ ) -> Any:
41
+ policy = self._policies.get(tool_name, ToolPolicy())
42
+ if self._is_rejected(approval):
43
+ return self._approval_rejected(tool_name, policy, approval)
44
+ if self._is_approved(approval) or not self._requires_approval(policy):
45
+ return func(*args, **kwargs)
46
+ return self._approval_required(tool_name, policy)
47
+
48
+ def _requires_approval(self, policy: ToolPolicy) -> bool:
49
+ return tool_policy_requires_approval(policy, approval_mode=self._approval_mode())
50
+
51
+ @staticmethod
52
+ def _approval_mode() -> str:
53
+ value = os.environ.get("KSADK_TOOL_APPROVAL_MODE", "").strip().lower()
54
+ return value or "off"
55
+
56
+ @staticmethod
57
+ def _is_approved(approval: Mapping[str, Any] | None) -> bool:
58
+ if not approval:
59
+ return False
60
+ return bool(approval.get("approved") or approval.get("approve"))
61
+
62
+ @staticmethod
63
+ def _is_rejected(approval: Mapping[str, Any] | None) -> bool:
64
+ if not approval:
65
+ return False
66
+ if "approved" in approval:
67
+ return not bool(approval.get("approved"))
68
+ if "approve" in approval:
69
+ return not bool(approval.get("approve"))
70
+ return False
71
+
72
+ @staticmethod
73
+ def _approval_required(tool_name: str, policy: ToolPolicy) -> dict[str, Any]:
74
+ return {
75
+ "ok": False,
76
+ "type": "approval_required",
77
+ "approval_required": True,
78
+ "approval_request": {
79
+ "id": f"appr_{uuid4().hex}",
80
+ "tool_name": tool_name,
81
+ "risk_level": policy.risk_level,
82
+ "side_effects": list(policy.side_effects),
83
+ },
84
+ }
85
+
86
+ @staticmethod
87
+ def _approval_rejected(
88
+ tool_name: str,
89
+ policy: ToolPolicy,
90
+ approval: Mapping[str, Any] | None,
91
+ ) -> dict[str, Any]:
92
+ return {
93
+ "ok": False,
94
+ "type": "approval_rejected",
95
+ "approval_required": False,
96
+ "tool_name": tool_name,
97
+ "risk_level": policy.risk_level,
98
+ "reason": str((approval or {}).get("reason") or ""),
99
+ }
100
+
101
+
102
+ def default_tool_gateway(policies: Mapping[str, ToolPolicy] | None = None) -> ToolGateway:
103
+ return ToolGateway(policies)
104
+
105
+
106
+ def tool_policy_requires_approval(
107
+ policy: ToolPolicy,
108
+ *,
109
+ approval_mode: str | None = None,
110
+ ) -> bool:
111
+ mode = (approval_mode or os.environ.get("KSADK_TOOL_APPROVAL_MODE", "")).strip().lower() or "off"
112
+ if policy.requires_approval is not None:
113
+ return policy.requires_approval and mode != "off"
114
+ if mode != "strict":
115
+ return False
116
+ return policy.risk_level.lower() in {"medium", "high", "critical"}
117
+
118
+
119
+ def check_command_policy(command: str) -> dict[str, Any]:
120
+ text = str(command or "").strip()
121
+ if not text:
122
+ return {"ok": False, "decision": "reject", "error_type": "command_required", "error_message": "command is required"}
123
+ try:
124
+ tokens = shlex.split(text)
125
+ except ValueError as exc:
126
+ return {"ok": False, "decision": "reject", "error_type": "invalid_command", "error_message": str(exc)}
127
+ if not tokens:
128
+ return {"ok": False, "decision": "reject", "error_type": "command_required", "error_message": "command is required"}
129
+ if _contains_recursive_rm(tokens):
130
+ return _command_rejected("recursive rm is not allowed without explicit approval")
131
+ if any(token in _DANGEROUS_COMMAND_TOKENS for token in tokens):
132
+ return _command_rejected(f"{tokens[0]} command is not allowed by default policy")
133
+ if tokens[0] == "git" and len(tokens) > 1:
134
+ subcommand = tokens[1]
135
+ if subcommand in _READ_ONLY_GIT_COMMANDS:
136
+ return {"ok": True, "decision": "allow", "reason": "read_only_git"}
137
+ if subcommand in _DANGEROUS_GIT_COMMANDS:
138
+ return _command_rejected(f"git {subcommand} is not allowed without explicit approval")
139
+ if _references_metadata_endpoint(tokens):
140
+ return _command_rejected("metadata/private endpoint access is not allowed by default policy")
141
+ return {"ok": True, "decision": "allow", "reason": "default_allow"}
142
+
143
+
144
+ def _command_rejected(message: str) -> dict[str, Any]:
145
+ return {"ok": False, "decision": "reject", "error_type": "command_rejected", "error_message": message}
146
+
147
+
148
+ def _contains_recursive_rm(tokens: Sequence[str]) -> bool:
149
+ for index, token in enumerate(tokens[:-1]):
150
+ if token == "rm" and any(
151
+ flag.startswith("-") and ("r" in flag or "R" in flag)
152
+ for flag in tokens[index + 1 : index + 3]
153
+ ):
154
+ return True
155
+ return False
156
+
157
+
158
+ def _references_metadata_endpoint(tokens: Sequence[str]) -> bool:
159
+ joined = " ".join(tokens)
160
+ return "169.254.169.254" in joined or "metadata.google.internal" in joined
161
+
162
+
163
+ def _canonical_tool_args(tool_args: Any) -> str:
164
+ try:
165
+ return json.dumps(tool_args or {}, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
166
+ except TypeError:
167
+ return json.dumps(str(tool_args), ensure_ascii=False, separators=(",", ":"))
168
+
169
+
170
+ def build_tool_receipt_idempotency_key(
171
+ *,
172
+ session_id: str,
173
+ run_id: str,
174
+ checkpoint_id: str | None = None,
175
+ tool_call_id: str | None = None,
176
+ tool_name: str,
177
+ tool_args: Any = None,
178
+ ) -> str:
179
+ payload = {
180
+ "session_id": str(session_id or ""),
181
+ "run_id": str(run_id or ""),
182
+ "checkpoint_id": str(checkpoint_id or ""),
183
+ "tool_call_id": str(tool_call_id or ""),
184
+ "tool_name": str(tool_name or ""),
185
+ "tool_args": _canonical_tool_args(tool_args),
186
+ }
187
+ digest = hashlib.sha256(
188
+ json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")
189
+ ).hexdigest()
190
+ return f"tool_receipt:{digest}"
191
+
192
+
193
+ def approval_interrupt_info_from_result(
194
+ result: Any,
195
+ *,
196
+ fallback_tool_name: str = "tool",
197
+ tool_args: Any = None,
198
+ run_id: str | None = None,
199
+ ) -> dict[str, Any] | None:
200
+ if not isinstance(result, Mapping):
201
+ return None
202
+ if str(result.get("type") or "") != "approval_required":
203
+ return None
204
+ approval_request = result.get("approval_request")
205
+ if not isinstance(approval_request, Mapping):
206
+ return None
207
+
208
+ request_id = str(
209
+ approval_request.get("approval_request_id")
210
+ or approval_request.get("id")
211
+ or f"appr_{uuid4().hex}"
212
+ )
213
+ interrupt = {
214
+ "id": request_id,
215
+ "approval_request_id": request_id,
216
+ "tool_name": str(approval_request.get("tool_name") or fallback_tool_name or "tool"),
217
+ "arguments": (
218
+ approval_request.get("arguments")
219
+ or approval_request.get("tool_args")
220
+ or approval_request.get("args")
221
+ or tool_args
222
+ or {}
223
+ ),
224
+ "risk_level": str(approval_request.get("risk_level") or result.get("risk_level") or ""),
225
+ "side_effects": list(approval_request.get("side_effects") or result.get("side_effects") or []),
226
+ "server_label": str(approval_request.get("server_label") or result.get("server_label") or "ksadk"),
227
+ }
228
+ if run_id:
229
+ interrupt["run_id"] = str(run_id)
230
+ return interrupt
@@ -0,0 +1,154 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import re
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import Any
9
+ from uuid import uuid4
10
+
11
+ from ksadk.sessions.local_service import resolve_local_session_dir
12
+
13
+
14
+ _SAFE_NAME_RE = re.compile(r"[^A-Za-z0-9_.-]+")
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class ToolResultBudget:
19
+ max_chars: int = 50_000
20
+ preview_chars: int = 8_000
21
+ persist_threshold_chars: int = 50_000
22
+ persist_dir: Path | str | None = None
23
+
24
+ @property
25
+ def resolved_persist_dir(self) -> Path:
26
+ if self.persist_dir is not None:
27
+ return Path(self.persist_dir).expanduser().resolve()
28
+ configured = os.environ.get("KSADK_TOOL_RESULT_DIR", "").strip()
29
+ if configured:
30
+ return Path(configured).expanduser().resolve()
31
+ return (resolve_local_session_dir() / "tool-results").resolve()
32
+
33
+
34
+ def default_tool_result_budget(
35
+ *,
36
+ max_chars: int | None = None,
37
+ preview_chars: int | None = None,
38
+ persist_threshold_chars: int | None = None,
39
+ ) -> ToolResultBudget:
40
+ return ToolResultBudget(
41
+ max_chars=_int_env("KSADK_TOOL_RESULT_MAX_CHARS", max_chars or 50_000),
42
+ preview_chars=_int_env("KSADK_TOOL_RESULT_PREVIEW_CHARS", preview_chars or 8_000),
43
+ persist_threshold_chars=_int_env(
44
+ "KSADK_TOOL_RESULT_PERSIST_THRESHOLD_CHARS",
45
+ persist_threshold_chars or max_chars or 50_000,
46
+ ),
47
+ )
48
+
49
+
50
+ def budget_tool_output(
51
+ *,
52
+ tool_name: str,
53
+ field_name: str,
54
+ value: Any,
55
+ metadata: dict[str, Any] | None = None,
56
+ budget: ToolResultBudget | None = None,
57
+ ) -> dict[str, Any]:
58
+ active_budget = budget or default_tool_result_budget()
59
+ text, mime_type, extension = _stringify_value(value)
60
+ original_chars = len(text)
61
+ should_persist = original_chars > active_budget.persist_threshold_chars or original_chars > active_budget.max_chars
62
+ preview_limit = max(0, min(active_budget.preview_chars, active_budget.max_chars))
63
+ preview = text[:preview_limit] if should_persist else text[: active_budget.max_chars]
64
+ result: dict[str, Any] = {
65
+ field_name: preview,
66
+ "truncated": original_chars > len(preview),
67
+ "original_chars": original_chars,
68
+ "preview_chars": len(preview),
69
+ }
70
+ if should_persist:
71
+ path = _persist_tool_output(
72
+ tool_name=tool_name,
73
+ field_name=field_name,
74
+ text=text,
75
+ extension=extension,
76
+ metadata=metadata or {},
77
+ budget=active_budget,
78
+ )
79
+ result["persisted"] = {"path": str(path), "mime_type": mime_type}
80
+ return result
81
+
82
+
83
+ def budget_text_fields(
84
+ payload: dict[str, Any],
85
+ *,
86
+ tool_name: str,
87
+ fields: tuple[str, ...],
88
+ metadata: dict[str, Any] | None = None,
89
+ budget: ToolResultBudget | None = None,
90
+ ) -> dict[str, Any]:
91
+ updated = dict(payload)
92
+ for field in fields:
93
+ if field not in updated:
94
+ continue
95
+ budgeted = budget_tool_output(
96
+ tool_name=tool_name,
97
+ field_name=field,
98
+ value=updated[field],
99
+ metadata={**(metadata or {}), "field_name": field},
100
+ budget=budget,
101
+ )
102
+ updated[field] = budgeted[field]
103
+ for key in ("truncated", "original_chars", "preview_chars", "persisted"):
104
+ if key in budgeted:
105
+ if key == "persisted":
106
+ updated.setdefault("persisted_outputs", {})[field] = budgeted[key]
107
+ else:
108
+ updated[f"{field}_{key}"] = budgeted[key]
109
+ return updated
110
+
111
+
112
+ def _persist_tool_output(
113
+ *,
114
+ tool_name: str,
115
+ field_name: str,
116
+ text: str,
117
+ extension: str,
118
+ metadata: dict[str, Any],
119
+ budget: ToolResultBudget,
120
+ ) -> Path:
121
+ persist_dir = budget.resolved_persist_dir
122
+ persist_dir.mkdir(parents=True, exist_ok=True)
123
+ tool_use_id = str(
124
+ metadata.get("tool_use_id")
125
+ or metadata.get("tool_call_id")
126
+ or metadata.get("id")
127
+ or uuid4().hex
128
+ )
129
+ stem = _safe_filename(f"{tool_use_id}.{field_name}") or _safe_filename(f"{tool_name}.{field_name}.{uuid4().hex}")
130
+ path = (persist_dir / f"{stem}.{extension}").resolve()
131
+ if persist_dir not in path.parents and path != persist_dir:
132
+ raise ValueError("tool result path must stay inside persist_dir")
133
+ path.write_text(text, encoding="utf-8")
134
+ return path
135
+
136
+
137
+ def _stringify_value(value: Any) -> tuple[str, str, str]:
138
+ if isinstance(value, str):
139
+ return value, "text/plain", "txt"
140
+ return json.dumps(value, ensure_ascii=False, indent=2, sort_keys=True), "application/json", "json"
141
+
142
+
143
+ def _safe_filename(value: str) -> str:
144
+ return _SAFE_NAME_RE.sub("_", value.strip()).strip("._")
145
+
146
+
147
+ def _int_env(name: str, default: int) -> int:
148
+ raw = os.environ.get(name)
149
+ if raw is None:
150
+ return int(default)
151
+ try:
152
+ return max(0, int(raw))
153
+ except ValueError:
154
+ return int(default)