agentengine-sdk-python 0.6.9__py3-none-any.whl → 0.8.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 (384) hide show
  1. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +41 -23
  2. agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
  3. ksadk/a2a/__init__.py +178 -11
  4. ksadk/a2a/bootstrap.py +334 -0
  5. ksadk/a2a/card.py +120 -0
  6. ksadk/a2a/context_store.py +203 -0
  7. ksadk/a2a/control_plane.py +818 -0
  8. ksadk/a2a/credential.py +99 -0
  9. ksadk/a2a/event_adapter.py +149 -0
  10. ksadk/a2a/executor.py +406 -89
  11. ksadk/a2a/external_transport.py +516 -0
  12. ksadk/a2a/identity.py +304 -0
  13. ksadk/a2a/ids.py +22 -0
  14. ksadk/a2a/langgraph.py +285 -0
  15. ksadk/a2a/resume_store.py +201 -0
  16. ksadk/a2a/routes.py +105 -0
  17. ksadk/a2a/server.py +107 -60
  18. ksadk/a2a/space_client.py +1101 -0
  19. ksadk/a2a/task_adapter.py +423 -0
  20. ksadk/a2a/task_event_dispatcher.py +167 -0
  21. ksadk/a2a/task_event_outbox.py +326 -0
  22. ksadk/a2a/task_store.py +206 -0
  23. ksadk/a2ui/__init__.py +27 -0
  24. ksadk/a2ui/core.py +186 -0
  25. ksadk/a2ui/models.py +166 -0
  26. ksadk/a2ui/renderer.py +198 -0
  27. ksadk/agui/__init__.py +9 -0
  28. ksadk/agui/a2ui_projection.py +92 -0
  29. ksadk/agui/agent.py +857 -0
  30. ksadk/agui/config.py +86 -0
  31. ksadk/agui/routes.py +55 -0
  32. ksadk/api/client.py +252 -191
  33. ksadk/builders/__init__.py +2 -0
  34. ksadk/builders/base.py +16 -14
  35. ksadk/builders/code_builder.py +318 -236
  36. ksadk/builders/container_builder.py +187 -167
  37. ksadk/builders/framework_requirements.py +29 -11
  38. ksadk/builders/ks3_uploader.py +58 -27
  39. ksadk/builders/managed_runtime_builder.py +145 -0
  40. ksadk/builders/mcp_builder.py +91 -92
  41. ksadk/builders/requirements_utils.py +1 -5
  42. ksadk/cli/__init__.py +89 -171
  43. ksadk/cli/cmd_a2a.py +254 -70
  44. ksadk/cli/cmd_agent.py +19 -5
  45. ksadk/cli/cmd_build.py +158 -29
  46. ksadk/cli/cmd_completion.py +47 -35
  47. ksadk/cli/cmd_config.py +267 -198
  48. ksadk/cli/cmd_create.py +533 -726
  49. ksadk/cli/cmd_dashboard.py +120 -45
  50. ksadk/cli/cmd_deploy.py +117 -58
  51. ksadk/cli/cmd_destroy.py +44 -14
  52. ksadk/cli/cmd_files.py +63 -24
  53. ksadk/cli/cmd_hermes.py +173 -90
  54. ksadk/cli/cmd_invoke.py +388 -159
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +103 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +488 -228
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +44 -14
  61. ksadk/cli/cmd_status.py +80 -31
  62. ksadk/cli/cmd_version.py +20 -13
  63. ksadk/cli/cmd_web.py +89 -13
  64. ksadk/cli/deploy_utils.py +20 -20
  65. ksadk/cli/dry_run.py +5 -3
  66. ksadk/cli/error_utils.py +37 -12
  67. ksadk/cli/global_options.py +1 -2
  68. ksadk/cli/local_runtime.py +1 -2
  69. ksadk/cli/model_catalog.py +6 -2
  70. ksadk/cli/network_options.py +38 -16
  71. ksadk/cli/resource_common.py +6 -2
  72. ksadk/cli/storage.py +0 -1
  73. ksadk/cli/ui.py +5 -3
  74. ksadk/cli/workflow_common.py +51 -17
  75. ksadk/codex/__init__.py +12 -0
  76. ksadk/codex/client.py +408 -0
  77. ksadk/codex/phase.py +143 -0
  78. ksadk/codex/runtime.py +449 -0
  79. ksadk/common/aicp_env.py +0 -1
  80. ksadk/common/auth.py +2 -2
  81. ksadk/common/constants.py +1 -3
  82. ksadk/common/llm_utils.py +17 -13
  83. ksadk/compat/__init__.py +5 -0
  84. ksadk/compat/adk_compat.py +200 -0
  85. ksadk/compat/copilotkit_a2ui.py +330 -0
  86. ksadk/configs/__init__.py +12 -12
  87. ksadk/configs/env_registry.py +501 -100
  88. ksadk/configs/global_config.py +2 -1
  89. ksadk/configs/settings.py +151 -124
  90. ksadk/conversations/__init__.py +7 -5
  91. ksadk/conversations/attachment_storage.py +16 -11
  92. ksadk/conversations/attachments.py +44 -36
  93. ksadk/conversations/compaction_pipeline.py +12 -12
  94. ksadk/conversations/compaction_prompt.py +9 -5
  95. ksadk/conversations/context.py +221 -6
  96. ksadk/conversations/message_projection.py +656 -0
  97. ksadk/conversations/model_context.py +22 -6
  98. ksadk/conversations/model_options.py +0 -1
  99. ksadk/conversations/normalize.py +20 -16
  100. ksadk/conversations/reasoning_markup.py +1 -1
  101. ksadk/conversations/runtime.py +339 -5187
  102. ksadk/conversations/runtime_compaction.py +333 -0
  103. ksadk/conversations/runtime_constants.py +27 -0
  104. ksadk/conversations/runtime_governance.py +185 -0
  105. ksadk/conversations/runtime_input.py +652 -0
  106. ksadk/conversations/runtime_invocation.py +395 -0
  107. ksadk/conversations/runtime_metadata.py +475 -0
  108. ksadk/conversations/runtime_observability.py +355 -0
  109. ksadk/conversations/runtime_payloads.py +272 -0
  110. ksadk/conversations/runtime_persistence.py +440 -0
  111. ksadk/conversations/runtime_preparation.py +418 -0
  112. ksadk/conversations/runtime_resume.py +816 -0
  113. ksadk/conversations/runtime_stream_events.py +902 -0
  114. ksadk/conversations/runtime_streaming.py +547 -0
  115. ksadk/conversations/semantic_summary.py +17 -5
  116. ksadk/conversations/session_title.py +6 -3
  117. ksadk/deployment/__init__.py +15 -16
  118. ksadk/deployment/agent_access.py +12 -23
  119. ksadk/deployment/base.py +52 -39
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +326 -209
  122. ksadk/deployment/registry.py +38 -32
  123. ksadk/deployment/state.py +11 -11
  124. ksadk/deployment/ui_config.py +1 -1
  125. ksadk/detection/__init__.py +1 -1
  126. ksadk/detection/detector.py +146 -83
  127. ksadk/detection/mcp_detector.py +9 -6
  128. ksadk/events/__init__.py +25 -0
  129. ksadk/events/parser.py +191 -0
  130. ksadk/events/replay.py +37 -0
  131. ksadk/events/runtime_event.py +264 -0
  132. ksadk/events/store.py +317 -0
  133. ksadk/harness/__init__.py +34 -0
  134. ksadk/harness/app.py +278 -0
  135. ksadk/harness/config.py +181 -0
  136. ksadk/harness/reasoner.py +105 -0
  137. ksadk/harness/runner.py +211 -0
  138. ksadk/harness/sandbox.py +141 -0
  139. ksadk/harness/tools.py +222 -0
  140. ksadk/hermes_terminal.py +23 -12
  141. ksadk/identity/resolver.py +15 -9
  142. ksadk/ids.py +32 -0
  143. ksadk/knowledge_base/adk_tool.py +1 -1
  144. ksadk/knowledge_base/client.py +23 -29
  145. ksadk/managed_runtime.py +188 -0
  146. ksadk/markdown.py +5 -2
  147. ksadk/mcp_runtime/__init__.py +9 -6
  148. ksadk/memory/__init__.py +1 -1
  149. ksadk/memory/adk/__init__.py +2 -0
  150. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  151. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  152. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  153. ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
  154. ksadk/memory/adk/long_term_memory.py +31 -35
  155. ksadk/memory/adk/resilient_session_service.py +267 -0
  156. ksadk/memory/adk/short_term_memory.py +33 -27
  157. ksadk/memory/adk_tool.py +3 -2
  158. ksadk/memory/backends/base.py +19 -19
  159. ksadk/memory/backends/memory.py +24 -25
  160. ksadk/memory/backends/redis.py +31 -30
  161. ksadk/memory/langchain_tool.py +2 -1
  162. ksadk/memory/manager.py +52 -47
  163. ksadk/memory/service.py +10 -8
  164. ksadk/model_policy.py +15 -7
  165. ksadk/model_proxy/__init__.py +51 -0
  166. ksadk/model_proxy/bootstrap.py +80 -0
  167. ksadk/model_proxy/cache.py +165 -0
  168. ksadk/model_proxy/config.py +45 -0
  169. ksadk/model_proxy/demo_webui.py +115 -0
  170. ksadk/model_proxy/detect.py +145 -0
  171. ksadk/model_proxy/gate.py +68 -0
  172. ksadk/model_proxy/namespace.py +173 -0
  173. ksadk/model_proxy/protocol_proxy.py +22 -0
  174. ksadk/model_proxy/server.py +300 -0
  175. ksadk/model_proxy/transform.py +691 -0
  176. ksadk/openclaw_gateway.py +29 -14
  177. ksadk/runners/adk_runner.py +1248 -164
  178. ksadk/runners/base_runner.py +46 -29
  179. ksadk/runners/codex_runner.py +132 -0
  180. ksadk/runners/deepagents_runner.py +0 -1
  181. ksadk/runners/factory.py +17 -5
  182. ksadk/runners/langchain_runner.py +29 -530
  183. ksadk/runners/langgraph_runner.py +490 -95
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +264 -38
  186. ksadk/runners/usage_accumulator.py +1 -0
  187. ksadk/runners/utils/langfuse.py +3 -3
  188. ksadk/runners/utils/loader.py +7 -7
  189. ksadk/runtime/__init__.py +41 -0
  190. ksadk/runtime/adapter.py +345 -0
  191. ksadk/runtime/framework_adapters.py +124 -0
  192. ksadk/runtime/preprocessing.py +118 -0
  193. ksadk/runtime/runner_adapter.py +873 -0
  194. ksadk/runtime_context.py +18 -3
  195. ksadk/runtime_state.py +0 -1
  196. ksadk/sandbox/__init__.py +4 -1
  197. ksadk/sandbox/backends/__init__.py +4 -1
  198. ksadk/sandbox/backends/e2b.py +13 -5
  199. ksadk/sandbox/backends/local_process.py +11 -3
  200. ksadk/sandbox/base.py +10 -15
  201. ksadk/sandbox/factory.py +14 -4
  202. ksadk/sandbox/registry.py +57 -6
  203. ksadk/server/api_models.py +15 -5
  204. ksadk/server/app.py +455 -3743
  205. ksadk/server/composition.py +21 -0
  206. ksadk/server/factory.py +624 -0
  207. ksadk/server/routes/__init__.py +1 -0
  208. ksadk/server/routes/checkpoint_resolution.py +116 -0
  209. ksadk/server/routes/common.py +713 -0
  210. ksadk/server/routes/control.py +327 -0
  211. ksadk/server/routes/dependencies.py +98 -0
  212. ksadk/server/routes/misc.py +448 -0
  213. ksadk/server/routes/models.py +443 -0
  214. ksadk/server/routes/openai_compat.py +207 -0
  215. ksadk/server/routes/projection.py +795 -0
  216. ksadk/server/routes/routers.py +52 -0
  217. ksadk/server/routes/run.py +726 -0
  218. ksadk/server/routes/sessions.py +649 -0
  219. ksadk/server/routes/streaming.py +223 -0
  220. ksadk/server/routes/workspace.py +381 -0
  221. ksadk/server/static/assets/{ArtifactsPanel-C0meuOdi.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
  222. ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
  224. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
  226. ksadk/server/static/assets/{arc-bj2rZnP5.js → arc-CFKwSk_B.js} +1 -1
  227. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
  228. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-2u1ltDIj.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-D6fvdK20.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-BK82L5n5.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-DLVdkeyQ.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-BbwsYcbW.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-DOairxzw.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-hCO487gs.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-XU8vDOuG.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-PrapyfMu.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-CboKhTZ3.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
  239. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
  240. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
  241. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
  242. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-_N8bJ-EU.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-FoDlo5J2.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BBp6ebBw.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-CqOvG1PR.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-O9T3t6ba.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-CGG8ekBO.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-4BmH1EEg.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-CiZHB6ZW.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-BMKM66B4.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-CZ6C3x8B.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DbaH3p5h.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-BVzcWa6D.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-D99wf6_X.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-DLMjL01k.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-DI-oVAXw.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-BkJjNih3.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-D5JGcxBx.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-CWiTDN_V.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-DLeM1OCK.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-BmuTWcm7.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-C2DKRFVK.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-B67uF2uK.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-Cwhk4lwI.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-S4klkK5W.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DCpZrjaK.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-Cp1_jKwf.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-6kSZvCZh.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-DM0rEQPk.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-Bk1l05Ni.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-oJhaci7S.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
  272. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
  273. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-DtTmUan-.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BSsb_eij.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
  275. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
  276. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-BR5s6Pws.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
  277. ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
  278. ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
  279. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
  280. ksadk/server/static/assets/{infoDiagram-5YYISTIA-DYPc5cvh.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-MoBdALDg.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-DgLiQT8l.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-CsFx112F.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DRsiwpM2.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-TNRQ5Orv.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-D2eMVOgo.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-BtByYFhL.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
  288. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
  289. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
  290. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPnuCB8c.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-miFpCPv4.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
  292. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
  293. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-mjB_yYkW.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-D7hSlZZZ.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-D9Cx6hC3.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-D_zrg47o.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
  297. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
  298. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-CwSec0Wa.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
  299. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
  300. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
  301. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-agCVobiF.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
  302. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
  303. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-TmrlhWNt.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-DV71V-ah.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
  305. ksadk/server/static/index.html +2 -2
  306. ksadk/server/terminal_sessions.py +111 -58
  307. ksadk/sessions/__init__.py +86 -40
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +28 -5
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +216 -35
  313. ksadk/sessions/resilience.py +52 -0
  314. ksadk/sessions/resilient.py +388 -0
  315. ksadk/skills/models.py +17 -5
  316. ksadk/skills/package_store.py +5 -2
  317. ksadk/skills/runtime/agent.py +20 -5
  318. ksadk/skills/runtime/artifacts.py +1 -5
  319. ksadk/skills/runtime/backends/e2b.py +10 -4
  320. ksadk/skills/runtime/backends/local.py +15 -3
  321. ksadk/skills/runtime/base.py +1 -2
  322. ksadk/skills/runtime/executor.py +10 -3
  323. ksadk/skills/runtime/factory.py +4 -2
  324. ksadk/skills/runtime/loader.py +1 -2
  325. ksadk/skills/runtime/registry.py +15 -10
  326. ksadk/skills/runtime/request.py +3 -1
  327. ksadk/skills/service_client.py +38 -17
  328. ksadk/skills/tool_defs.py +15 -10
  329. ksadk/terminal_exec_policy.py +3 -4
  330. ksadk/tools/gateway.py +92 -15
  331. ksadk/tools/result_budget.py +12 -4
  332. ksadk/toolsets/__init__.py +136 -36
  333. ksadk/toolsets/platform.py +21 -5
  334. ksadk/toolsets/sandbox.py +82 -16
  335. ksadk/toolsets/skills.py +200 -39
  336. ksadk/toolsets/web.py +123 -26
  337. ksadk/toolsets/workspace.py +264 -114
  338. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  339. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  340. ksadk/tracing/setup.py +132 -53
  341. ksadk/tracing/span_utils.py +5 -2
  342. ksadk/tui/__init__.py +22 -7
  343. ksadk/tui/loop.py +1925 -0
  344. ksadk/tui/stream_render.py +69 -0
  345. ksadk/ui_config.py +5 -3
  346. ksadk/version.py +1 -1
  347. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  348. agentengine_sdk_python-0.6.9.dist-info/RECORD +0 -487
  349. ksadk/server/static/assets/CodeBlock-BbI4HPtJ.js +0 -9
  350. ksadk/server/static/assets/MathMessageMarkdown-DMLQYoLp.js +0 -8
  351. ksadk/server/static/assets/MermaidBlock-DCR8WZ17.js +0 -303
  352. ksadk/server/static/assets/NativeTerminalPanel-CKUvWhUz.js +0 -1
  353. ksadk/server/static/assets/architecture-7EHR7CIX-Cr6Xz1_c.js +0 -1
  354. ksadk/server/static/assets/channel-BSSOwFIb.js +0 -1
  355. ksadk/server/static/assets/chunk-QZHKN3VN-XXpdiwUL.js +0 -1
  356. ksadk/server/static/assets/classDiagram-4FO5ZUOK-C5HvGiyK.js +0 -1
  357. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-C5HvGiyK.js +0 -1
  358. ksadk/server/static/assets/eventmodeling-FCH6USID-CIgwHJLL.js +0 -1
  359. ksadk/server/static/assets/gitGraph-WXDBUCRP-BVAJ7uo0.js +0 -1
  360. ksadk/server/static/assets/index-BH7-pC0B.js +0 -165
  361. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  362. ksadk/server/static/assets/info-J43DQDTF-MT80V4ge.js +0 -1
  363. ksadk/server/static/assets/packet-YPE3B663-BLKhbXZB.js +0 -1
  364. ksadk/server/static/assets/pie-LRSECV5Y-DFOikjSY.js +0 -1
  365. ksadk/server/static/assets/radar-GUYGQ44K-095b1Ikw.js +0 -1
  366. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-J9kCb0nC.js +0 -1
  367. ksadk/server/static/assets/treeView-BLDUP644-yinfJEY6.js +0 -1
  368. ksadk/server/static/assets/treemap-LRROVOQU-DosUqN1Q.js +0 -1
  369. ksadk/server/static/assets/wardley-L42UT6IY-Bvp7-5uH.js +0 -1
  370. ksadk/tui/app.py +0 -400
  371. ksadk/tui/clipboard.py +0 -100
  372. ksadk/tui/widgets/__init__.py +0 -22
  373. ksadk/tui/widgets/assistant.py +0 -89
  374. ksadk/tui/widgets/base.py +0 -54
  375. ksadk/tui/widgets/chat_input.py +0 -246
  376. ksadk/tui/widgets/history.py +0 -156
  377. ksadk/tui/widgets/system.py +0 -87
  378. ksadk/tui/widgets/thinking.py +0 -110
  379. ksadk/tui/widgets/tool_call.py +0 -161
  380. ksadk/tui/widgets/user.py +0 -37
  381. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  382. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  383. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  384. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,388 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import logging
5
+ from typing import Any, Optional, cast
6
+
7
+ from ksadk.sessions.base import BaseSessionService, Session, SessionEvent, SessionState
8
+ from ksadk.sessions.in_memory import InMemorySessionService
9
+ from ksadk.sessions.resilience import is_session_backend_failure
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class ResilientSessionService(BaseSessionService):
15
+ """Keep live agent sessions available when durable persistence is unavailable.
16
+
17
+ The in-memory service is authoritative for the lifetime of this process. The
18
+ configured durable service is used as a read-through source and a best-effort
19
+ write-through sink. After its first failure it stays disabled until a
20
+ background probe confirms the durable backend is reachable again, at which
21
+ point it is re-enabled and an INFO log is emitted.
22
+ """
23
+
24
+ _probe_interval_seconds: float = 30.0
25
+
26
+ def __init__(
27
+ self,
28
+ primary: BaseSessionService,
29
+ fallback: InMemorySessionService | None = None,
30
+ ) -> None:
31
+ self.primary = primary
32
+ self.fallback = fallback or InMemorySessionService()
33
+ self._primary_enabled = True
34
+ self._hydrate_lock = asyncio.Lock()
35
+ self._primary_session_lock = asyncio.Lock()
36
+ self._primary_session_ids: set[str] = set()
37
+ self._probe_task: asyncio.Task[None] | None = None
38
+
39
+ @property
40
+ def degraded(self) -> bool:
41
+ return not self._primary_enabled
42
+
43
+ async def _call_primary(self, method_name: str, *args: Any, **kwargs: Any) -> tuple[bool, Any]:
44
+ if not self._primary_enabled:
45
+ return False, None
46
+ try:
47
+ method = getattr(self.primary, method_name)
48
+ return True, await method(*args, **kwargs)
49
+ except Exception as exc:
50
+ if not is_session_backend_failure(exc):
51
+ raise
52
+ self._disable_primary(exc)
53
+ return False, None
54
+
55
+ def _disable_primary(self, exc: Exception) -> None:
56
+ if not self._primary_enabled:
57
+ return
58
+ self._primary_enabled = False
59
+ logger.error(
60
+ "KSADK session persistence degraded; using in-memory live session: %s",
61
+ exc,
62
+ extra={
63
+ "session_backend_state": "degraded",
64
+ "session_backend": type(self.primary).__name__,
65
+ },
66
+ )
67
+ self._start_probe()
68
+
69
+ def _start_probe(self) -> None:
70
+ if self._probe_task is not None and not self._probe_task.done():
71
+ return
72
+ self._probe_task = asyncio.create_task(self._probe_loop())
73
+
74
+ async def _probe_loop(self) -> None:
75
+ while not self._primary_enabled:
76
+ await asyncio.sleep(self._probe_interval_seconds)
77
+ if self._primary_enabled:
78
+ break
79
+ try:
80
+ await self.primary.get_session("__ksadk_probe__")
81
+ except Exception:
82
+ continue
83
+ self._primary_enabled = True
84
+ logger.info(
85
+ "KSADK session persistence recovered; durable backend re-enabled",
86
+ extra={
87
+ "session_backend_state": "recovered",
88
+ "session_backend": type(self.primary).__name__,
89
+ },
90
+ )
91
+
92
+ async def _hydrate(self, session: Session) -> Session:
93
+ async with self._hydrate_lock:
94
+ self._primary_session_ids.add(session.id)
95
+ existing = await self.fallback.get_session(session.id)
96
+ if existing is None:
97
+ await self.fallback.create_session(
98
+ session.agent_id,
99
+ session.user_id,
100
+ session_id=session.id,
101
+ )
102
+ existing_events = await self.fallback.get_events(session.id)
103
+ existing_ids = {event.id for event in existing_events}
104
+ for event in sorted(session.events, key=lambda item: item.seq_id):
105
+ if event.id not in existing_ids:
106
+ await self.fallback.append_event(session.id, event)
107
+ await self.fallback.update_session_metadata(
108
+ session.id,
109
+ title=session.title,
110
+ title_source=session.title_source,
111
+ summary=session.summary,
112
+ first_prompt=session.first_prompt,
113
+ last_prompt=session.last_prompt,
114
+ )
115
+ current = await self.fallback.get_session(session.id)
116
+ if current is not None and session.state != current.state:
117
+ await self.fallback.update_state(
118
+ agent_id=session.agent_id,
119
+ user_id=session.user_id,
120
+ session_id=session.id,
121
+ scope="session",
122
+ state_delta=session.state,
123
+ )
124
+ hydrated = await self.fallback.get_session(session.id)
125
+ if hydrated is None:
126
+ raise RuntimeError(f"Failed to hydrate live session {session.id}")
127
+ return hydrated
128
+
129
+ async def create_session(
130
+ self,
131
+ agent_id: str,
132
+ user_id: str,
133
+ session_id: Optional[str] = None,
134
+ ) -> Session:
135
+ if session_id:
136
+ ok, durable = await self._call_primary("get_session", session_id)
137
+ if ok and durable is not None:
138
+ return await self._hydrate(durable)
139
+ existing = await self.fallback.get_session(session_id)
140
+ if existing is not None:
141
+ return existing
142
+
143
+ live = await self.fallback.create_session(agent_id, user_id, session_id=session_id)
144
+ ok, durable = await self._call_primary(
145
+ "create_session",
146
+ agent_id,
147
+ user_id,
148
+ session_id=live.id,
149
+ )
150
+ if ok and durable is not None:
151
+ self._primary_session_ids.add(durable.id)
152
+ return await self._hydrate(durable)
153
+ return live
154
+
155
+ async def get_session(self, session_id: str) -> Optional[Session]:
156
+ live = await self.fallback.get_session(session_id)
157
+ ok, durable = await self._call_primary("get_session", session_id)
158
+ if ok and durable is not None:
159
+ return await self._hydrate(durable)
160
+ return live
161
+
162
+ async def get_session_metadata(self, session_id: str) -> Optional[Session]:
163
+ ok, durable = await self._call_primary("get_session_metadata", session_id)
164
+ if ok and durable is not None:
165
+ return cast(Session, durable)
166
+ return await self.fallback.get_session_metadata(session_id)
167
+
168
+ async def list_sessions(
169
+ self,
170
+ agent_id: str,
171
+ user_id: Optional[str] = None,
172
+ offset: Optional[int] = None,
173
+ limit: Optional[int] = None,
174
+ ) -> list[Session]:
175
+ ok, durable_sessions = await self._call_primary(
176
+ "list_sessions",
177
+ agent_id,
178
+ user_id,
179
+ offset,
180
+ limit,
181
+ )
182
+ if ok:
183
+ return cast(list[Session], durable_sessions or [])
184
+ return await self.fallback.list_sessions(agent_id, user_id, offset, limit)
185
+
186
+ async def count_sessions(self, agent_id: str, user_id: Optional[str] = None) -> int:
187
+ ok, total = await self._call_primary("count_sessions", agent_id, user_id)
188
+ if ok:
189
+ return int(total or 0)
190
+ return await self.fallback.count_sessions(agent_id, user_id)
191
+
192
+ async def delete_session(self, session_id: str) -> bool:
193
+ deleted = await self.fallback.delete_session(session_id)
194
+ ok, durable_deleted = await self._call_primary("delete_session", session_id)
195
+ if ok:
196
+ self._primary_session_ids.discard(session_id)
197
+ return deleted or bool(durable_deleted) if ok else deleted
198
+
199
+ async def update_session_metadata(
200
+ self,
201
+ session_id: str,
202
+ *,
203
+ title: Optional[str] = None,
204
+ title_source: Optional[str] = None,
205
+ summary: Optional[str] = None,
206
+ first_prompt: Optional[str] = None,
207
+ last_prompt: Optional[str] = None,
208
+ ) -> Session:
209
+ if await self.fallback.get_session(session_id) is None:
210
+ await self.get_session(session_id)
211
+ live = await self.fallback.update_session_metadata(
212
+ session_id,
213
+ title=title,
214
+ title_source=title_source,
215
+ summary=summary,
216
+ first_prompt=first_prompt,
217
+ last_prompt=last_prompt,
218
+ )
219
+ await self._ensure_primary_session(session_id)
220
+ await self._call_primary(
221
+ "update_session_metadata",
222
+ session_id,
223
+ title=title,
224
+ title_source=title_source,
225
+ summary=summary,
226
+ first_prompt=first_prompt,
227
+ last_prompt=last_prompt,
228
+ )
229
+ return live
230
+
231
+ async def _ensure_primary_session(self, session_id: str) -> None:
232
+ """Create the session in PG if it only exists in memory (degraded-era)."""
233
+ if not self._primary_enabled or session_id in self._primary_session_ids:
234
+ return
235
+ async with self._primary_session_lock:
236
+ if not self._primary_enabled or session_id in self._primary_session_ids:
237
+ return
238
+ ok, durable = await self._call_primary("get_session", session_id)
239
+ if not ok:
240
+ return
241
+ if durable is None:
242
+ live = await self.fallback.get_session(session_id)
243
+ if live is None:
244
+ return
245
+ ok, durable = await self._call_primary(
246
+ "create_session",
247
+ live.agent_id,
248
+ live.user_id,
249
+ session_id=live.id,
250
+ )
251
+ if not ok or durable is None:
252
+ return
253
+ self._primary_session_ids.add(session_id)
254
+
255
+ async def append_event(self, session_id: str, event: SessionEvent) -> SessionEvent:
256
+ if await self.fallback.get_session(session_id) is None:
257
+ await self.get_session(session_id)
258
+ live = await self.fallback.append_event(session_id, event)
259
+ await self._ensure_primary_session(session_id)
260
+ await self._call_primary("append_event", session_id, event)
261
+ return live
262
+
263
+ async def get_events(
264
+ self,
265
+ session_id: str,
266
+ offset: Optional[int] = None,
267
+ limit: Optional[int] = None,
268
+ after_seq_id: Optional[int] = None,
269
+ before_seq_id: Optional[int] = None,
270
+ ) -> list[SessionEvent]:
271
+ await self.get_session(session_id)
272
+ return cast(
273
+ list[SessionEvent],
274
+ await self.fallback.get_events(
275
+ session_id,
276
+ offset,
277
+ limit,
278
+ after_seq_id,
279
+ before_seq_id,
280
+ ),
281
+ )
282
+
283
+ async def count_events(
284
+ self,
285
+ session_id: str,
286
+ after_seq_id: Optional[int] = None,
287
+ before_seq_id: Optional[int] = None,
288
+ ) -> int:
289
+ await self.get_session(session_id)
290
+ return cast(
291
+ int,
292
+ await self.fallback.count_events(session_id, after_seq_id, before_seq_id),
293
+ )
294
+
295
+ async def get_events_for_agent(
296
+ self,
297
+ agent_id: str,
298
+ user_id: Optional[str] = None,
299
+ offset: Optional[int] = None,
300
+ limit: Optional[int] = None,
301
+ ) -> list[SessionEvent]:
302
+ ok, events = await self._call_primary(
303
+ "get_events_for_agent", agent_id, user_id, offset, limit
304
+ )
305
+ if ok:
306
+ return cast(list[SessionEvent], events)
307
+ return await self.fallback.get_events_for_agent(agent_id, user_id, offset, limit)
308
+
309
+ async def count_events_for_agent(
310
+ self,
311
+ agent_id: str,
312
+ user_id: Optional[str] = None,
313
+ ) -> int:
314
+ ok, total = await self._call_primary("count_events_for_agent", agent_id, user_id)
315
+ if ok:
316
+ return int(total or 0)
317
+ return await self.fallback.count_events_for_agent(agent_id, user_id)
318
+
319
+ async def get_state(
320
+ self,
321
+ agent_id: str,
322
+ user_id: Optional[str],
323
+ session_id: Optional[str],
324
+ scope: str = "session",
325
+ ) -> Optional[SessionState]:
326
+ if session_id:
327
+ await self.get_session(session_id)
328
+ live = await self.fallback.get_state(agent_id, user_id, session_id, scope)
329
+ if live is not None or not self._primary_enabled:
330
+ return live
331
+ ok, durable = await self._call_primary(
332
+ "get_state",
333
+ agent_id,
334
+ user_id,
335
+ session_id,
336
+ scope,
337
+ )
338
+ if ok and durable is not None:
339
+ return await self.fallback.update_state(
340
+ agent_id=agent_id,
341
+ user_id=user_id,
342
+ session_id=session_id,
343
+ scope=scope,
344
+ state_delta=durable.state,
345
+ )
346
+ return live
347
+
348
+ async def update_state(
349
+ self,
350
+ *,
351
+ agent_id: str,
352
+ user_id: Optional[str],
353
+ session_id: Optional[str],
354
+ scope: str,
355
+ state_delta: dict[str, Any],
356
+ ) -> SessionState:
357
+ if session_id and await self.fallback.get_session(session_id) is None:
358
+ await self.get_session(session_id)
359
+ live = await self.fallback.update_state(
360
+ agent_id=agent_id,
361
+ user_id=user_id,
362
+ session_id=session_id,
363
+ scope=scope,
364
+ state_delta=state_delta,
365
+ )
366
+ if session_id:
367
+ await self._ensure_primary_session(session_id)
368
+ await self._call_primary(
369
+ "update_state",
370
+ agent_id=agent_id,
371
+ user_id=user_id,
372
+ session_id=session_id,
373
+ scope=scope,
374
+ state_delta=state_delta,
375
+ )
376
+ return live
377
+
378
+ async def aclose(self) -> None:
379
+ if self._probe_task is not None and not self._probe_task.done():
380
+ self._probe_task.cancel()
381
+ try:
382
+ await self._probe_task
383
+ except asyncio.CancelledError:
384
+ pass
385
+ for service in (self.primary, self.fallback):
386
+ close = getattr(service, "aclose", None)
387
+ if close is not None:
388
+ await close()
ksadk/skills/models.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Iterable
3
4
  from dataclasses import dataclass
4
5
  from typing import Any
5
6
 
@@ -48,7 +49,9 @@ class SkillRef:
48
49
  name=str(payload.get("Name") or payload.get("name") or ""),
49
50
  description=str(payload.get("Description") or payload.get("description") or ""),
50
51
  status=str(payload.get("Status") or payload.get("status") or ""),
51
- content_hash=ContentHash.parse(payload.get("ContentHash") or payload.get("content_hash")),
52
+ content_hash=ContentHash.parse(
53
+ payload.get("ContentHash") or payload.get("content_hash")
54
+ ),
52
55
  archive_uri=str(payload.get("ArchiveUri") or payload.get("archive_uri") or ""),
53
56
  aliases=_string_tuple(payload.get("Aliases") or payload.get("aliases")),
54
57
  tags=_string_tuple(payload.get("Tags") or payload.get("tags")),
@@ -65,7 +68,9 @@ class SkillRef:
65
68
  version_key = self.version_id or self.version
66
69
  if not version_key and self.content_hash:
67
70
  version_key = self.content_hash.value
68
- return "__".join(part.replace("/", "_").replace(":", "_") for part in (identity, version_key) if part)
71
+ return "__".join(
72
+ part.replace("/", "_").replace(":", "_") for part in (identity, version_key) if part
73
+ )
69
74
 
70
75
  @property
71
76
  def is_active(self) -> bool:
@@ -90,14 +95,20 @@ class SkillListResponse:
90
95
  space_name: str = "",
91
96
  ) -> "SkillListResponse":
92
97
  data = payload.get("Data") or payload.get("data") or {}
93
- skills_payload = data.get("Skills") or data.get("skills") or data.get("Items") or data.get("items") or []
98
+ skills_payload = (
99
+ data.get("Skills") or data.get("skills") or data.get("Items") or data.get("items") or []
100
+ )
94
101
  return cls(
95
102
  code=int(payload.get("Code") or payload.get("code") or 0),
96
103
  message=str(payload.get("Message") or payload.get("message") or ""),
97
104
  request_id=str(payload.get("RequestId") or payload.get("request_id") or ""),
98
105
  space_id=str(data.get("SkillSpaceId") or data.get("skill_space_id") or space_id),
99
- space_name=str(data.get("SkillSpaceName") or data.get("skill_space_name") or space_name),
100
- skills=[SkillRef.from_payload(item) for item in skills_payload if isinstance(item, dict)],
106
+ space_name=str(
107
+ data.get("SkillSpaceName") or data.get("skill_space_name") or space_name
108
+ ),
109
+ skills=[
110
+ SkillRef.from_payload(item) for item in skills_payload if isinstance(item, dict)
111
+ ],
101
112
  )
102
113
 
103
114
  def active_skills(self) -> list[SkillRef]:
@@ -107,6 +118,7 @@ class SkillListResponse:
107
118
  def _string_tuple(raw: Any) -> tuple[str, ...]:
108
119
  if raw is None:
109
120
  return ()
121
+ values: Iterable[Any]
110
122
  if isinstance(raw, str):
111
123
  values = raw.split(",")
112
124
  elif isinstance(raw, (list, tuple, set)):
@@ -79,11 +79,14 @@ class PackageStore:
79
79
  if not ref.content_hash:
80
80
  return
81
81
  if ref.content_hash.algorithm != "sha256":
82
- raise SkillPackageError(f"Unsupported ContentHash algorithm: {ref.content_hash.algorithm}")
82
+ raise SkillPackageError(
83
+ f"Unsupported ContentHash algorithm: {ref.content_hash.algorithm}"
84
+ )
83
85
  actual = hashlib.sha256(content).hexdigest()
84
86
  if actual.lower() != ref.content_hash.value.lower():
85
87
  raise SkillPackageError(
86
- f"ContentHash mismatch for {ref.name}: expected {ref.content_hash.render()}, got sha256:{actual}"
88
+ f"ContentHash mismatch for {ref.name}: expected "
89
+ f"{ref.content_hash.render()}, got sha256:{actual}"
87
90
  )
88
91
 
89
92
  def _safe_extract(self, archive_path: Path, extract_dir: Path) -> None:
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import os
5
- import subprocess
6
5
  import sys
7
6
  from dataclasses import asdict
8
7
  from pathlib import Path
@@ -12,15 +11,29 @@ import httpx
12
11
  from ksadk.skills.loader import LocalSkill
13
12
  from ksadk.skills.models import SkillRef
14
13
  from ksadk.skills.package_store import PackageStore
14
+ from ksadk.skills.runtime import loader as runtime_loader
15
+ from ksadk.skills.runtime import registry as runtime_registry
15
16
  from ksadk.skills.runtime.base import normalize_skill_names
16
17
  from ksadk.skills.runtime.executor import (
17
18
  WorkflowExecution,
18
19
  execute_workflow,
20
+ )
21
+ from ksadk.skills.runtime.executor import (
19
22
  _can_run_web_artifacts_builder as _executor_can_run_web_artifacts_builder,
23
+ )
24
+ from ksadk.skills.runtime.executor import (
20
25
  _run_command as _executor_run_command,
26
+ )
27
+ from ksadk.skills.runtime.executor import (
21
28
  _run_web_artifacts_builder as _executor_run_web_artifacts_builder,
29
+ )
30
+ from ksadk.skills.runtime.executor import (
22
31
  _runtime_timeout as _executor_runtime_timeout,
32
+ )
33
+ from ksadk.skills.runtime.executor import (
23
34
  _safe_project_name as _executor_safe_project_name,
35
+ )
36
+ from ksadk.skills.runtime.executor import (
24
37
  _tail as _executor_tail,
25
38
  )
26
39
  from ksadk.skills.runtime.request import (
@@ -28,8 +41,6 @@ from ksadk.skills.runtime.request import (
28
41
  SkillWorkflowRequestError,
29
42
  parse_workflow_request,
30
43
  )
31
- from ksadk.skills.runtime import loader as runtime_loader
32
- from ksadk.skills.runtime import registry as runtime_registry
33
44
 
34
45
 
35
46
  def _skill_space_ids() -> list[str]:
@@ -109,7 +120,9 @@ def run_agent(
109
120
  print("workflow=")
110
121
  print(f"skill_spaces={','.join(_skill_space_ids())}")
111
122
  print("loaded_skills=")
112
- print(f"workflow_result={json.dumps(asdict(execution), ensure_ascii=False, sort_keys=True)}")
123
+ print(
124
+ f"workflow_result={json.dumps(asdict(execution), ensure_ascii=False, sort_keys=True)}"
125
+ )
113
126
  return 1
114
127
 
115
128
  prompt = request.workflow_prompt
@@ -125,7 +138,9 @@ def run_agent(
125
138
  print(f"loaded_skills={','.join(skill.name for skill in loaded_skills)}")
126
139
  print(f"selected_skills={json.dumps(selected_skill_names, ensure_ascii=False, sort_keys=True)}")
127
140
  if _SKILL_LOAD_WARNINGS:
128
- print(f"skill_warnings={json.dumps(_SKILL_LOAD_WARNINGS, ensure_ascii=False, sort_keys=True)}")
141
+ print(
142
+ f"skill_warnings={json.dumps(_SKILL_LOAD_WARNINGS, ensure_ascii=False, sort_keys=True)}"
143
+ )
129
144
  print(f"workflow_result={json.dumps(asdict(execution), ensure_ascii=False, sort_keys=True)}")
130
145
  return 0 if execution.status != "failed" else 1
131
146
 
@@ -20,11 +20,7 @@ def parse_artifact_lines(stdout: str) -> list[str]:
20
20
  def collect_output_dir_artifacts(output_dir: Path) -> list[str]:
21
21
  if not output_dir.is_dir():
22
22
  return []
23
- return [
24
- str(path)
25
- for path in sorted(output_dir.rglob("*"))
26
- if path.is_file()
27
- ]
23
+ return [str(path) for path in sorted(output_dir.rglob("*")) if path.is_file()]
28
24
 
29
25
 
30
26
  def merge_artifacts(*groups: list[str]) -> list[str]:
@@ -7,9 +7,11 @@ from typing import Any
7
7
 
8
8
  from ksadk.sandbox import (
9
9
  E2BSandboxBackend,
10
- SandboxInputFile as RuntimeSandboxInputFile,
11
10
  SandboxSpec,
12
11
  )
12
+ from ksadk.sandbox import (
13
+ SandboxInputFile as RuntimeSandboxInputFile,
14
+ )
13
15
  from ksadk.skills.runtime.base import (
14
16
  SandboxInputFile,
15
17
  SkillRuntimeError,
@@ -75,10 +77,10 @@ class E2BSkillRuntimeBackend:
75
77
  @classmethod
76
78
  def from_env(cls) -> "E2BSkillRuntimeBackend":
77
79
  try:
78
- from e2b import Sandbox
80
+ from e2b import Sandbox # type: ignore[import-untyped]
79
81
  except ImportError as exc:
80
82
  raise SkillRuntimeError(
81
- "e2b>=2.0.0 is required for KSADK_SKILL_RUNTIME_BACKEND=e2b"
83
+ "e2b>=2.15.3,<2.25.0 is required for KSADK_SKILL_RUNTIME_BACKEND=e2b"
82
84
  ) from exc
83
85
  return cls(
84
86
  sandbox_cls=Sandbox,
@@ -87,7 +89,11 @@ class E2BSkillRuntimeBackend:
87
89
  or os.environ.get("KSADK_SKILL_RUNTIME_TEMPLATE_ID")
88
90
  or ""
89
91
  ),
90
- timeout=int(os.environ.get("KSADK_SANDBOX_TIMEOUT") or os.environ.get("KSADK_SKILL_RUNTIME_TIMEOUT") or "900"),
92
+ timeout=int(
93
+ os.environ.get("KSADK_SANDBOX_TIMEOUT")
94
+ or os.environ.get("KSADK_SKILL_RUNTIME_TIMEOUT")
95
+ or "900"
96
+ ),
91
97
  allow_internet_access=_bool_env(
92
98
  "KSADK_SANDBOX_ALLOW_INTERNET_ACCESS",
93
99
  _bool_env("KSADK_SKILL_RUNTIME_ALLOW_INTERNET_ACCESS", True),
@@ -17,6 +17,12 @@ from ksadk.skills.runtime.base import (
17
17
  )
18
18
 
19
19
 
20
+ def _coerce_output(value: str | bytes | None) -> str:
21
+ if isinstance(value, bytes):
22
+ return value.decode("utf-8", errors="replace")
23
+ return value or ""
24
+
25
+
20
26
  class LocalProcessSkillRuntimeBackend:
21
27
  def __init__(self, agent_path: str | Path, timeout: int = 900):
22
28
  self.agent_path = Path(agent_path)
@@ -67,7 +73,13 @@ class LocalProcessSkillRuntimeBackend:
67
73
  encoding="utf-8",
68
74
  )
69
75
  completed = subprocess.run(
70
- [sys.executable, "-u", str(self.agent_path), "--request-file", str(request_path)],
76
+ [
77
+ sys.executable,
78
+ "-u",
79
+ str(self.agent_path),
80
+ "--request-file",
81
+ str(request_path),
82
+ ],
71
83
  text=True,
72
84
  capture_output=True,
73
85
  timeout=timeout or self.timeout,
@@ -86,8 +98,8 @@ class LocalProcessSkillRuntimeBackend:
86
98
  return SkillRuntimeResult(
87
99
  runtime_id=f"local:{session_id}",
88
100
  exit_code=None,
89
- stdout=exc.stdout or "",
90
- stderr=exc.stderr or "",
101
+ stdout=_coerce_output(exc.stdout),
102
+ stderr=_coerce_output(exc.stderr),
91
103
  duration_ms=int((time.monotonic() - started) * 1000),
92
104
  timed_out=True,
93
105
  error_type="TimeoutExpired",
@@ -57,8 +57,7 @@ class SkillRuntimeBackend(Protocol):
57
57
  env: dict[str, str] | None = None,
58
58
  input_files: list[SandboxInputFile] | None = None,
59
59
  timeout: int = 900,
60
- ) -> SkillRuntimeResult:
61
- ...
60
+ ) -> SkillRuntimeResult: ...
62
61
 
63
62
 
64
63
  def parse_output_files(stdout: str) -> list[str]:
@@ -82,7 +82,10 @@ def _can_run_web_artifacts_builder(skill: LocalSkill, prompt: str) -> bool:
82
82
  if not init_script.exists() or not bundle_script.exists():
83
83
  return False
84
84
  normalized = prompt.lower()
85
- return any(marker in normalized for marker in ("web-artifacts-builder", "artifact", "bundle", "html", "react"))
85
+ return any(
86
+ marker in normalized
87
+ for marker in ("web-artifacts-builder", "artifact", "bundle", "html", "react")
88
+ )
86
89
 
87
90
 
88
91
  def _can_run_generic_workflow(skill: LocalSkill) -> bool:
@@ -91,7 +94,9 @@ def _can_run_generic_workflow(skill: LocalSkill) -> bool:
91
94
 
92
95
  def _run_web_artifacts_builder(skill: LocalSkill) -> WorkflowExecution:
93
96
  workdir = _skill_workdir()
94
- project_name = _safe_project_name(os.environ.get("KSADK_SKILL_ARTIFACT_PROJECT") or "ksadk-artifact")
97
+ project_name = _safe_project_name(
98
+ os.environ.get("KSADK_SKILL_ARTIFACT_PROJECT") or "ksadk-artifact"
99
+ )
95
100
  project_dir = workdir / project_name
96
101
  workdir.mkdir(parents=True, exist_ok=True)
97
102
  if project_dir.exists():
@@ -114,7 +119,9 @@ def _run_web_artifacts_builder(skill: LocalSkill) -> WorkflowExecution:
114
119
  timeout=timeout,
115
120
  )
116
121
  commands.append(bundle_result)
117
- output_files = [str(project_dir / "bundle.html")] if (project_dir / "bundle.html").exists() else []
122
+ output_files = (
123
+ [str(project_dir / "bundle.html")] if (project_dir / "bundle.html").exists() else []
124
+ )
118
125
  status = "ok" if bundle_result["exit_code"] == 0 and output_files else "failed"
119
126
  return WorkflowExecution(
120
127
  status=status,