agentengine-sdk-python 0.7.0__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 (371) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
  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 +233 -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 +500 -720
  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 +168 -89
  54. ksadk/cli/cmd_invoke.py +184 -122
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +98 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +483 -227
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +33 -10
  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 +34 -14
  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 +500 -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 +438 -51
  97. ksadk/conversations/model_context.py +12 -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 -5255
  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 +51 -38
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +309 -202
  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 +4 -5
  156. ksadk/memory/adk/short_term_memory.py +12 -21
  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 +345 -120
  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 -742
  183. ksadk/runners/langgraph_runner.py +352 -90
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +134 -33
  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 -3885
  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-D-SSn2ee.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-BA13sHc9.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-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.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-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.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-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.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-C7Q0X-wi.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-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.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-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.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-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.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-FbCTGrf9.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-DWgwtPsJ.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-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.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 +69 -19
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +2 -3
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +143 -25
  313. ksadk/sessions/resilient.py +36 -8
  314. ksadk/skills/models.py +17 -5
  315. ksadk/skills/package_store.py +5 -2
  316. ksadk/skills/runtime/agent.py +20 -5
  317. ksadk/skills/runtime/artifacts.py +1 -5
  318. ksadk/skills/runtime/backends/e2b.py +10 -4
  319. ksadk/skills/runtime/backends/local.py +15 -3
  320. ksadk/skills/runtime/base.py +1 -2
  321. ksadk/skills/runtime/executor.py +10 -3
  322. ksadk/skills/runtime/factory.py +4 -2
  323. ksadk/skills/runtime/loader.py +1 -2
  324. ksadk/skills/runtime/registry.py +15 -10
  325. ksadk/skills/runtime/request.py +3 -1
  326. ksadk/skills/service_client.py +38 -17
  327. ksadk/skills/tool_defs.py +15 -10
  328. ksadk/terminal_exec_policy.py +3 -4
  329. ksadk/tools/gateway.py +92 -15
  330. ksadk/tools/result_budget.py +12 -4
  331. ksadk/toolsets/__init__.py +134 -36
  332. ksadk/toolsets/platform.py +21 -5
  333. ksadk/toolsets/sandbox.py +82 -16
  334. ksadk/toolsets/skills.py +200 -39
  335. ksadk/toolsets/web.py +123 -26
  336. ksadk/toolsets/workspace.py +212 -101
  337. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  338. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  339. ksadk/tracing/setup.py +69 -53
  340. ksadk/tracing/span_utils.py +5 -2
  341. ksadk/tui/loop.py +78 -30
  342. ksadk/tui/stream_render.py +1 -0
  343. ksadk/ui_config.py +5 -3
  344. ksadk/version.py +1 -1
  345. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  346. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  347. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  348. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  349. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  350. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  351. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  352. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  353. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  354. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  355. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  356. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  357. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  358. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  359. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  360. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  361. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  362. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  364. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  365. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  366. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  367. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  368. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  369. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  370. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  371. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
ksadk/runtime_context.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from contextlib import contextmanager
4
4
  from contextvars import ContextVar, Token
5
- from dataclasses import dataclass
5
+ from dataclasses import dataclass, field
6
6
  from typing import Any, Iterator
7
7
 
8
8
 
@@ -22,10 +22,14 @@ class PlatformInvocationContext:
22
22
  has_current_files: bool
23
23
  runner_type: str
24
24
  account_id: str = ""
25
+ metadata: dict[str, Any] = field(default_factory=dict)
25
26
  model: str | None = None
26
27
  model_options: dict[str, Any] | None = None
27
28
  kb_context: dict[str, Any] | None = None
28
29
  memory_context: dict[str, Any] | None = None
30
+ # Request-scoped runtime control. It is intentionally separate from
31
+ # public caller metadata so built-in tools can enforce it consistently.
32
+ tool_approval_mode: str = ""
29
33
 
30
34
  def to_payload(self) -> dict[str, Any]:
31
35
  return {
@@ -43,6 +47,7 @@ class PlatformInvocationContext:
43
47
  "current_attachment_results": list(self.current_attachment_results or []),
44
48
  "has_current_files": self.has_current_files,
45
49
  "runner_type": self.runner_type,
50
+ "metadata": dict(self.metadata or {}),
46
51
  "model": self.model,
47
52
  "model_options": dict(self.model_options or {}),
48
53
  }
