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
@@ -0,0 +1,223 @@
1
+ """Detached streaming and per-app resource lifecycle."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import logging
7
+ from collections.abc import AsyncIterator, Mapping
8
+ from typing import Any
9
+
10
+ from fastapi import HTTPException
11
+
12
+ from ksadk.server.factory import get_state
13
+
14
+ from . import dependencies as deps
15
+ from .models import _RUN_TERMINAL_STATUSES
16
+ from .projection import _latest_invocation_status
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ _RESERVED_UI_PATHS = {"/", "/chat", "/build", "/deploy"}
21
+ _CUSTOM_API_PROXY_ENV_KEYS = ("KSADK_USER_BACKEND_URL", "LUOLUO_USER_BACKEND_URL")
22
+ _HOP_BY_HOP_HEADERS = {
23
+ "connection",
24
+ "keep-alive",
25
+ "proxy-authenticate",
26
+ "proxy-authorization",
27
+ "te",
28
+ "trailer",
29
+ "transfer-encoding",
30
+ "upgrade",
31
+ "host",
32
+ "content-length",
33
+ }
34
+
35
+
36
+ class _DetachedSSEStream:
37
+ _MAX_BACKLOG_CHUNKS = 256
38
+
39
+ def __init__(
40
+ self,
41
+ source: AsyncIterator[str],
42
+ *,
43
+ invocation_id: str | None = None,
44
+ session_id: str | None = None,
45
+ run_mode: str = "unknown",
46
+ run_trigger: str = "unknown",
47
+ ):
48
+ self._source = source
49
+ self.invocation_id = invocation_id
50
+ self.session_id = session_id
51
+ self._run_mode = run_mode
52
+ self._run_trigger = run_trigger
53
+ self._subscribers: set[asyncio.Queue[str | None]] = set()
54
+ self._backlog: list[str] = []
55
+ self._done = False
56
+ # 后台 task 脱离请求上下文,创建时捕获 per-app registry(goal-01)。
57
+ self._registry = get_state().stream_registry
58
+ self._task = asyncio.create_task(self._consume())
59
+ self._registry.streams.add(self._task)
60
+ self._task.add_done_callback(self._registry.streams.discard)
61
+ if self.invocation_id:
62
+ self._registry.streams_by_invocation[self.invocation_id] = self
63
+ self._task.add_done_callback(
64
+ lambda _task: self._registry.streams_by_invocation.pop(
65
+ self.invocation_id or "", None
66
+ )
67
+ )
68
+
69
+ async def _has_terminal_run_status(self) -> bool:
70
+ if not self.session_id or not self.invocation_id:
71
+ return False
72
+ status = await _latest_invocation_status(
73
+ deps.resolve_session_service(),
74
+ self.session_id,
75
+ self.invocation_id,
76
+ )
77
+ return status in _RUN_TERMINAL_STATUSES
78
+
79
+ async def _consume(self) -> None:
80
+ terminal_fallback_status: str | None = None
81
+ try:
82
+ async for chunk in self._source:
83
+ self._backlog.append(chunk)
84
+ if len(self._backlog) > self._MAX_BACKLOG_CHUNKS:
85
+ self._backlog = self._backlog[-self._MAX_BACKLOG_CHUNKS :]
86
+ subscribers = list(self._subscribers)
87
+ if not subscribers:
88
+ continue
89
+ await asyncio.gather(
90
+ *(subscriber.put(chunk) for subscriber in subscribers),
91
+ return_exceptions=True,
92
+ )
93
+ except asyncio.CancelledError:
94
+ terminal_fallback_status = "cancelled"
95
+ raise
96
+ except Exception:
97
+ terminal_fallback_status = "failed"
98
+ logger.exception("Detached SSE stream failed")
99
+ raise
100
+ finally:
101
+ self._done = True
102
+ subscribers = list(self._subscribers)
103
+ if subscribers:
104
+ await asyncio.gather(
105
+ *(subscriber.put(None) for subscriber in subscribers),
106
+ return_exceptions=True,
107
+ )
108
+ if terminal_fallback_status and self.session_id:
109
+ try:
110
+ if not await self._has_terminal_run_status():
111
+ await deps.conversation().append_run_status_event(
112
+ session_id=self.session_id,
113
+ author="system",
114
+ status=terminal_fallback_status,
115
+ invocation_id=self.invocation_id or "",
116
+ detail=(
117
+ f"background_{terminal_fallback_status}:{self.invocation_id or ''}"
118
+ ),
119
+ session_service_provider=deps.resolve_session_service,
120
+ run_mode=self._run_mode,
121
+ run_trigger=self._run_trigger,
122
+ )
123
+ except Exception:
124
+ logger.exception("failed to write background terminal status fallback")
125
+
126
+ def subscribe(self) -> asyncio.Queue[str | None]:
127
+ queue: asyncio.Queue[str | None] = asyncio.Queue()
128
+ for chunk in self._backlog:
129
+ queue.put_nowait(chunk)
130
+ if self._done:
131
+ queue.put_nowait(None)
132
+ else:
133
+ self._subscribers.add(queue)
134
+ return queue
135
+
136
+ def unsubscribe(self, queue: asyncio.Queue[str | None]) -> None:
137
+ self._subscribers.discard(queue)
138
+
139
+ def cancel(self) -> bool:
140
+ if self._task.done():
141
+ return False
142
+ return self._task.cancel()
143
+
144
+ async def iter_for_client(self) -> AsyncIterator[str]:
145
+ queue = self.subscribe()
146
+ try:
147
+ while True:
148
+ # 对 queue.get() 计时而不取消上游:cancel queue.get() 只影响本订阅者的等待,
149
+ # 不影响 _consume 后台 task;心跳直接发给当前客户端,不进 _backlog,
150
+ # 因此断线重连(SubscribeRunEvents)不会回放心跳帧。
151
+ try:
152
+ chunk = await asyncio.wait_for(
153
+ queue.get(),
154
+ timeout=deps.heartbeat_interval(),
155
+ )
156
+ except asyncio.TimeoutError:
157
+ yield ": ping\n\n"
158
+ continue
159
+ if chunk is None:
160
+ break
161
+ yield chunk
162
+ finally:
163
+ self.unsubscribe(queue)
164
+
165
+
166
+ async def _cancel_detached_streams_for_session(session_id: str) -> None:
167
+ target_session_id = str(session_id or "").strip()
168
+ if not target_session_id:
169
+ return
170
+ registry = get_state().stream_registry
171
+ detached_streams = [
172
+ detached
173
+ for detached in list(registry.streams_by_invocation.values())
174
+ if detached.session_id == target_session_id
175
+ ]
176
+ for detached in detached_streams:
177
+ detached.cancel()
178
+ if detached_streams:
179
+ await asyncio.gather(
180
+ *(detached._task for detached in detached_streams),
181
+ return_exceptions=True,
182
+ )
183
+
184
+
185
+ def _clear_detached_resume_key(registry, invocation_id: str, resume_key: tuple[str, str]) -> None:
186
+ registry.resume_keys_by_invocation.pop(invocation_id, None)
187
+ if registry.active_resume_invocation_by_key.get(resume_key) == invocation_id:
188
+ registry.active_resume_invocation_by_key.pop(resume_key, None)
189
+
190
+
191
+ def _detached_resume_key_from_input(
192
+ session_id: str | None,
193
+ resume_input: Mapping[str, Any] | None,
194
+ ) -> tuple[str, str] | None:
195
+ if not isinstance(resume_input, Mapping):
196
+ return None
197
+ if str(resume_input.get("type") or "").strip() != "agentengine.resume_checkpoint":
198
+ return None
199
+ normalized_session_id = str(session_id or "").strip()
200
+ run_id = str(resume_input.get("run_id") or "").strip()
201
+ if not normalized_session_id or not run_id:
202
+ return None
203
+ return normalized_session_id, run_id
204
+
205
+
206
+ def _reject_if_detached_resume_active(resume_key: tuple[str, str] | None) -> None:
207
+ if resume_key is None:
208
+ return
209
+ active_resume_invocation_id = get_state().stream_registry.active_resume_invocation_by_key.get(
210
+ resume_key
211
+ )
212
+ if not active_resume_invocation_id:
213
+ return
214
+ raise HTTPException(
215
+ status_code=409,
216
+ detail={
217
+ "code": "resume_already_running",
218
+ "message": "A checkpoint resume is already running for this session and run.",
219
+ "invocation_id": active_resume_invocation_id,
220
+ "session_id": resume_key[0],
221
+ "run_id": resume_key[1],
222
+ },
223
+ )
@@ -0,0 +1,381 @@
1
+ """Workspace, attachment upload, model catalog, and cancel routes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import io
6
+ import logging
7
+ import uuid
8
+ import zipfile
9
+ from pathlib import PurePosixPath
10
+ from typing import Any, Optional
11
+ from urllib.parse import quote
12
+
13
+ from fastapi import File, Form, HTTPException, Query, Request, UploadFile
14
+ from fastapi.responses import Response, StreamingResponse
15
+ from pydantic import BaseModel
16
+
17
+ from ksadk.conversations.attachment_storage import AttachmentStorageService
18
+ from ksadk.conversations.model_context import normalize_model_metadata
19
+ from ksadk.server.factory import get_state
20
+ from ksadk_runtime_common.workspace_files.preview import (
21
+ build_workspace_file_base_href,
22
+ build_workspace_preview_csp,
23
+ inject_workspace_html_preview,
24
+ )
25
+
26
+ from . import dependencies as deps
27
+ from .common import (
28
+ _action_response,
29
+ _resolve_active_runner,
30
+ _resolve_current_model,
31
+ _workspace_root_dir,
32
+ _workspace_runtime_request,
33
+ )
34
+ from .models import (
35
+ CancelRunActionRequest,
36
+ WorkspaceDeleteActionRequest,
37
+ WorkspaceListActionRequest,
38
+ )
39
+ from .projection import (
40
+ _agent_contains_invocation,
41
+ _require_action_session,
42
+ _session_contains_invocation,
43
+ )
44
+ from .routers import control_router, workspace_router
45
+
46
+ logger = logging.getLogger(__name__)
47
+
48
+
49
+ @workspace_router.post("/agentengine/api/v1/UploadFile")
50
+ async def upload_file_action(file: UploadFile = File(...)):
51
+ file_id = uuid.uuid4().hex
52
+ data = await file.read()
53
+ file_uri, _local_path = await AttachmentStorageService().store(
54
+ data=data,
55
+ file_id=file_id,
56
+ display_name=file.filename,
57
+ mime_type=file.content_type,
58
+ )
59
+
60
+ return _action_response(
61
+ "UploadFile",
62
+ {
63
+ "FileData": {
64
+ "fileUri": file_uri,
65
+ "displayName": file.filename or "uploaded_file",
66
+ "mimeType": file.content_type or "application/octet-stream",
67
+ "sizeBytes": len(data),
68
+ }
69
+ },
70
+ )
71
+
72
+
73
+ @workspace_router.get("/agentengine/api/v1/AttachmentContent", include_in_schema=False)
74
+ async def attachment_content_action(FileUri: str = Query(...)):
75
+ loaded = AttachmentStorageService().read(FileUri)
76
+ if loaded is None:
77
+ raise HTTPException(status_code=404, detail="Attachment not found")
78
+
79
+ return Response(
80
+ content=loaded.data,
81
+ media_type=loaded.mime_type or "application/octet-stream",
82
+ headers={"Content-Disposition": f'inline; filename="{loaded.display_name}"'},
83
+ )
84
+
85
+
86
+ @workspace_router.post("/agentengine/api/v1/ListWorkspaceFiles")
87
+ async def list_workspace_files_action(request: WorkspaceListActionRequest):
88
+ response = await _workspace_runtime_request(
89
+ "GET",
90
+ "/_ksadk/workspace/v1/entries",
91
+ params={
92
+ "path": request.Path,
93
+ "recursive": "true" if request.Recursive else "false",
94
+ },
95
+ )
96
+ return _action_response("ListWorkspaceFiles", response.json())
97
+
98
+
99
+ @workspace_router.post("/agentengine/api/v1/AddWorkspaceFile")
100
+ async def upload_workspace_file_action(
101
+ file: UploadFile = File(...),
102
+ AgentId: Optional[str] = Form(None),
103
+ Path: str = Form(...),
104
+ ):
105
+ del AgentId
106
+ try:
107
+ payload = await file.read()
108
+ finally:
109
+ await file.close()
110
+
111
+ file_name = file.filename or Path.rsplit("/", 1)[-1]
112
+ response = await _workspace_runtime_request(
113
+ "POST",
114
+ f"/_ksadk/workspace/v1/files/{quote(Path, safe='/')}",
115
+ files={
116
+ "file": (
117
+ file_name,
118
+ payload,
119
+ file.content_type or "application/octet-stream",
120
+ )
121
+ },
122
+ )
123
+ return _action_response("AddWorkspaceFile", response.json())
124
+
125
+
126
+ @workspace_router.post("/agentengine/api/v1/DeleteWorkspaceFile")
127
+ async def delete_workspace_file_action(request: WorkspaceDeleteActionRequest):
128
+ response = await _workspace_runtime_request(
129
+ "DELETE",
130
+ f"/_ksadk/workspace/v1/files/{quote(request.Path, safe='/')}",
131
+ )
132
+ return _action_response("DeleteWorkspaceFile", response.json())
133
+
134
+
135
+ @control_router.post("/agentengine/api/v1/CancelRun")
136
+ async def cancel_run_action(request: CancelRunActionRequest):
137
+ detached = get_state().stream_registry.streams_by_invocation.get(request.InvocationId)
138
+ service = deps.resolve_session_service()
139
+ scoped_session_id = str(request.SessionId or "").strip()
140
+ detached_session_id = str(detached.session_id or "").strip() if detached is not None else ""
141
+ if scoped_session_id and detached_session_id and scoped_session_id != detached_session_id:
142
+ raise HTTPException(
143
+ status_code=409,
144
+ detail="InvocationId does not belong to SessionId",
145
+ )
146
+ if not scoped_session_id and detached is not None:
147
+ scoped_session_id = detached_session_id
148
+ if scoped_session_id:
149
+ await _require_action_session(
150
+ service,
151
+ session_id=scoped_session_id,
152
+ agent_id=request.AgentId,
153
+ user_id=request.UserId,
154
+ )
155
+ if detached is None and not await _session_contains_invocation(
156
+ service,
157
+ scoped_session_id,
158
+ request.InvocationId,
159
+ ):
160
+ raise HTTPException(
161
+ status_code=409,
162
+ detail="InvocationId does not belong to SessionId",
163
+ )
164
+ elif request.UserId:
165
+ if not request.AgentId:
166
+ raise HTTPException(status_code=400, detail="AgentId is required with UserId")
167
+ if not await _agent_contains_invocation(
168
+ service,
169
+ request.AgentId,
170
+ request.InvocationId,
171
+ user_id=request.UserId,
172
+ ):
173
+ raise HTTPException(status_code=404, detail="Invocation not found")
174
+ found = detached is not None
175
+ cancel_requested = False
176
+ if detached is not None:
177
+ cancel_requested = detached.cancel()
178
+ runner_cancel_status = "not_found" if found else "unsupported"
179
+ active_runner = _resolve_active_runner()
180
+ if active_runner is not None:
181
+ try:
182
+ runner_result = active_runner.request_cancel(request.InvocationId)
183
+ if isinstance(runner_result, str) and runner_result:
184
+ runner_cancel_status = runner_result
185
+ elif runner_result is True:
186
+ runner_cancel_status = "accepted"
187
+ elif runner_result is False and not found:
188
+ runner_cancel_status = "not_found"
189
+ except Exception as exc:
190
+ runner_cancel_status = "error"
191
+ logger.warning("CancelRun failed: %s", exc)
192
+ runner_accepted = runner_cancel_status in {"accepted", "cancelling", "cancelled"}
193
+ status = "cancelling" if found or runner_accepted else runner_cancel_status
194
+ return _action_response(
195
+ "CancelRun",
196
+ {
197
+ "Cancelled": bool(cancel_requested or runner_accepted),
198
+ "Found": found,
199
+ "Status": status,
200
+ "RunnerCancelStatus": runner_cancel_status,
201
+ },
202
+ )
203
+
204
+
205
+ @workspace_router.get("/agentengine/api/v1/GetWorkspaceFileContent", include_in_schema=False)
206
+ async def get_workspace_file_content_action(
207
+ FilePath: str = Query(...),
208
+ AgentId: Optional[str] = Query(None),
209
+ ):
210
+ del AgentId
211
+ response = await _workspace_runtime_request(
212
+ "GET",
213
+ f"/_ksadk/workspace/v1/files/{quote(FilePath, safe='/')}",
214
+ )
215
+ headers = {}
216
+ for key in ("content-disposition", "last-modified"):
217
+ value = response.headers.get(key)
218
+ if value:
219
+ headers[key] = value
220
+ return Response(
221
+ content=response.content,
222
+ status_code=response.status_code,
223
+ headers=headers,
224
+ media_type=response.headers.get("content-type"),
225
+ )
226
+
227
+
228
+ @workspace_router.get("/agentengine/api/v1/ws/{agent_id}/{file_path:path}", include_in_schema=False)
229
+ async def workspace_file_path_route(request: Request, agent_id: str, file_path: str):
230
+ response = await _workspace_runtime_request(
231
+ "GET",
232
+ f"/_ksadk/workspace/v1/files/{quote(file_path, safe='/')}",
233
+ )
234
+ headers = {}
235
+ for key in ("content-disposition", "last-modified"):
236
+ value = response.headers.get(key)
237
+ if value:
238
+ headers[key] = value
239
+
240
+ content_type = response.headers.get("content-type", "")
241
+ is_html = "text/html" in content_type or file_path.lower().endswith((".html", ".htm"))
242
+
243
+ if is_html and response.status_code == 200:
244
+ del agent_id
245
+ base_href = build_workspace_file_base_href(file_path)
246
+ asset_source = f"{request.url.scheme}://{request.url.netloc}{base_href}"
247
+ html_doc = response.content.decode("utf-8", errors="replace")
248
+ html_doc = inject_workspace_html_preview(html_doc, file_path)
249
+ headers.pop("content-disposition", None)
250
+ headers["Content-Security-Policy"] = build_workspace_preview_csp(asset_source)
251
+ return Response(
252
+ content=html_doc.encode("utf-8"),
253
+ status_code=response.status_code,
254
+ headers=headers,
255
+ media_type="text/html; charset=utf-8",
256
+ )
257
+
258
+ return Response(
259
+ content=response.content,
260
+ status_code=response.status_code,
261
+ headers=headers,
262
+ media_type=content_type,
263
+ )
264
+
265
+
266
+ @workspace_router.get("/agentengine/api/v1/ExportWorkspaceZip", include_in_schema=False)
267
+ async def export_workspace_zip(
268
+ AgentId: Optional[str] = Query(None),
269
+ Path: str = Query("."),
270
+ ):
271
+ del AgentId
272
+ dir_path = Path.strip() or "."
273
+ response = await _workspace_runtime_request(
274
+ "GET",
275
+ "/_ksadk/workspace/v1/entries",
276
+ params={"path": dir_path, "recursive": "true"},
277
+ )
278
+ data = response.json() if response.status_code == 200 else {}
279
+ entries = data.get("Entries", []) if isinstance(data, dict) else []
280
+ root = _workspace_root_dir()
281
+ root_resolved = root.resolve()
282
+ buf = io.BytesIO()
283
+ with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
284
+ for entry in entries:
285
+ if entry.get("Type") != "file":
286
+ continue
287
+ rel = entry.get("Path", "")
288
+ if not rel:
289
+ continue
290
+ rel_path = PurePosixPath(rel)
291
+ if rel_path.is_absolute() or ".." in rel_path.parts:
292
+ continue
293
+ target = root.joinpath(*rel_path.parts)
294
+ if target.is_symlink():
295
+ continue
296
+ try:
297
+ resolved_target = target.resolve(strict=True)
298
+ except OSError:
299
+ continue
300
+ if not resolved_target.is_relative_to(root_resolved):
301
+ continue
302
+ if resolved_target.is_file():
303
+ zf.writestr(rel_path.as_posix(), resolved_target.read_bytes())
304
+ buf.seek(0)
305
+ zip_name = f"workspace-{dir_path.replace('/', '-')}.zip" if dir_path != "." else "workspace.zip"
306
+ return StreamingResponse(
307
+ buf,
308
+ media_type="application/zip",
309
+ headers={"Content-Disposition": f'attachment; filename="{zip_name}"'},
310
+ )
311
+
312
+
313
+ def _normalize_model_catalog_items(raw_models: list[Any]) -> list[dict[str, Any]]:
314
+ """统一模型目录 shape,并按 id 去重。
315
+
316
+ 这里刻意保留上游原始 dict 字段,再补 canonical metadata。
317
+ 这样两周后模型服务扩展字段时,这一层不会再次把信息裁掉。
318
+ """
319
+
320
+ normalized_by_id: dict[str, dict[str, Any]] = {}
321
+ for raw_model in raw_models:
322
+ item = normalize_model_metadata(raw_model)
323
+ normalized_by_id[item["id"]] = item
324
+ return sorted(normalized_by_id.values(), key=lambda item: item["id"])
325
+
326
+
327
+ async def _build_models_payload() -> dict[str, Any]:
328
+ import os
329
+
330
+ import httpx
331
+
332
+ api_base = os.getenv("OPENAI_BASE_URL") or os.getenv("OPENAI_API_BASE")
333
+ api_key = os.getenv("OPENAI_API_KEY")
334
+ current_model, source = _resolve_current_model()
335
+
336
+ def _fallback_catalog() -> dict[str, Any]:
337
+ models = _normalize_model_catalog_items([current_model]) if current_model else []
338
+ return {
339
+ "data": models,
340
+ "current": current_model,
341
+ "source": source,
342
+ }
343
+
344
+ if not api_base:
345
+ return _fallback_catalog()
346
+
347
+ try:
348
+ base_url = api_base.rstrip("/")
349
+ if base_url.endswith("/v1"):
350
+ url = f"{base_url}/models"
351
+ else:
352
+ url = f"{base_url}/v1/models"
353
+
354
+ headers = {}
355
+ if api_key:
356
+ headers["Authorization"] = f"Bearer {api_key}"
357
+
358
+ async with httpx.AsyncClient(verify=False, timeout=10) as client:
359
+ resp = await client.get(url, headers=headers)
360
+ resp.raise_for_status()
361
+ data = resp.json()
362
+
363
+ if isinstance(data, list):
364
+ models = _normalize_model_catalog_items(list(data))
365
+ else:
366
+ models = _normalize_model_catalog_items(list(data.get("data", [])))
367
+ if current_model and all(
368
+ str(item.get("id") or "").strip() != current_model for item in models
369
+ ):
370
+ models = _normalize_model_catalog_items([*models, current_model])
371
+ return {"data": models, "current": current_model, "source": source}
372
+ except Exception as e:
373
+ logger.error(f"Failed to fetch models: {e}")
374
+ fallback = _fallback_catalog()
375
+ fallback["error"] = str(e)
376
+ return fallback
377
+
378
+
379
+ class ListAgentModelsRequest(BaseModel):
380
+ AgentId: Optional[str] = None
381
+ Name: Optional[str] = None
@@ -1 +1 @@
1
- import{bt as e,ct as t,gt as n,lt as r,n as i,t as a,ut as o,wt as s,xt as c}from"./index-C00Lwg3L.js";var l=s(c(),1),u=t();function d(){let t=e(e=>e.visible),s=e(e=>e.content),c=e(e=>e.type),d=e(e=>e.hide),f=(0,l.useRef)(null);if(i(f),!t||!s)return null;let p=a(s);return(0,u.jsxs)(`aside`,{className:r(`flex h-full flex-shrink-0 flex-col border-l border-slate-200/30 bg-white dark:border-slate-800/40 dark:bg-slate-950`,`w-[min(42rem,50vw)]`),children:[(0,u.jsxs)(`div`,{className:`flex h-14 flex-shrink-0 items-center justify-between border-b border-slate-200/30 px-4 dark:border-slate-800/40`,children:[(0,u.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,u.jsx)(`span`,{className:`text-sm font-semibold text-slate-900 dark:text-slate-100`,children:`Artifact`}),(0,u.jsx)(`span`,{className:`rounded-md bg-slate-100 px-1.5 py-0.5 font-mono text-[11px] text-slate-500 dark:bg-slate-900 dark:text-slate-400`,children:c})]}),(0,u.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,u.jsxs)(`button`,{type:`button`,onClick:()=>{let e=new Blob([s],{type:`text/html;charset=utf-8`}),t=URL.createObjectURL(e),n=document.createElement(`a`);n.href=t,n.download=`artifact.${c===`svg`?`svg`:`html`}`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(t)},className:`inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium text-slate-600 transition hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-900`,title:`Download`,children:[(0,u.jsx)(n,{className:`h-3.5 w-3.5`}),`Download`]}),(0,u.jsx)(`button`,{type:`button`,onClick:d,className:`rounded-lg p-1.5 text-slate-500 transition hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-900 dark:hover:text-slate-100`,"aria-label":`Close Artifact`,title:`Close`,children:(0,u.jsx)(o,{className:`h-4 w-4`})})]})]}),(0,u.jsx)(`div`,{className:`min-h-0 flex-1`,children:(0,u.jsx)(`iframe`,{ref:f,srcDoc:p,sandbox:`allow-scripts allow-downloads`,title:`Artifact Preview`,className:`h-full w-full border-0 bg-white`})})]})}export{d as ArtifactsPanel};
1
+ import{bt as e,ht as t,lt as n,n as r,t as i,ut as a,wt as o,xt as s,yt as c}from"./index-QSwCHuB8.js";var l=o(s(),1),u=c();function d(){let o=e(e=>e.visible),s=e(e=>e.content),c=e(e=>e.type),d=e(e=>e.hide),f=(0,l.useRef)(null);if(r(f),!o||!s)return null;let p=i(s);return(0,u.jsxs)(`aside`,{className:n(`flex h-full flex-shrink-0 flex-col border-l border-slate-200/30 bg-white dark:border-slate-800/40 dark:bg-slate-950`,`w-[min(42rem,50vw)]`),children:[(0,u.jsxs)(`div`,{className:`flex h-14 flex-shrink-0 items-center justify-between border-b border-slate-200/30 px-4 dark:border-slate-800/40`,children:[(0,u.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,u.jsx)(`span`,{className:`text-sm font-semibold text-slate-900 dark:text-slate-100`,children:`Artifact`}),(0,u.jsx)(`span`,{className:`rounded-md bg-slate-100 px-1.5 py-0.5 font-mono text-[11px] text-slate-500 dark:bg-slate-900 dark:text-slate-400`,children:c})]}),(0,u.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,u.jsxs)(`button`,{type:`button`,onClick:()=>{let e=new Blob([s],{type:`text/html;charset=utf-8`}),t=URL.createObjectURL(e),n=document.createElement(`a`);n.href=t,n.download=`artifact.${c===`svg`?`svg`:`html`}`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(t)},className:`inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium text-slate-600 transition hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-900`,title:`Download`,children:[(0,u.jsx)(t,{className:`h-3.5 w-3.5`}),`Download`]}),(0,u.jsx)(`button`,{type:`button`,onClick:d,className:`rounded-lg p-1.5 text-slate-500 transition hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-900 dark:hover:text-slate-100`,"aria-label":`Close Artifact`,title:`Close`,children:(0,u.jsx)(a,{className:`h-4 w-4`})})]})]}),(0,u.jsx)(`div`,{className:`min-h-0 flex-1`,children:(0,u.jsx)(`iframe`,{ref:f,srcDoc:p,sandbox:`allow-scripts allow-downloads`,title:`Artifact Preview`,className:`h-full w-full border-0 bg-white`})})]})}export{d as ArtifactsPanel};