@@ -122,7 +127,14 @@ def set_current_invocation_context(
122
127
  def reset_current_invocation_context(
123
128
  token: Token[PlatformInvocationContext | None],
124
129
  ) -> None:
125
- _CURRENT_PLATFORM_INVOCATION_CONTEXT.reset(token)
130
+ try:
131
+ _CURRENT_PLATFORM_INVOCATION_CONTEXT.reset(token)
132
+ except ValueError:
133
+ # ASGI streaming may resume an async generator in a descendant
134
+ # Context after it yielded an interrupt. Tokens cannot be reset from
135
+ # that different Context; clearing the active descendant avoids
136
+ # converting a successfully persisted approval pause into a failed run.
137
+ _CURRENT_PLATFORM_INVOCATION_CONTEXT.set(None)
126
138
 
127
139
 
128
140
  def set_current_tool_execution_context(
@@ -134,7 +146,10 @@ def set_current_tool_execution_context(
134
146
  def reset_current_tool_execution_context(
135
147
  token: Token[ToolExecutionContext | None],
136
148
  ) -> None:
137
- _CURRENT_TOOL_EXECUTION_CONTEXT.reset(token)
149
+ try:
150
+ _CURRENT_TOOL_EXECUTION_CONTEXT.reset(token)
151
+ except ValueError:
152
+ _CURRENT_TOOL_EXECUTION_CONTEXT.set(None)
138
153
 
139
154
 
140
155
  @contextmanager
ksadk/runtime_state.py CHANGED
@@ -7,7 +7,6 @@ from typing import Any
7
7
 
8
8
  import yaml
9
9
 
10
-
11
10
  STATE_FILE_NAME = ".agentengine.state"
12
11
 
13
12
 
ksadk/sandbox/__init__.py CHANGED
@@ -1,5 +1,8 @@
1
1
  from ksadk.sandbox.backends.e2b import E2BSandboxBackend, E2BSandboxSession
2
- from ksadk.sandbox.backends.local_process import LocalProcessSandboxBackend, LocalProcessSandboxSession
2
+ from ksadk.sandbox.backends.local_process import (
3
+ LocalProcessSandboxBackend,
4
+ LocalProcessSandboxSession,
5
+ )
3
6
  from ksadk.sandbox.base import (
4
7
  SandboxBackend,
5
8
  SandboxCommandResult,
@@ -1,5 +1,8 @@
1
1
  from ksadk.sandbox.backends.e2b import E2BSandboxBackend, E2BSandboxSession
2
- from ksadk.sandbox.backends.local_process import LocalProcessSandboxBackend, LocalProcessSandboxSession
2
+ from ksadk.sandbox.backends.local_process import (
3
+ LocalProcessSandboxBackend,
4
+ LocalProcessSandboxSession,
5
+ )
3
6
 
4
7
  __all__ = [
5
8
  "E2BSandboxBackend",
@@ -67,6 +67,11 @@ class E2BSandboxSession:
67
67
  def write_file(self, path: str, data: str | bytes) -> None:
68
68
  self._sandbox.files.write(path, data)
69
69
 
70
+ def write_files(self, files: list[tuple[str, str | bytes]]) -> None:
71
+ if not files:
72
+ return
73
+ self._sandbox.files.write_files([{"path": path, "data": data} for path, data in files])
74
+
70
75
  def read_file(self, path: str) -> str:
71
76
  return str(self._sandbox.files.read(path))
72
77
 
@@ -78,7 +83,7 @@ class E2BSandboxSession:
78
83
  env: dict[str, str] | None = None,
79
84
  cwd: str | None = None,
80
85
  ) -> SandboxCommandResult:
81
- kwargs = {}
86
+ kwargs: dict[str, Any] = {}
82
87
  if timeout is not None:
83
88
  kwargs["timeout"] = timeout
84
89
  if env is not None:
@@ -121,9 +126,11 @@ class E2BSandboxBackend:
121
126
  sandbox_cls = self.sandbox_cls
122
127
  if sandbox_cls is None:
123
128
  try:
124
- from e2b import Sandbox
129
+ from e2b import Sandbox # type: ignore[import-untyped]
125
130
  except ImportError as exc:
126
- raise SandboxError("e2b>=2.0.0 is required for KSADK_SANDBOX_BACKEND=e2b") from exc
131
+ raise SandboxError(
132
+ "e2b>=2.15.3,<2.25.0 is required for KSADK_SANDBOX_BACKEND=e2b"
133
+ ) from exc
127
134
  sandbox_cls = Sandbox
128
135
 
129
136
  metadata = {
@@ -142,8 +149,9 @@ class E2BSandboxBackend:
142
149
  )
143
150
  session = self._wrap_sandbox(sandbox)
144
151
  self._wait_until_ready(session)
145
- for item in input_files or []:
146
- session.write_file(item.target_path, item.source.read_bytes())
152
+ session.write_files(
153
+ [(item.target_path, item.source.read_bytes()) for item in input_files or []]
154
+ )
147
155
  return session
148
156
 
149
157
  def _wrap_sandbox(self, sandbox: Any) -> E2BSandboxSession:
@@ -8,8 +8,16 @@ from pathlib import Path
8
8
  from ksadk.sandbox.base import SandboxCommandResult, SandboxInputFile, SandboxSession
9
9
 
10
10
 
11
+ def _coerce_output(value: str | bytes | None) -> str:
12
+ if isinstance(value, bytes):
13
+ return value.decode("utf-8", errors="replace")
14
+ return value or ""
15
+
16
+
11
17
  class LocalProcessSandboxSession:
12
- def __init__(self, *, session_id: str, workspace_root: Path, backend_name: str = "local_process"):
18
+ def __init__(
19
+ self, *, session_id: str, workspace_root: Path, backend_name: str = "local_process"
20
+ ):
13
21
  self._session_id = session_id
14
22
  self._workspace_root = workspace_root.expanduser().resolve()
15
23
  self._workspace_root.mkdir(parents=True, exist_ok=True)
@@ -67,8 +75,8 @@ class LocalProcessSandboxSession:
67
75
  pass
68
76
  stdout, stderr = process.communicate()
69
77
  return SandboxCommandResult(
70
- stdout=stdout or exc.stdout or "",
71
- stderr=(stderr or exc.stderr or "") + "\ncommand timed out",
78
+ stdout=_coerce_output(stdout or exc.stdout),
79
+ stderr=_coerce_output(stderr or exc.stderr) + "\ncommand timed out",
72
80
  exit_code=124,
73
81
  )
74
82
 
ksadk/sandbox/base.py CHANGED
@@ -20,7 +20,9 @@ class SandboxType(str, Enum):
20
20
  def from_value(cls, value: str | "SandboxType" | None) -> "SandboxType":
21
21
  if isinstance(value, SandboxType):
22
22
  return value
23
- normalized = (value or "").strip().lower().replace("_", "").replace("-", "").replace(" ", "")
23
+ normalized = (
24
+ (value or "").strip().lower().replace("_", "").replace("-", "").replace(" ", "")
25
+ )
24
26
  aliases = {
25
27
  "": cls.AIO,
26
28
  "aio": cls.AIO,
@@ -64,14 +66,11 @@ class SandboxSpec:
64
66
 
65
67
  class SandboxSession(Protocol):
66
68
  @property
67
- def sandbox_id(self) -> str:
68
- ...
69
+ def sandbox_id(self) -> str: ...
69
70
 
70
- def write_file(self, path: str, data: str | bytes) -> None:
71
- ...
71
+ def write_file(self, path: str, data: str | bytes) -> None: ...
72
72
 
73
- def read_file(self, path: str) -> str:
74
- ...
73
+ def read_file(self, path: str) -> str: ...
75
74
 
76
75
  def run_command(
77
76
  self,
@@ -80,14 +79,11 @@ class SandboxSession(Protocol):
80
79
  timeout: int | None = None,
81
80
  env: dict[str, str] | None = None,
82
81
  cwd: str | None = None,
83
- ) -> SandboxCommandResult:
84
- ...
82
+ ) -> SandboxCommandResult: ...
85
83
 
86
- def get_host(self, port: int) -> str:
87
- ...
84
+ def get_host(self, port: int) -> str: ...
88
85
 
89
- def kill(self) -> None:
90
- ...
86
+ def kill(self) -> None: ...
91
87
 
92
88
 
93
89
  class SandboxBackend(Protocol):
@@ -97,5 +93,4 @@ class SandboxBackend(Protocol):
97
93
  session_id: str,
98
94
  env: dict[str, str] | None = None,
99
95
  input_files: list[SandboxInputFile] | None = None,
100
- ) -> SandboxSession:
101
- ...
96
+ ) -> SandboxSession: ...
ksadk/sandbox/factory.py CHANGED
@@ -23,11 +23,17 @@ def create_sandbox_backend(
23
23
  ) -> SandboxBackend:
24
24
  resolved = (backend or os.environ.get("KSADK_SANDBOX_BACKEND") or "e2b").strip().lower()
25
25
  if resolved in {"local", "local_process"}:
26
- return LocalProcessSandboxBackend(workspace_root=resolve_local_session_dir() / "workspace", backend_name="local_process")
26
+ return LocalProcessSandboxBackend(
27
+ workspace_root=resolve_local_session_dir() / "workspace", backend_name="local_process"
28
+ )
27
29
  if resolved in {"pod", "pod_process"}:
28
30
  if not bool_env("KSADK_ALLOW_POD_PROCESS_TOOLS", False):
29
- raise SandboxError("KSADK_ALLOW_POD_PROCESS_TOOLS=true is required for pod_process backend")
30
- return LocalProcessSandboxBackend(workspace_root=resolve_local_session_dir() / "workspace", backend_name="pod_process")
31
+ raise SandboxError(
32
+ "KSADK_ALLOW_POD_PROCESS_TOOLS=true is required for pod_process backend"
33
+ )
34
+ return LocalProcessSandboxBackend(
35
+ workspace_root=resolve_local_session_dir() / "workspace", backend_name="pod_process"
36
+ )
31
37
  if resolved != "e2b":
32
38
  raise SandboxError(f"Unsupported sandbox backend: {resolved}")
33
39
  return E2BSandboxBackend(spec=sandbox_spec_from_env(), sandbox_cls=sandbox_cls)
@@ -39,7 +45,11 @@ def sandbox_spec_from_env() -> SandboxSpec:
39
45
  or os.environ.get("KSADK_SKILL_RUNTIME_TEMPLATE_ID")
40
46
  or ""
41
47
  )
42
- timeout = int(os.environ.get("KSADK_SANDBOX_TIMEOUT") or os.environ.get("KSADK_SKILL_RUNTIME_TIMEOUT") or "900")
48
+ timeout = int(
49
+ os.environ.get("KSADK_SANDBOX_TIMEOUT")
50
+ or os.environ.get("KSADK_SKILL_RUNTIME_TIMEOUT")
51
+ or "900"
52
+ )
43
53
  allow_internet_access = bool_env(
44
54
  "KSADK_SANDBOX_ALLOW_INTERNET_ACCESS",
45
55
  bool_env("KSADK_SKILL_RUNTIME_ALLOW_INTERNET_ACCESS", True),
ksadk/sandbox/registry.py CHANGED
@@ -1,11 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import atexit
4
+ import contextvars
4
5
  import logging
5
6
  import os
6
7
  import threading
7
8
  import time
9
+ from contextlib import contextmanager
8
10
  from dataclasses import dataclass
11
+ from typing import Any, Iterator
9
12
 
10
13
  from ksadk.sandbox.base import SandboxBackend, SandboxSession
11
14
 
@@ -43,7 +46,9 @@ class SandboxRegistry:
43
46
 
44
47
  @staticmethod
45
48
  def _resolve_sweep_interval() -> int:
46
- raw = os.environ.get("KSADK_SANDBOX_SWEEP_INTERVAL_SECONDS", str(_DEFAULT_SWEEP_INTERVAL_SECONDS))
49
+ raw = os.environ.get(
50
+ "KSADK_SANDBOX_SWEEP_INTERVAL_SECONDS", str(_DEFAULT_SWEEP_INTERVAL_SECONDS)
51
+ )
47
52
  try:
48
53
  value = int(raw)
49
54
  except (TypeError, ValueError):
@@ -103,7 +108,8 @@ class SandboxRegistry:
103
108
  expired = [
104
109
  key
105
110
  for key, entry in self._entries.items()
106
- if entry.expires_at <= current or (idle_ttl > 0 and current - entry.last_used_at > idle_ttl)
111
+ if entry.expires_at <= current
112
+ or (idle_ttl > 0 and current - entry.last_used_at > idle_ttl)
107
113
  ]
108
114
  for key in expired:
109
115
  self.kill(key)
@@ -138,7 +144,8 @@ class SandboxRegistry:
138
144
  with self._lock:
139
145
  while len(self._entries) - len(to_kill) >= max_sessions:
140
146
  candidates = [
141
- entry for entry in self._entries.values()
147
+ entry
148
+ for entry in self._entries.values()
142
149
  if entry.key != keep_key and entry.key not in to_kill
143
150
  ]
144
151
  if not candidates:
@@ -171,17 +178,61 @@ class SandboxRegistry:
171
178
 
172
179
  def reset_for_tests(self) -> None:
173
180
  """停后台 sweep 线程并清空所有 entry,用于测试隔离。"""
181
+ self.close()
182
+ self._idle_ttl_seconds = 0
183
+ self._sweep_stop.clear()
184
+
185
+ def close(self) -> None:
186
+ """Stop the owned sweep thread and kill every sandbox session."""
174
187
  self._sweep_stop.set()
175
188
  thread = self._sweep_thread
176
189
  if thread is not None and thread.is_alive():
177
190
  thread.join(timeout=2.0)
178
191
  self._sweep_thread = None
179
192
  self.clear()
180
- self._idle_ttl_seconds = 0
181
- self._sweep_stop.clear()
182
193
 
183
194
 
184
- GLOBAL_SANDBOX_REGISTRY = SandboxRegistry()
195
+ _current_sandbox_registry: contextvars.ContextVar[SandboxRegistry | None] = contextvars.ContextVar(
196
+ "ksadk_sandbox_registry", default=None
197
+ )
198
+ _fallback_sandbox_registry = SandboxRegistry()
199
+
200
+
201
+ def set_fallback_sandbox_registry(registry: SandboxRegistry) -> None:
202
+ """Set the registry used by legacy calls outside a bound app context."""
203
+ global _fallback_sandbox_registry
204
+ _fallback_sandbox_registry = registry
205
+
206
+
207
+ @contextmanager
208
+ def bind_sandbox_registry(registry: SandboxRegistry) -> Iterator[None]:
209
+ token = _current_sandbox_registry.set(registry)
210
+ try:
211
+ yield
212
+ finally:
213
+ _current_sandbox_registry.reset(token)
214
+
215
+
216
+ def get_sandbox_registry() -> SandboxRegistry:
217
+ return _current_sandbox_registry.get() or _fallback_sandbox_registry
218
+
219
+
220
+ class _ContextualSandboxRegistry:
221
+ """Compatibility proxy resolving the registry owned by the current app."""
222
+
223
+ def __getattr__(self, name: str) -> Any:
224
+ return getattr(get_sandbox_registry(), name)
225
+
226
+ def clear(self) -> None:
227
+ # Keep atexit dynamic: resolve the default app registry when invoked,
228
+ # not when the callback is registered.
229
+ get_sandbox_registry().clear()
230
+
231
+ def close(self) -> None:
232
+ get_sandbox_registry().close()
233
+
234
+
235
+ GLOBAL_SANDBOX_REGISTRY = _ContextualSandboxRegistry()
185
236
  # 进程退出时清理 sandbox,避免 E2B sandbox 活到服务端 timeout 才销毁(按秒计费)。
186
237
  # clear() 幂等,与 server lifespan shutdown 重复调用安全。kill -9 不触发 atexit,只能靠 E2B 兜底。
187
238
  atexit.register(GLOBAL_SANDBOX_REGISTRY.clear)
@@ -1,13 +1,16 @@
1
- from typing import List, Optional, Dict, Any, Union
2
- from pydantic import BaseModel, Field
1
+ from typing import Any, Dict, List, Optional
2
+
3
+ from pydantic import BaseModel
3
4
 
4
5
  # --- Consolidating Part Types ---
5
6
 
7
+
6
8
  class FunctionCall(BaseModel):
7
9
  id: Optional[str] = None
8
10
  name: str
9
11
  args: Dict[str, Any]
10
12
 
13
+
11
14
  class FunctionResponse(BaseModel):
12
15
  id: Optional[str] = None
13
16
  name: str
@@ -32,19 +35,22 @@ class Part(BaseModel):
32
35
  functionResponse: Optional[FunctionResponse] = None
33
36
  inlineData: Optional[InlineData] = None
34
37
  fileData: Optional[FileData] = None
35
-
36
- # Simple alias for JSON field mapping if needed,
38
+
39
+ # Simple alias for JSON field mapping if needed,
37
40
  # but Pydantic usually handles this with field aliases if inputs differ.
38
41
  # For now we stick to the TS interface names.
39
42
 
43
+
40
44
  class GenAiContent(BaseModel):
41
45
  role: str = "user"
42
46
  parts: List[Part]
43
47
 
48
+
44
49
  class NewMessage(BaseModel):
45
50
  parts: List[Part]
46
51
  role: str = "user"
47
52
 
53
+
48
54
  class AgentRunRequest(BaseModel):
49
55
  appName: str
50
56
  userId: str
@@ -56,18 +62,22 @@ class AgentRunRequest(BaseModel):
56
62
  functionCallEventId: Optional[str] = None
57
63
  model: Optional[str] = None
58
64
 
65
+
59
66
  # --- Response Types ---
60
67
 
68
+
61
69
  class LlmResponse(BaseModel):
62
70
  content: Optional[GenAiContent] = None
63
71
  error: Optional[str] = None
64
72
 
73
+
65
74
  class Session(BaseModel):
66
75
  id: str
67
76
  userId: str
68
77
  appName: str
69
78
  createdTime: Optional[float] = None
70
79
  updatedTime: Optional[float] = None
71
-
80
+
81
+
72
82
  class AppListResponse(BaseModel):
73
83
  apps: List[str]