agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.1__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 (450) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/METADATA +52 -20
  2. agentengine_sdk_python-0.8.1.dist-info/RECORD +644 -0
  3. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/WHEEL +1 -1
  4. ksadk/a2a/__init__.py +180 -11
  5. ksadk/a2a/bootstrap.py +332 -0
  6. ksadk/a2a/card.py +15 -0
  7. ksadk/a2a/context_store.py +203 -0
  8. ksadk/a2a/control_plane.py +1056 -0
  9. ksadk/a2a/credential.py +99 -0
  10. ksadk/a2a/event_adapter.py +149 -0
  11. ksadk/a2a/executor.py +361 -137
  12. ksadk/a2a/external_transport.py +516 -0
  13. ksadk/a2a/identity.py +304 -0
  14. ksadk/a2a/ids.py +22 -0
  15. ksadk/a2a/langgraph.py +285 -0
  16. ksadk/a2a/resume_store.py +201 -0
  17. ksadk/a2a/routes.py +112 -0
  18. ksadk/a2a/server.py +102 -62
  19. ksadk/a2a/service_env.py +33 -0
  20. ksadk/a2a/space_client.py +1122 -0
  21. ksadk/a2a/task_adapter.py +423 -0
  22. ksadk/a2a/task_event_dispatcher.py +167 -0
  23. ksadk/a2a/task_event_outbox.py +326 -0
  24. ksadk/a2a/task_store.py +206 -0
  25. ksadk/a2a_card.py +101 -0
  26. ksadk/a2ui/__init__.py +27 -0
  27. ksadk/a2ui/core.py +186 -0
  28. ksadk/a2ui/models.py +166 -0
  29. ksadk/a2ui/renderer.py +198 -0
  30. ksadk/agui/__init__.py +9 -0
  31. ksadk/agui/a2ui_projection.py +92 -0
  32. ksadk/agui/agent.py +872 -0
  33. ksadk/agui/config.py +92 -0
  34. ksadk/agui/routes.py +47 -0
  35. ksadk/api/client.py +238 -204
  36. ksadk/api/environment.py +27 -0
  37. ksadk/builders/__init__.py +2 -0
  38. ksadk/builders/base.py +16 -14
  39. ksadk/builders/code_builder.py +375 -270
  40. ksadk/builders/container_builder.py +240 -200
  41. ksadk/builders/framework_requirements.py +31 -12
  42. ksadk/builders/ks3_uploader.py +60 -29
  43. ksadk/builders/managed_runtime_builder.py +173 -0
  44. ksadk/builders/mcp_builder.py +91 -92
  45. ksadk/builders/requirements_utils.py +1 -5
  46. ksadk/cli/__init__.py +97 -171
  47. ksadk/cli/cmd_a2a.py +255 -84
  48. ksadk/cli/cmd_agent.py +19 -5
  49. ksadk/cli/cmd_build.py +158 -29
  50. ksadk/cli/cmd_completion.py +47 -35
  51. ksadk/cli/cmd_config.py +267 -198
  52. ksadk/cli/cmd_create.py +507 -740
  53. ksadk/cli/cmd_dashboard.py +120 -45
  54. ksadk/cli/cmd_deploy.py +135 -59
  55. ksadk/cli/cmd_destroy.py +44 -14
  56. ksadk/cli/cmd_eval.py +386 -0
  57. ksadk/cli/cmd_files.py +63 -24
  58. ksadk/cli/cmd_hermes.py +313 -135
  59. ksadk/cli/cmd_invoke.py +184 -122
  60. ksadk/cli/cmd_launch.py +76 -28
  61. ksadk/cli/cmd_mcp.py +98 -64
  62. ksadk/cli/cmd_model.py +14 -5
  63. ksadk/cli/cmd_openclaw.py +564 -268
  64. ksadk/cli/cmd_replay.py +71 -0
  65. ksadk/cli/cmd_run.py +58 -73
  66. ksadk/cli/cmd_status.py +80 -31
  67. ksadk/cli/cmd_studio.py +110 -0
  68. ksadk/cli/cmd_version.py +20 -13
  69. ksadk/cli/cmd_web.py +95 -18
  70. ksadk/cli/deploy_utils.py +20 -20
  71. ksadk/cli/dry_run.py +7 -4
  72. ksadk/cli/env_options.py +83 -0
  73. ksadk/cli/error_utils.py +37 -12
  74. ksadk/cli/global_options.py +4 -3
  75. ksadk/cli/local_runtime.py +1 -2
  76. ksadk/cli/model_catalog.py +6 -2
  77. ksadk/cli/network_options.py +41 -19
  78. ksadk/cli/resource_common.py +6 -2
  79. ksadk/cli/runtime_bootstrap.py +51 -0
  80. ksadk/cli/storage.py +0 -1
  81. ksadk/cli/ui.py +11 -3
  82. ksadk/cli/workflow_common.py +52 -18
  83. ksadk/codex/__init__.py +12 -0
  84. ksadk/codex/client.py +1042 -0
  85. ksadk/codex/phase.py +143 -0
  86. ksadk/codex/runtime.py +940 -0
  87. ksadk/common/aicp_env.py +0 -1
  88. ksadk/common/auth.py +2 -2
  89. ksadk/common/constants.py +1 -3
  90. ksadk/common/kop_client.py +232 -0
  91. ksadk/common/llm_utils.py +17 -13
  92. ksadk/compat/__init__.py +5 -0
  93. ksadk/compat/adk_compat.py +200 -0
  94. ksadk/compat/copilotkit_a2ui.py +330 -0
  95. ksadk/configs/__init__.py +12 -14
  96. ksadk/configs/env_registry.py +661 -116
  97. ksadk/configs/global_config.py +3 -2
  98. ksadk/configs/settings.py +133 -209
  99. ksadk/conversations/__init__.py +85 -92
  100. ksadk/conversations/attachment_storage.py +16 -11
  101. ksadk/conversations/attachments.py +44 -36
  102. ksadk/conversations/compaction_pipeline.py +12 -12
  103. ksadk/conversations/compaction_prompt.py +9 -5
  104. ksadk/conversations/context.py +221 -6
  105. ksadk/conversations/message_projection.py +438 -51
  106. ksadk/conversations/model_context.py +12 -6
  107. ksadk/conversations/model_options.py +0 -1
  108. ksadk/conversations/normalize.py +20 -16
  109. ksadk/conversations/reasoning_markup.py +1 -1
  110. ksadk/conversations/runtime.py +339 -5255
  111. ksadk/conversations/runtime_compaction.py +333 -0
  112. ksadk/conversations/runtime_constants.py +27 -0
  113. ksadk/conversations/runtime_governance.py +185 -0
  114. ksadk/conversations/runtime_input.py +660 -0
  115. ksadk/conversations/runtime_invocation.py +395 -0
  116. ksadk/conversations/runtime_metadata.py +475 -0
  117. ksadk/conversations/runtime_observability.py +367 -0
  118. ksadk/conversations/runtime_payloads.py +272 -0
  119. ksadk/conversations/runtime_persistence.py +440 -0
  120. ksadk/conversations/runtime_preparation.py +426 -0
  121. ksadk/conversations/runtime_resume.py +836 -0
  122. ksadk/conversations/runtime_stream_events.py +902 -0
  123. ksadk/conversations/runtime_streaming.py +700 -0
  124. ksadk/conversations/semantic_summary.py +17 -5
  125. ksadk/conversations/session_title.py +6 -3
  126. ksadk/deployment/__init__.py +15 -16
  127. ksadk/deployment/agent_access.py +12 -23
  128. ksadk/deployment/base.py +51 -38
  129. ksadk/deployment/managed_runtime.py +33 -0
  130. ksadk/deployment/manager.py +85 -71
  131. ksadk/deployment/providers/serverless.py +379 -210
  132. ksadk/deployment/registry.py +38 -32
  133. ksadk/deployment/state.py +11 -11
  134. ksadk/deployment/ui_config.py +1 -1
  135. ksadk/detection/__init__.py +1 -1
  136. ksadk/detection/detector.py +146 -83
  137. ksadk/detection/mcp_detector.py +9 -6
  138. ksadk/evaluation/__init__.py +84 -0
  139. ksadk/evaluation/a2a_adapter.py +444 -0
  140. ksadk/evaluation/adapters.py +54 -0
  141. ksadk/evaluation/contracts.py +409 -0
  142. ksadk/evaluation/evalset.py +351 -0
  143. ksadk/evaluation/evaluators.py +461 -0
  144. ksadk/evaluation/executor.py +118 -0
  145. ksadk/evaluation/storage.py +68 -0
  146. ksadk/evaluation/target.py +73 -0
  147. ksadk/events/__init__.py +25 -0
  148. ksadk/events/parser.py +191 -0
  149. ksadk/events/replay.py +37 -0
  150. ksadk/events/runtime_event.py +273 -0
  151. ksadk/events/store.py +317 -0
  152. ksadk/harness/__init__.py +35 -0
  153. ksadk/harness/app.py +269 -0
  154. ksadk/harness/config.py +181 -0
  155. ksadk/harness/reasoner.py +105 -0
  156. ksadk/harness/runtime.py +364 -0
  157. ksadk/harness/sandbox.py +141 -0
  158. ksadk/harness/tools.py +222 -0
  159. ksadk/hermes_terminal.py +28 -12
  160. ksadk/identity/resolver.py +15 -9
  161. ksadk/ids.py +32 -0
  162. ksadk/knowledge_base/adk_tool.py +1 -1
  163. ksadk/knowledge_base/client.py +38 -33
  164. ksadk/managed_a2a_card.py +160 -0
  165. ksadk/managed_runtime.py +195 -0
  166. ksadk/markdown.py +5 -2
  167. ksadk/mcp_runtime/__init__.py +9 -6
  168. ksadk/memory/__init__.py +1 -1
  169. ksadk/memory/adk/__init__.py +2 -0
  170. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  171. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  172. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  173. ksadk/memory/adk/backends/sdk_ltm_backend.py +36 -36
  174. ksadk/memory/adk/long_term_memory.py +34 -37
  175. ksadk/memory/adk/resilient_session_service.py +4 -5
  176. ksadk/memory/adk/short_term_memory.py +12 -21
  177. ksadk/memory/adk_tool.py +3 -2
  178. ksadk/memory/backends/base.py +19 -19
  179. ksadk/memory/backends/memory.py +24 -25
  180. ksadk/memory/backends/redis.py +31 -30
  181. ksadk/memory/langchain_tool.py +2 -1
  182. ksadk/memory/manager.py +52 -47
  183. ksadk/memory/service.py +16 -6
  184. ksadk/memory/tool.py +4 -0
  185. ksadk/model_policy.py +15 -7
  186. ksadk/model_proxy/__init__.py +51 -0
  187. ksadk/model_proxy/bootstrap.py +80 -0
  188. ksadk/model_proxy/cache.py +165 -0
  189. ksadk/model_proxy/config.py +66 -0
  190. ksadk/model_proxy/demo_webui.py +115 -0
  191. ksadk/model_proxy/detect.py +145 -0
  192. ksadk/model_proxy/gate.py +68 -0
  193. ksadk/model_proxy/namespace.py +201 -0
  194. ksadk/model_proxy/protocol_proxy.py +22 -0
  195. ksadk/model_proxy/server.py +443 -0
  196. ksadk/model_proxy/transform.py +735 -0
  197. ksadk/openclaw_gateway.py +29 -14
  198. ksadk/runners/adk_runner.py +354 -146
  199. ksadk/runners/base_runner.py +71 -29
  200. ksadk/runners/deepagents_runner.py +0 -1
  201. ksadk/runners/factory.py +18 -5
  202. ksadk/runners/langchain_runner.py +29 -742
  203. ksadk/runners/langgraph_runner.py +417 -97
  204. ksadk/runners/patch_langchain.py +16 -16
  205. ksadk/runners/remote_runner.py +134 -33
  206. ksadk/runners/usage_accumulator.py +1 -0
  207. ksadk/runners/utils/__init__.py +0 -10
  208. ksadk/runners/utils/loader.py +23 -7
  209. ksadk/runtime/__init__.py +67 -0
  210. ksadk/runtime/adapter.py +412 -0
  211. ksadk/runtime/conversation_execution.py +553 -0
  212. ksadk/runtime/executor.py +251 -0
  213. ksadk/runtime/factory.py +156 -0
  214. ksadk/runtime/framework_adapters.py +118 -0
  215. ksadk/runtime/launch.py +48 -0
  216. ksadk/runtime/preprocessing.py +131 -0
  217. ksadk/runtime/runner_adapter.py +1032 -0
  218. ksadk/runtime/runner_loading.py +36 -0
  219. ksadk/runtime_context.py +18 -3
  220. ksadk/runtime_state.py +0 -1
  221. ksadk/sandbox/__init__.py +4 -1
  222. ksadk/sandbox/backends/__init__.py +4 -1
  223. ksadk/sandbox/backends/e2b.py +13 -5
  224. ksadk/sandbox/backends/local_process.py +11 -3
  225. ksadk/sandbox/base.py +10 -15
  226. ksadk/sandbox/factory.py +14 -4
  227. ksadk/sandbox/registry.py +57 -6
  228. ksadk/server/__init__.py +39 -4
  229. ksadk/server/api_models.py +15 -5
  230. ksadk/server/app.py +24 -3928
  231. ksadk/server/composition.py +47 -0
  232. ksadk/server/factory.py +622 -0
  233. ksadk/server/routes/__init__.py +1 -0
  234. ksadk/server/routes/checkpoint_resolution.py +116 -0
  235. ksadk/server/routes/common.py +682 -0
  236. ksadk/server/routes/control.py +331 -0
  237. ksadk/server/routes/dependencies.py +98 -0
  238. ksadk/server/routes/misc.py +425 -0
  239. ksadk/server/routes/models.py +451 -0
  240. ksadk/server/routes/openai_compat.py +229 -0
  241. ksadk/server/routes/projection.py +848 -0
  242. ksadk/server/routes/routers.py +52 -0
  243. ksadk/server/routes/run.py +519 -0
  244. ksadk/server/routes/sessions.py +644 -0
  245. ksadk/server/routes/streaming.py +265 -0
  246. ksadk/server/routes/workspace.py +414 -0
  247. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-CakCqxEN.js} +1 -1
  248. ksadk/server/static/assets/CodeBlock-CynLknyO.js +9 -0
  249. ksadk/server/static/assets/MathMessageMarkdown-3sQdOysS.js +8 -0
  250. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +303 -0
  251. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +1 -0
  252. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-DrgjcKhl.js} +1 -1
  253. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +1 -0
  254. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-BXoVRbQ6.js} +1 -1
  255. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-BnaB3Ywv.js} +1 -1
  256. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-Dw4weZcp.js} +1 -1
  257. ksadk/server/static/assets/channel-Dt3rQTFI.js +1 -0
  258. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-ChjpLK7j.js} +1 -1
  259. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-B9drTgOW.js} +1 -1
  260. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-CK4ROATy.js} +1 -1
  261. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B9KtTTgw.js} +1 -1
  262. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-1O1mki3m.js} +1 -1
  263. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-B_fH2YuH.js} +1 -1
  264. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D6rFLaVV.js} +1 -1
  265. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +1 -0
  266. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +1 -0
  267. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +1 -0
  268. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-ChNs_Mdk.js} +1 -1
  269. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-D0QXg_MQ.js} +1 -1
  270. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-DBDDKwBQ.js} +1 -1
  271. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-BkwDOxmO.js} +1 -1
  272. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Bv8waYvY.js} +1 -1
  273. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-e1VECDdu.js} +1 -1
  274. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-Ds9adfRl.js} +1 -1
  275. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-4N2NMVYg.js} +1 -1
  276. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-B-jNR6Vn.js} +1 -1
  277. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-B5J2uhNk.js} +1 -1
  278. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-B5oS1zcj.js} +1 -1
  279. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BB3-OwTQ.js} +1 -1
  280. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-BIlKoW0k.js} +1 -1
  281. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-BjOdlDjj.js} +1 -1
  282. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-C1sz5Eo3.js} +1 -1
  283. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-CWV4lDr1.js} +1 -1
  284. ksadk/server/static/assets/{dist-D-xOD048.js → dist-CmZHzlwZ.js} +1 -1
  285. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-D6MpCZtz.js} +1 -1
  286. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-DJN_6Y39.js} +1 -1
  287. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-DQU9EWw-.js} +1 -1
  288. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-DWKByxWV.js} +1 -1
  289. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-Dli7qW-B.js} +1 -1
  290. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-DsHPdk3W.js} +1 -1
  291. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-X4TnqwOK.js} +1 -1
  292. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-_pHPTyZ-.js} +1 -1
  293. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-fhOuWds5.js} +1 -1
  294. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-gLnrGsoU.js} +1 -1
  295. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-j6Dxmf_j.js} +1 -1
  296. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-o2OVmKvt.js} +1 -1
  297. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-BPItFKH6.js} +1 -1
  298. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +1 -0
  299. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-BbYB9w5Y.js} +1 -1
  300. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-TQXa0KXv.js} +1 -1
  301. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +1 -0
  302. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-bKblCnpa.js} +1 -1
  303. ksadk/server/static/assets/index-R52pJJvg.js +177 -0
  304. ksadk/server/static/assets/index-jJr3_955.css +2 -0
  305. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +1 -0
  306. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-BGVT7J_i.js} +1 -1
  307. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-K0OOfVna.js} +1 -1
  308. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-8LeOJaZp.js} +1 -1
  309. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-C6uCgZrW.js} +1 -1
  310. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-CYWseY5E.js} +1 -1
  311. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-hdBcYzM8.js} +1 -1
  312. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-BWrDjSZM.js} +2 -2
  313. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-Bjy_2v4_.js} +1 -1
  314. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +1 -0
  315. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +1 -0
  316. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-GmmqNiVH.js} +1 -1
  317. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-BmkRbwCg.js} +1 -1
  318. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +1 -0
  319. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DSWFqL7c.js} +1 -1
  320. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-l6iXmU65.js} +1 -1
  321. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-Cq6UBeQB.js} +1 -1
  322. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-qzTQpg3Y.js} +1 -1
  323. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +1 -0
  324. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-DEz24vV0.js} +1 -1
  325. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +1 -0
  326. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +1 -0
  327. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-CMCixki2.js} +1 -1
  328. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +1 -0
  329. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-CVzB8F9K.js} +1 -1
  330. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-BFBqBLc1.js} +1 -1
  331. ksadk/server/static/index.html +2 -2
  332. ksadk/server/terminal_sessions.py +111 -58
  333. ksadk/sessions/__init__.py +69 -19
  334. ksadk/sessions/base.py +31 -11
  335. ksadk/sessions/continuity.py +2 -3
  336. ksadk/sessions/in_memory.py +46 -2
  337. ksadk/sessions/local_service.py +148 -17
  338. ksadk/sessions/postgres_service.py +143 -25
  339. ksadk/sessions/resilient.py +36 -8
  340. ksadk/skills/models.py +17 -5
  341. ksadk/skills/package_store.py +5 -2
  342. ksadk/skills/runtime/agent.py +20 -5
  343. ksadk/skills/runtime/artifacts.py +1 -5
  344. ksadk/skills/runtime/backends/e2b.py +10 -4
  345. ksadk/skills/runtime/backends/local.py +15 -3
  346. ksadk/skills/runtime/base.py +1 -2
  347. ksadk/skills/runtime/executor.py +10 -3
  348. ksadk/skills/runtime/factory.py +4 -2
  349. ksadk/skills/runtime/loader.py +1 -2
  350. ksadk/skills/runtime/registry.py +15 -10
  351. ksadk/skills/runtime/request.py +3 -1
  352. ksadk/skills/service_client.py +47 -16
  353. ksadk/skills/tool_defs.py +15 -10
  354. ksadk/studio/__init__.py +5 -0
  355. ksadk/studio/agent_avatar_assets.py +120 -0
  356. ksadk/studio/agent_lifecycle.py +51 -0
  357. ksadk/studio/api.py +1046 -0
  358. ksadk/studio/api_catalog_routes.py +324 -0
  359. ksadk/studio/api_contracts.py +177 -0
  360. ksadk/studio/api_helpers.py +132 -0
  361. ksadk/studio/authoring.py +524 -0
  362. ksadk/studio/authoring_coordinator.py +285 -0
  363. ksadk/studio/builder.py +320 -0
  364. ksadk/studio/capabilities.py +351 -0
  365. ksadk/studio/cloud.py +278 -0
  366. ksadk/studio/codex_agent_service.py +583 -0
  367. ksadk/studio/codex_builder.py +324 -0
  368. ksadk/studio/codex_manifest.py +278 -0
  369. ksadk/studio/codex_run.py +352 -0
  370. ksadk/studio/compiler.py +189 -0
  371. ksadk/studio/contracts.py +644 -0
  372. ksadk/studio/errors.py +47 -0
  373. ksadk/studio/evaluation.py +192 -0
  374. ksadk/studio/event_store.py +284 -0
  375. ksadk/studio/framework_run.py +114 -0
  376. ksadk/studio/identifiers.py +33 -0
  377. ksadk/studio/mcp_runtime.py +229 -0
  378. ksadk/studio/model_client.py +543 -0
  379. ksadk/studio/model_profile_service.py +214 -0
  380. ksadk/studio/operations.py +243 -0
  381. ksadk/studio/otel_trace.py +754 -0
  382. ksadk/studio/pagination.py +182 -0
  383. ksadk/studio/python_tool_inspection.py +183 -0
  384. ksadk/studio/repository.py +306 -0
  385. ksadk/studio/resource_catalog.py +1217 -0
  386. ksadk/studio/run_service.py +707 -0
  387. ksadk/studio/runtime_catalog.py +74 -0
  388. ksadk/studio/runtime_source.py +339 -0
  389. ksadk/studio/service.py +1141 -0
  390. ksadk/studio/shared_web.py +994 -0
  391. ksadk/studio/skill_discovery.py +628 -0
  392. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
  393. ksadk/studio/static/assets/index-CaEN0eTR.css +1 -0
  394. ksadk/studio/static/assets/index-DI2eY_NH.js +252 -0
  395. ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
  396. ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
  397. ksadk/studio/static/index.html +15 -0
  398. ksadk/studio/templates.py +630 -0
  399. ksadk/studio/validator.py +246 -0
  400. ksadk/studio/workspace.py +137 -0
  401. ksadk/terminal_exec_policy.py +3 -4
  402. ksadk/tools/gateway.py +101 -15
  403. ksadk/tools/result_budget.py +12 -4
  404. ksadk/toolsets/__init__.py +161 -37
  405. ksadk/toolsets/a2a.py +426 -0
  406. ksadk/toolsets/platform.py +21 -5
  407. ksadk/toolsets/sandbox.py +82 -16
  408. ksadk/toolsets/skills.py +200 -39
  409. ksadk/toolsets/web.py +123 -26
  410. ksadk/toolsets/workspace.py +212 -101
  411. ksadk/tracing/__init__.py +19 -21
  412. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  413. ksadk/tracing/setup.py +135 -506
  414. ksadk/tracing/span_utils.py +0 -41
  415. ksadk/tui/loop.py +78 -30
  416. ksadk/tui/stream_render.py +1 -0
  417. ksadk/ui_config.py +5 -3
  418. ksadk/version.py +1 -1
  419. ksadk_runtime_common/memory_backend/registry.py +56 -56
  420. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  421. ksadk_runtime_common/workspace_files/router.py +8 -2
  422. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  423. ksadk/a2a/card_builder.py +0 -64
  424. ksadk/a2a/client.py +0 -309
  425. ksadk/runners/utils/langfuse.py +0 -230
  426. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  427. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  428. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  429. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  430. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  431. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  432. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  433. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  434. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  435. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  436. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  437. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  438. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  439. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  440. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  441. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  442. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  443. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  444. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  445. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  446. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  447. ksadk/tracing/exporters/langfuse_exporter.py +0 -445
  448. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/entry_points.txt +0 -0
  449. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/licenses/LICENSE +0 -0
  450. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1141 @@
1
+ """Application service composing Studio modules behind one local API boundary."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import os
7
+ from pathlib import Path
8
+ from typing import Any, Callable, Literal, cast
9
+ from urllib.parse import urlparse
10
+
11
+ from ksadk.evaluation import (
12
+ EvaluationConfig as PublicEvaluationConfig,
13
+ )
14
+ from ksadk.evaluation import (
15
+ EvaluationExecutionError,
16
+ EvaluationNotImplementedError,
17
+ EvaluationStorage,
18
+ EvaluationStorageError,
19
+ TargetKind,
20
+ TargetRef,
21
+ execute_evaluation,
22
+ load_evalset,
23
+ )
24
+ from ksadk.evaluation import (
25
+ EvaluationRequest as PublicEvaluationRequest,
26
+ )
27
+ from ksadk.evaluation.evalset import EvalSetParseError
28
+ from ksadk.runtime import RuntimeExecutor, build_default_runtime_registry
29
+ from ksadk.studio.agent_avatar_assets import AgentAvatarAssetStore
30
+ from ksadk.studio.agent_lifecycle import delete_framework_agent
31
+ from ksadk.studio.authoring_coordinator import StudioAuthoringCoordinator
32
+ from ksadk.studio.builder import AgentBundleBuilder
33
+ from ksadk.studio.capabilities import builtin_tool_contracts
34
+ from ksadk.studio.cloud import (
35
+ CloudDeploymentGateway,
36
+ CloudDeploymentService,
37
+ UnavailableCloudGateway,
38
+ )
39
+ from ksadk.studio.codex_agent_service import CodexAgentService, CodexDraftRepository
40
+ from ksadk.studio.codex_builder import (
41
+ CodexBuildRecord,
42
+ CodexBuildRepository,
43
+ CodexStudioBuilder,
44
+ RuntimeInspector,
45
+ )
46
+ from ksadk.studio.codex_manifest import (
47
+ CodexAgentManifest,
48
+ CodexManifestRepository,
49
+ )
50
+ from ksadk.studio.codex_run import CodexRunSpecResolver
51
+ from ksadk.studio.compiler import AgentCompiler
52
+ from ksadk.studio.contracts import (
53
+ AgentAppearance,
54
+ AgentBindings,
55
+ AgentDraft,
56
+ AgentSpec,
57
+ AgentTemplateComposeRequest,
58
+ AgentTemplateComposition,
59
+ DeploymentRequest,
60
+ Operation,
61
+ OperationKind,
62
+ RunEvent,
63
+ RunStatus,
64
+ RuntimeRef,
65
+ )
66
+ from ksadk.studio.errors import StudioError
67
+ from ksadk.studio.evaluation import EvaluationRunner
68
+ from ksadk.studio.event_store import RunEventStore
69
+ from ksadk.studio.framework_run import FrameworkRunSpecResolver
70
+ from ksadk.studio.mcp_runtime import MCPRuntimeAdapter
71
+ from ksadk.studio.model_client import CredentialResolver, OpenAICompatibleModelClient
72
+ from ksadk.studio.model_profile_service import test_model_profile_connection
73
+ from ksadk.studio.operations import OperationManager
74
+ from ksadk.studio.repository import AgentDraftRepository, BuildRepository, load_yaml_file
75
+ from ksadk.studio.resource_catalog import LocalResourceCatalog
76
+ from ksadk.studio.run_service import StudioRunService
77
+ from ksadk.studio.runtime_catalog import inspect_runtime_catalog
78
+ from ksadk.studio.runtime_source import materialize_generated_runtime_source
79
+ from ksadk.studio.templates import (
80
+ compose_blank_agent,
81
+ compose_research_agent,
82
+ default_agent_spec,
83
+ list_agent_templates,
84
+ )
85
+ from ksadk.studio.validator import AgentValidator
86
+ from ksadk.studio.workspace import Workspace
87
+
88
+
89
+ class StudioService:
90
+ def __init__(
91
+ self,
92
+ root: Path | str,
93
+ *,
94
+ model_client: OpenAICompatibleModelClient | None = None,
95
+ credential_resolver: CredentialResolver | None = None,
96
+ cloud_gateway: CloudDeploymentGateway | None = None,
97
+ codex_runtime_inspector: RuntimeInspector | None = None,
98
+ runtime_executor: RuntimeExecutor | None = None,
99
+ ) -> None:
100
+ self.workspace = Workspace(root)
101
+ self.workspace.initialize()
102
+ self._apply_persisted_settings()
103
+ self.avatar_assets = AgentAvatarAssetStore(self.workspace)
104
+ self.drafts = AgentDraftRepository(self.workspace)
105
+ self.catalog = LocalResourceCatalog(self.workspace)
106
+ self.builds = BuildRepository(self.workspace)
107
+ self.validator = AgentValidator()
108
+ self.builder = AgentBundleBuilder(
109
+ self.workspace,
110
+ compiler=AgentCompiler(
111
+ self.workspace,
112
+ validator=self.validator,
113
+ catalog=self.catalog,
114
+ ),
115
+ repository=self.builds,
116
+ )
117
+ self.event_store = RunEventStore(self.workspace)
118
+ self.event_store.recover_interrupted()
119
+ self.codex_manifests = CodexManifestRepository(self.workspace)
120
+ self.codex_builds = CodexBuildRepository(self.workspace)
121
+ self.codex_drafts = CodexDraftRepository(self.workspace)
122
+ codex_builder_kwargs = {}
123
+ if codex_runtime_inspector is not None:
124
+ codex_builder_kwargs["runtime_inspector"] = codex_runtime_inspector
125
+ self.codex_builder = CodexStudioBuilder(
126
+ self.workspace,
127
+ manifest_repository=self.codex_manifests,
128
+ build_repository=self.codex_builds,
129
+ resource_catalog=self.catalog,
130
+ draft_repository=self.codex_drafts,
131
+ **codex_builder_kwargs,
132
+ )
133
+ self.runtime_executor = runtime_executor or RuntimeExecutor(
134
+ build_default_runtime_registry()
135
+ )
136
+ self.run_service = StudioRunService(
137
+ self.workspace,
138
+ self.runtime_executor,
139
+ event_store=self.event_store,
140
+ )
141
+ self.credentials = (
142
+ credential_resolver
143
+ or getattr(model_client, "credential_resolver", None)
144
+ or CredentialResolver(self.workspace)
145
+ )
146
+ self.codex_runs = CodexRunSpecResolver(
147
+ self.workspace,
148
+ build_repository=self.codex_builds,
149
+ manifest_repository=self.codex_manifests,
150
+ credential_resolver=self.credentials,
151
+ resource_catalog=self.catalog,
152
+ )
153
+ self.framework_runs = FrameworkRunSpecResolver(
154
+ self.workspace,
155
+ build_repository=self.builds,
156
+ )
157
+ runtime_model_client = model_client or OpenAICompatibleModelClient(
158
+ credential_resolver=self.credentials
159
+ )
160
+ self.model_client = runtime_model_client
161
+ self.mcp_runtime = MCPRuntimeAdapter(self.workspace, credentials=self.credentials)
162
+ self.evaluations = EvaluationRunner(
163
+ self.workspace,
164
+ run_agent=self.run_build,
165
+ event_store=self.event_store,
166
+ build_repository=self.builds,
167
+ )
168
+ self.cloud = CloudDeploymentService(
169
+ self.workspace,
170
+ gateway=cloud_gateway or UnavailableCloudGateway(),
171
+ build_repository=self.builds,
172
+ )
173
+ self.operations = OperationManager(self.workspace)
174
+ self.evaluation_storage = EvaluationStorage(
175
+ self.workspace.resolve(".agentkit/evaluations")
176
+ )
177
+ self.authoring = StudioAuthoringCoordinator(self)
178
+ self.codex_agents = CodexAgentService(self)
179
+
180
+ def runtime_catalog(self) -> list[dict]:
181
+ return inspect_runtime_catalog(self.runtime_executor)
182
+
183
+ def codex_manifest_state(self, agent_id: str | None = None) -> dict:
184
+ return self.codex_agents.manifest_state(agent_id)
185
+
186
+ def save_codex_manifest(self, manifest: CodexAgentManifest) -> dict:
187
+ return self.codex_agents.save_manifest(manifest)
188
+
189
+ def list_codex_agents(self, *, query: str = "", limit: int = 50) -> list[AgentDraft]:
190
+ return self.codex_agents.list(query=query, limit=limit)
191
+
192
+ def create_codex_agent(
193
+ self,
194
+ *,
195
+ agent_id: str,
196
+ spec: AgentSpec | None,
197
+ name: str | None = None,
198
+ labels: dict[str, str] | None = None,
199
+ ) -> AgentDraft:
200
+ return self.codex_agents.create(
201
+ agent_id=agent_id,
202
+ spec=spec,
203
+ name=name,
204
+ labels=labels,
205
+ )
206
+
207
+ def update_codex_agent(
208
+ self,
209
+ agent_id: str,
210
+ spec: AgentSpec,
211
+ *,
212
+ expected_revision: int,
213
+ ) -> AgentDraft:
214
+ return self.codex_agents.update(
215
+ agent_id,
216
+ spec,
217
+ expected_revision=expected_revision,
218
+ )
219
+
220
+ def delete_codex_agent(self, agent_id: str, *, purge: bool = False) -> None:
221
+ self.codex_agents.delete(agent_id, purge=purge)
222
+
223
+ def codex_agent_detail(self, agent_id: str | None = None) -> dict:
224
+ return self.codex_agents.detail(agent_id)
225
+
226
+ @staticmethod
227
+ def codex_build_view(record: CodexBuildRecord) -> dict:
228
+ return CodexAgentService.build_view(record)
229
+
230
+ def submit_codex_build(
231
+ self,
232
+ *,
233
+ idempotency_key: str,
234
+ agent_id: str | None = None,
235
+ ) -> Operation:
236
+ return self.codex_agents.submit_build(
237
+ idempotency_key=idempotency_key,
238
+ agent_id=agent_id,
239
+ )
240
+
241
+ def submit_codex_run(
242
+ self,
243
+ build_id: str,
244
+ user_input: str,
245
+ *,
246
+ session_id: str | None,
247
+ model: str | None = None,
248
+ sandbox: str | None = None,
249
+ approval_mode: str | None = None,
250
+ collaboration_mode: str | None = None,
251
+ goal_objective: str | None = None,
252
+ runtime_input: Any = None,
253
+ idempotency_key: str,
254
+ on_event: Callable[[RunEvent], None] | None = None,
255
+ ) -> Operation:
256
+ return self.codex_agents.submit_run(
257
+ build_id,
258
+ user_input,
259
+ session_id=session_id,
260
+ model=model,
261
+ sandbox=sandbox,
262
+ approval_mode=approval_mode,
263
+ collaboration_mode=collaboration_mode,
264
+ goal_objective=goal_objective,
265
+ runtime_input=runtime_input,
266
+ idempotency_key=idempotency_key,
267
+ on_event=on_event,
268
+ )
269
+
270
+ def delete_session(self, session_id: str) -> None:
271
+ from ksadk.studio.errors import not_found
272
+
273
+ runs = self.event_store.list_runs(session_id=session_id)
274
+ if not runs:
275
+ raise not_found("session", session_id)
276
+ if any(run.status == RunStatus.RUNNING for run in runs):
277
+ raise StudioError(
278
+ "SESSION_RUN_ACTIVE",
279
+ "会话仍在运行,请先停止运行后再删除",
280
+ status_code=409,
281
+ details={"sessionId": session_id},
282
+ )
283
+ self.event_store.delete_session(session_id)
284
+
285
+ async def test_model_profile(self, resource_id: str) -> dict:
286
+ return await test_model_profile_connection(
287
+ catalog=self.catalog,
288
+ model_client=self.model_client,
289
+ resource_id=resource_id,
290
+ )
291
+
292
+ def create_agent(
293
+ self,
294
+ *,
295
+ agent_id: str,
296
+ name: str,
297
+ description: str = "",
298
+ template: str = "blank",
299
+ spec: AgentSpec | None = None,
300
+ labels: dict[str, str] | None = None,
301
+ ):
302
+ if self.codex_manifests.exists(agent_id):
303
+ from ksadk.studio.errors import StudioError
304
+
305
+ raise StudioError(
306
+ "AGENT_ALREADY_EXISTS",
307
+ "Agent ID 已存在",
308
+ status_code=409,
309
+ details={"id": agent_id},
310
+ )
311
+ resolved_spec = spec or default_agent_spec(
312
+ template,
313
+ description=description,
314
+ )
315
+ self._validate_bindings(resolved_spec.bindings)
316
+ draft = self.drafts.create(
317
+ agent_id=agent_id,
318
+ name=name,
319
+ description=description,
320
+ template=template,
321
+ spec=resolved_spec,
322
+ labels=labels,
323
+ )
324
+ materialize_generated_runtime_source(self.workspace, draft)
325
+ return draft
326
+
327
+ def create_authored_agent(
328
+ self,
329
+ *,
330
+ name: str,
331
+ slug: str | None = None,
332
+ runtime_type: str,
333
+ template: str = "blank",
334
+ description: str = "",
335
+ spec: AgentSpec | None = None,
336
+ ) -> AgentDraft:
337
+ return self.authoring.create(
338
+ name=name,
339
+ slug=slug,
340
+ runtime_type=runtime_type,
341
+ description=description,
342
+ template=template,
343
+ spec=spec,
344
+ )
345
+
346
+ def inspect_agent_import(self, content: bytes, *, filename: str) -> dict:
347
+ return self.authoring.inspect_import(content, filename=filename)
348
+
349
+ def commit_agent_import(
350
+ self,
351
+ inspection_token: str,
352
+ *,
353
+ name: str | None = None,
354
+ slug: str | None = None,
355
+ ) -> AgentDraft:
356
+ return self.authoring.commit_import(
357
+ inspection_token,
358
+ name=name,
359
+ slug=slug,
360
+ )
361
+
362
+ def inspect_agent_project(self, project_path: str) -> dict:
363
+ return self.authoring.inspect_project(project_path)
364
+
365
+ def commit_agent_project(
366
+ self,
367
+ inspection_token: str,
368
+ *,
369
+ name: str | None = None,
370
+ slug: str | None = None,
371
+ model_profile_id: str | None = None,
372
+ ) -> AgentDraft:
373
+ return self.authoring.commit_project(
374
+ inspection_token,
375
+ name=name,
376
+ slug=slug,
377
+ model_profile_id=model_profile_id,
378
+ )
379
+
380
+ async def compose_agent_conversation(
381
+ self,
382
+ *,
383
+ messages: list[dict[str, str]],
384
+ model_profile_id: str,
385
+ ) -> dict:
386
+ return await self.authoring.compose_conversation(
387
+ messages=messages,
388
+ model_profile_id=model_profile_id,
389
+ )
390
+
391
+ def is_codex_agent(self, agent_id: str) -> bool:
392
+ """Return whether one Agent is backed by the Codex YAML contract."""
393
+
394
+ return self.codex_manifests.exists(agent_id)
395
+
396
+ def agent_runtime_type(self, agent_id: str) -> str:
397
+ """Resolve runtime from the Agent itself, never from Studio process state."""
398
+
399
+ if self.is_codex_agent(agent_id):
400
+ return "codex"
401
+ draft = self.drafts.get(agent_id)
402
+ runtime = draft.spec.runtime
403
+ if runtime is None:
404
+ # Read compatibility for Agent drafts written before RuntimeRef existed.
405
+ framework = draft.metadata.labels.get("agentkit.ksyun.com/framework", "")
406
+ return framework.strip().lower() or "adk"
407
+ return runtime.type
408
+
409
+ def list_agents(self, *, query: str = "", limit: int = 50) -> list[AgentDraft]:
410
+ """List all local Agents from one registry view across runtime types."""
411
+
412
+ if limit < 1:
413
+ return []
414
+ normalized = query.strip().lower()
415
+ combined: dict[str, AgentDraft] = {
416
+ draft.metadata.id: draft for draft in self.list_codex_agents(query=query, limit=limit)
417
+ }
418
+ for draft in self.drafts.list(query=query, limit=limit):
419
+ combined.setdefault(draft.metadata.id, draft)
420
+ values = list(combined.values())
421
+ if normalized:
422
+ values = [
423
+ item
424
+ for item in values
425
+ if normalized in item.metadata.id.lower()
426
+ or normalized in item.metadata.name.lower()
427
+ ]
428
+ return values[:limit]
429
+
430
+ def agent_detail(self, agent_id: str) -> dict:
431
+ if self.is_codex_agent(agent_id):
432
+ return self.codex_agent_detail(agent_id)
433
+ draft = self.drafts.get(agent_id)
434
+ return {
435
+ "draft": draft,
436
+ "builds": self.builds.list_for_agent(agent_id)[:10],
437
+ "validation": self.validator.validate(draft),
438
+ }
439
+
440
+ def create_studio_agent(
441
+ self,
442
+ *,
443
+ agent_id: str,
444
+ name: str,
445
+ description: str = "",
446
+ template: str = "blank",
447
+ spec: AgentSpec | None = None,
448
+ runtime: RuntimeRef | None = None,
449
+ labels: dict[str, str] | None = None,
450
+ ) -> AgentDraft:
451
+ """Create one Agent and dispatch from its RuntimeRef."""
452
+
453
+ resolved_spec = (spec or default_agent_spec(template, description=description)).model_copy(
454
+ deep=True
455
+ )
456
+ selected = runtime or resolved_spec.runtime
457
+ resolved_spec.runtime = selected
458
+ if selected is not None and selected.type == "codex":
459
+ return cast(
460
+ AgentDraft,
461
+ self.create_codex_agent(
462
+ agent_id=agent_id,
463
+ spec=resolved_spec,
464
+ name=name,
465
+ labels=labels,
466
+ ),
467
+ )
468
+ return cast(
469
+ AgentDraft,
470
+ self.create_agent(
471
+ agent_id=agent_id,
472
+ name=name,
473
+ description=description,
474
+ template=template,
475
+ spec=resolved_spec,
476
+ labels=labels,
477
+ ),
478
+ )
479
+
480
+ def update_studio_agent(
481
+ self,
482
+ agent_id: str,
483
+ spec: AgentSpec,
484
+ *,
485
+ expected_revision: int,
486
+ ) -> AgentDraft:
487
+ if self.is_codex_agent(agent_id):
488
+ spec.runtime = self.agent_detail(agent_id)["draft"].spec.runtime
489
+ return cast(
490
+ AgentDraft,
491
+ self.update_codex_agent(
492
+ agent_id,
493
+ spec,
494
+ expected_revision=expected_revision,
495
+ ),
496
+ )
497
+ current = self.drafts.get(agent_id)
498
+ if spec.runtime is None:
499
+ spec.runtime = current.spec.runtime
500
+ elif current.spec.runtime is not None and spec.runtime.type != current.spec.runtime.type:
501
+ from ksadk.studio.errors import StudioError
502
+
503
+ raise StudioError(
504
+ "AGENT_RUNTIME_IMMUTABLE",
505
+ "编辑 Agent 时不能直接切换 Runtime;请通过导入/迁移创建新 Agent",
506
+ status_code=422,
507
+ field="runtime.type",
508
+ )
509
+ return cast(
510
+ AgentDraft,
511
+ self.update_agent(agent_id, spec, expected_revision=expected_revision),
512
+ )
513
+
514
+ def update_studio_agent_bindings(
515
+ self,
516
+ agent_id: str,
517
+ bindings: AgentBindings,
518
+ *,
519
+ expected_revision: int,
520
+ ) -> AgentDraft:
521
+ detail = self.agent_detail(agent_id)
522
+ spec = detail["draft"].spec.model_copy(deep=True)
523
+ spec.bindings = bindings
524
+ return self.update_studio_agent(
525
+ agent_id,
526
+ spec,
527
+ expected_revision=expected_revision,
528
+ )
529
+
530
+ def update_studio_agent_appearance(
531
+ self,
532
+ agent_id: str,
533
+ appearance: AgentAppearance,
534
+ *,
535
+ expected_revision: int,
536
+ ) -> AgentDraft:
537
+ if self.is_codex_agent(agent_id):
538
+ return self.codex_agents.update_appearance(
539
+ agent_id,
540
+ appearance,
541
+ expected_revision=expected_revision,
542
+ )
543
+ return self.drafts.update_appearance(
544
+ agent_id,
545
+ appearance,
546
+ expected_revision=expected_revision,
547
+ )
548
+
549
+ def delete_studio_agent(self, agent_id: str, *, purge: bool = False) -> None:
550
+ if self.is_codex_agent(agent_id):
551
+ self.delete_codex_agent(agent_id, purge=purge)
552
+ return
553
+ delete_framework_agent(self, agent_id, purge=purge)
554
+
555
+ def validate_studio_agent(
556
+ self,
557
+ agent_id: str,
558
+ *,
559
+ revision: int,
560
+ level: Literal["schema", "build", "release"] = "build",
561
+ ):
562
+ detail = self.agent_detail(agent_id)
563
+ draft = detail["draft"]
564
+ if draft.metadata.revision != revision:
565
+ from ksadk.studio.errors import StudioError
566
+
567
+ raise StudioError(
568
+ "AGENT_REVISION_CONFLICT",
569
+ "Validation revision 与当前 Agent 不一致",
570
+ status_code=409,
571
+ )
572
+ if self.is_codex_agent(agent_id):
573
+ return detail["validation"]
574
+ return self.validator.validate(draft, level=level)
575
+
576
+ def submit_studio_build(
577
+ self,
578
+ agent_id: str,
579
+ *,
580
+ revision: int,
581
+ idempotency_key: str,
582
+ ) -> Operation:
583
+ runtime_type = self.agent_runtime_type(agent_id)
584
+ runtime = next(
585
+ (item for item in self.runtime_catalog() if item["runtimeType"] == runtime_type),
586
+ None,
587
+ )
588
+ if runtime is None:
589
+ from ksadk.studio.errors import StudioError
590
+
591
+ raise StudioError(
592
+ "RUNTIME_NOT_REGISTERED",
593
+ "Agent 引用的 RuntimeAdapter 未注册",
594
+ status_code=422,
595
+ details={"runtimeType": runtime_type},
596
+ )
597
+ if runtime["status"] != "ready":
598
+ from ksadk.studio.errors import StudioError
599
+
600
+ raise StudioError(
601
+ "RUNTIME_DEPENDENCY_MISSING",
602
+ f"{runtime['displayName']} Runtime 依赖未安装",
603
+ status_code=422,
604
+ details={
605
+ "runtimeType": runtime_type,
606
+ "installCommand": runtime["installCommand"],
607
+ },
608
+ )
609
+ if self.is_codex_agent(agent_id):
610
+ detail = self.agent_detail(agent_id)
611
+ if revision != detail["draft"].metadata.revision:
612
+ from ksadk.studio.errors import StudioError
613
+
614
+ raise StudioError(
615
+ "AGENT_REVISION_CONFLICT",
616
+ "Build revision 与当前 Agent 不一致",
617
+ status_code=409,
618
+ )
619
+ return self.submit_codex_build(
620
+ idempotency_key=idempotency_key,
621
+ agent_id=agent_id,
622
+ )
623
+ return self.submit_build(
624
+ agent_id,
625
+ revision=revision,
626
+ idempotency_key=idempotency_key,
627
+ )
628
+
629
+ def build_view(self, build_id: str):
630
+ try:
631
+ return self.codex_build_view(self.codex_builds.get(build_id))
632
+ except Exception as exc: # repository not-found is the only fallback contract
633
+ if getattr(exc, "status_code", None) != 404:
634
+ raise
635
+ return self.builds.get(build_id)
636
+
637
+ def submit_studio_run(
638
+ self,
639
+ build_id: str,
640
+ user_input: str,
641
+ *,
642
+ session_id: str | None,
643
+ model: str | None,
644
+ idempotency_key: str,
645
+ sandbox: str | None = None,
646
+ approval_mode: str | None = None,
647
+ collaboration_mode: str | None = None,
648
+ goal_objective: str | None = None,
649
+ runtime_input: Any = None,
650
+ on_event: Callable[[RunEvent], None] | None = None,
651
+ ) -> Operation:
652
+ try:
653
+ self.codex_builds.get(build_id)
654
+ except Exception as exc:
655
+ if getattr(exc, "status_code", None) != 404:
656
+ raise
657
+ else:
658
+ return self.submit_codex_run(
659
+ build_id,
660
+ user_input,
661
+ session_id=session_id,
662
+ model=model,
663
+ sandbox=sandbox,
664
+ approval_mode=approval_mode,
665
+ collaboration_mode=collaboration_mode,
666
+ goal_objective=goal_objective,
667
+ runtime_input=runtime_input,
668
+ idempotency_key=idempotency_key,
669
+ on_event=on_event,
670
+ )
671
+ return self.submit_run(
672
+ build_id,
673
+ user_input,
674
+ session_id=session_id,
675
+ model=model,
676
+ sandbox=sandbox,
677
+ approval_mode=approval_mode,
678
+ collaboration_mode=collaboration_mode,
679
+ goal_objective=goal_objective,
680
+ runtime_input=runtime_input,
681
+ idempotency_key=idempotency_key,
682
+ on_event=on_event,
683
+ )
684
+
685
+ def _draft_exists(self, agent_id: str) -> bool:
686
+ try:
687
+ self.drafts.get(agent_id)
688
+ except Exception as exc:
689
+ if getattr(exc, "status_code", None) == 404:
690
+ return False
691
+ raise
692
+ return True
693
+
694
+ @staticmethod
695
+ def list_agent_templates() -> list[dict]:
696
+ return list_agent_templates()
697
+
698
+ def compose_agent_template(
699
+ self,
700
+ template_id: str,
701
+ request: AgentTemplateComposeRequest,
702
+ ) -> AgentTemplateComposition:
703
+ composers = {
704
+ "blank": compose_blank_agent,
705
+ "research": compose_research_agent,
706
+ }
707
+ composer = composers.get(template_id)
708
+ if composer is None:
709
+ from ksadk.studio.errors import StudioError
710
+
711
+ raise StudioError(
712
+ "AGENT_TEMPLATE_UNSUPPORTED",
713
+ "当前模板不支持自动编排",
714
+ status_code=422,
715
+ field="templateId",
716
+ details={"templateId": template_id},
717
+ )
718
+ composition = composer(self.workspace, self.catalog, request)
719
+ self._validate_bindings(composition.spec.bindings)
720
+ return composition
721
+
722
+ def update_agent(
723
+ self,
724
+ agent_id: str,
725
+ spec: AgentSpec,
726
+ *,
727
+ expected_revision: int,
728
+ ):
729
+ self._validate_bindings(spec.bindings)
730
+ updated = self.drafts.update(
731
+ agent_id,
732
+ spec,
733
+ expected_revision=expected_revision,
734
+ )
735
+ materialize_generated_runtime_source(self.workspace, updated)
736
+ return updated
737
+
738
+ def update_agent_bindings(
739
+ self,
740
+ agent_id: str,
741
+ bindings: AgentBindings,
742
+ *,
743
+ expected_revision: int,
744
+ ):
745
+ self._validate_bindings(bindings)
746
+ draft = self.drafts.get(agent_id)
747
+ spec = draft.spec.model_copy(deep=True)
748
+ spec.bindings = bindings
749
+ return self.drafts.update(
750
+ agent_id,
751
+ spec,
752
+ expected_revision=expected_revision,
753
+ )
754
+
755
+ def _validate_bindings(self, bindings: AgentBindings) -> None:
756
+ self.catalog.resolve_model(bindings)
757
+ self.catalog.resolve_models(bindings)
758
+ self.catalog.policy_preview(bindings)
759
+ self.catalog.resolve_mcp_servers(bindings)
760
+ self.catalog.resolve_mcp_tools(bindings)
761
+ self.catalog.resolve_skills(bindings)
762
+
763
+ def validate_agent(
764
+ self,
765
+ agent_id: str,
766
+ *,
767
+ level: Literal["schema", "build", "release"] = "build",
768
+ ):
769
+ return self.validator.validate(self.drafts.get(agent_id), level=level)
770
+
771
+ def submit_build(
772
+ self,
773
+ agent_id: str,
774
+ *,
775
+ revision: int,
776
+ idempotency_key: str,
777
+ ) -> Operation:
778
+ draft = self.drafts.get(agent_id)
779
+ if draft.metadata.revision != revision:
780
+ from ksadk.studio.errors import StudioError
781
+
782
+ raise StudioError(
783
+ "AGENT_REVISION_CONFLICT",
784
+ "Build revision 与当前 Agent 不一致",
785
+ status_code=409,
786
+ details={"expected": revision, "actual": draft.metadata.revision},
787
+ )
788
+ snapshot = draft.model_copy(deep=True)
789
+
790
+ async def runner():
791
+ return await asyncio.to_thread(self.builder.build, snapshot)
792
+
793
+ return self.operations.submit(
794
+ kind=OperationKind.BUILD,
795
+ resource_id=agent_id,
796
+ idempotency_key=idempotency_key,
797
+ runner=runner,
798
+ )
799
+
800
+ def submit_run(
801
+ self,
802
+ build_id: str,
803
+ user_input: str,
804
+ *,
805
+ session_id: str | None,
806
+ model: str | None = None,
807
+ sandbox: str | None = None,
808
+ approval_mode: str | None = None,
809
+ collaboration_mode: str | None = None,
810
+ goal_objective: str | None = None,
811
+ runtime_input: Any = None,
812
+ idempotency_key: str,
813
+ on_event: Callable[[RunEvent], None] | None = None,
814
+ ) -> Operation:
815
+ async def runner():
816
+ return await self.run_build(
817
+ build_id,
818
+ user_input,
819
+ session_id,
820
+ model=model,
821
+ sandbox=sandbox,
822
+ approval_mode=approval_mode,
823
+ collaboration_mode=collaboration_mode,
824
+ goal_objective=goal_objective,
825
+ runtime_input=runtime_input,
826
+ on_event=on_event,
827
+ )
828
+
829
+ return self.operations.submit(
830
+ kind=OperationKind.RUN,
831
+ resource_id=build_id,
832
+ idempotency_key=idempotency_key,
833
+ runner=runner,
834
+ )
835
+
836
+ async def run_build(
837
+ self,
838
+ build_id: str,
839
+ user_input: str,
840
+ session_id: str | None,
841
+ *,
842
+ model: str | None = None,
843
+ sandbox: str | None = None,
844
+ approval_mode: str | None = None,
845
+ collaboration_mode: str | None = None,
846
+ goal_objective: str | None = None,
847
+ runtime_input: Any = None,
848
+ on_event: Callable[[RunEvent], None] | None = None,
849
+ ):
850
+ """Execute any immutable Studio Build through the canonical executor."""
851
+
852
+ try:
853
+ spec = self.codex_runs.resolve(
854
+ build_id,
855
+ model=model,
856
+ sandbox=sandbox,
857
+ approval_mode=approval_mode,
858
+ )
859
+ except Exception as exc:
860
+ if getattr(exc, "status_code", None) != 404:
861
+ raise
862
+ spec = self.framework_runs.resolve(
863
+ build_id,
864
+ model=model,
865
+ approval_mode=approval_mode,
866
+ )
867
+ if collaboration_mode or goal_objective:
868
+ from dataclasses import replace
869
+
870
+ request_config = dict(spec.request_config)
871
+ if collaboration_mode:
872
+ request_config["collaboration_mode"] = collaboration_mode
873
+ if goal_objective:
874
+ request_config["goal_objective"] = goal_objective
875
+ request_config["ephemeral"] = False
876
+ spec = replace(spec, request_config=request_config)
877
+ return await self.run_service.run(
878
+ spec,
879
+ user_input,
880
+ runtime_input=runtime_input,
881
+ session_id=session_id,
882
+ on_event=on_event,
883
+ )
884
+
885
+ def submit_evaluation(
886
+ self,
887
+ build_id: str,
888
+ suite_refs: list[str],
889
+ *,
890
+ fail_fast: bool,
891
+ idempotency_key: str,
892
+ ) -> Operation:
893
+ async def runner():
894
+ return await self.evaluations.run(
895
+ build_id,
896
+ suite_refs,
897
+ fail_fast=fail_fast,
898
+ )
899
+
900
+ return self.operations.submit(
901
+ kind=OperationKind.EVALUATION,
902
+ resource_id=build_id,
903
+ idempotency_key=idempotency_key,
904
+ runner=runner,
905
+ )
906
+
907
+ def submit_public_evaluation(
908
+ self,
909
+ evalset_file: str,
910
+ target: TargetRef,
911
+ config: PublicEvaluationConfig,
912
+ *,
913
+ idempotency_key: str,
914
+ ) -> Operation:
915
+ """Queue the public CLI/Studio handoff without exposing adapter internals."""
916
+
917
+ try:
918
+ path = self.workspace.resolve(evalset_file, must_exist=True)
919
+ except StudioError:
920
+ raise
921
+ if not path.is_file():
922
+ raise StudioError(
923
+ "EVALSET_FILE_INVALID",
924
+ "EvalSet 必须是工作区内的文件",
925
+ status_code=422,
926
+ field="evalsetFile",
927
+ )
928
+ try:
929
+ evalset = load_evalset(path)
930
+ except EvalSetParseError as exc:
931
+ raise StudioError(
932
+ exc.code,
933
+ str(exc),
934
+ status_code=422,
935
+ field="evalsetFile",
936
+ ) from exc
937
+ target = self._normalize_public_evaluation_target(target)
938
+ request = PublicEvaluationRequest(
939
+ evalset=evalset,
940
+ target=target,
941
+ config=config,
942
+ report_dir=str(self.evaluation_storage.root),
943
+ )
944
+
945
+ async def runner():
946
+ try:
947
+ report = await execute_evaluation(request)
948
+ except EvaluationNotImplementedError as exc:
949
+ raise StudioError(
950
+ "EVALUATION_EXECUTOR_UNAVAILABLE",
951
+ str(exc),
952
+ status_code=501,
953
+ ) from exc
954
+ except EvaluationExecutionError as exc:
955
+ raise StudioError(
956
+ "EVALUATION_EXECUTION_FAILED",
957
+ str(exc),
958
+ status_code=502,
959
+ ) from exc
960
+ try:
961
+ self.evaluation_storage.write_report(report)
962
+ except EvaluationStorageError as exc:
963
+ raise StudioError(
964
+ "EVALUATION_REPORT_WRITE_FAILED",
965
+ "评测报告写入失败",
966
+ status_code=500,
967
+ ) from exc
968
+ return report
969
+
970
+ return self.operations.submit(
971
+ kind=OperationKind.EVALUATION,
972
+ resource_id=evalset.content_digest,
973
+ idempotency_key=idempotency_key,
974
+ runner=runner,
975
+ )
976
+
977
+ def list_public_evaluations(self):
978
+ return self.evaluation_storage.list_reports()
979
+
980
+ def get_public_evaluation(self, evaluation_id: str):
981
+ try:
982
+ return self.evaluation_storage.read_report(evaluation_id)
983
+ except EvaluationStorageError as exc:
984
+ raise StudioError(
985
+ "EVALUATION_NOT_FOUND",
986
+ "Evaluation 不存在",
987
+ status_code=404,
988
+ details={"id": evaluation_id},
989
+ ) from exc
990
+
991
+ def _normalize_public_evaluation_target(self, target: TargetRef) -> TargetRef:
992
+ if target.kind == TargetKind.A2A:
993
+ parsed = urlparse(target.locator)
994
+ if parsed.scheme not in {"http", "https"} or not parsed.netloc:
995
+ raise StudioError(
996
+ "EVALUATION_A2A_URL_INVALID",
997
+ "A2A target 必须是 http 或 https URL",
998
+ status_code=422,
999
+ field="target.locator",
1000
+ )
1001
+ return target
1002
+ path = self.workspace.resolve(target.locator, must_exist=True)
1003
+ if not path.is_dir():
1004
+ raise StudioError(
1005
+ "EVALUATION_TARGET_INVALID",
1006
+ "本地 target 必须是工作区内的目录",
1007
+ status_code=422,
1008
+ field="target.locator",
1009
+ )
1010
+ return target.model_copy(update={"locator": str(path)})
1011
+
1012
+ def submit_deployment(
1013
+ self,
1014
+ build_id: str,
1015
+ request: DeploymentRequest,
1016
+ *,
1017
+ idempotency_key: str,
1018
+ ) -> Operation:
1019
+ async def runner():
1020
+ return await self.cloud.deploy(build_id, request)
1021
+
1022
+ return self.operations.submit(
1023
+ kind=OperationKind.DEPLOYMENT,
1024
+ resource_id=build_id,
1025
+ idempotency_key=idempotency_key,
1026
+ runner=runner,
1027
+ )
1028
+
1029
+ def submit_rollback(
1030
+ self,
1031
+ deployment_id: str,
1032
+ *,
1033
+ target_build_id: str,
1034
+ idempotency_key: str,
1035
+ ) -> Operation:
1036
+ async def runner():
1037
+ return await self.cloud.rollback(
1038
+ deployment_id,
1039
+ target_build_id=target_build_id,
1040
+ )
1041
+
1042
+ return self.operations.submit(
1043
+ kind=OperationKind.DEPLOYMENT,
1044
+ resource_id=deployment_id,
1045
+ idempotency_key=idempotency_key,
1046
+ runner=runner,
1047
+ )
1048
+
1049
+ def get_settings(self) -> dict[str, Any]:
1050
+ path = self.workspace.resolve(".agentkit/settings.yaml")
1051
+ data: dict[str, Any] = {}
1052
+ if path.is_file():
1053
+ try:
1054
+ data = load_yaml_file(path) or {}
1055
+ except Exception:
1056
+ data = {}
1057
+ defaults = {
1058
+ "sandbox": os.environ.get("KSADK_CODEX_SANDBOX", "read_only"),
1059
+ "buildAfterCreate": True,
1060
+ "codexProxy": os.environ.get("KSADK_CODEX_USE_PROXY", "auto"),
1061
+ "cloudAccessKey": os.environ.get("KINGSOFTCLOUD_ACCESS_KEY", ""),
1062
+ "cloudSecretKey": os.environ.get("KINGSOFTCLOUD_SECRET_KEY", ""),
1063
+ "cloudRegion": os.environ.get("KSYUN_REGION", "cn-beijing-6"),
1064
+ "traceContent": os.environ.get("KSADK_STUDIO_TRACE_CONTENT", "1") != "0",
1065
+ }
1066
+ defaults.update({k: v for k, v in data.items() if v is not None})
1067
+ return defaults
1068
+
1069
+ def update_settings(self, payload: dict[str, Any]) -> dict[str, Any]:
1070
+ allowed = {
1071
+ "sandbox",
1072
+ "buildAfterCreate",
1073
+ "codexProxy",
1074
+ "cloudAccessKey",
1075
+ "cloudSecretKey",
1076
+ "cloudRegion",
1077
+ "traceContent",
1078
+ }
1079
+ data = {k: payload[k] for k in allowed if k in payload}
1080
+ if data.get("sandbox") and data["sandbox"] not in {
1081
+ "read-only",
1082
+ "workspace-write",
1083
+ "workspace-write-auto",
1084
+ "full-access",
1085
+ "read_only",
1086
+ "workspace_write",
1087
+ "workspace_write_auto",
1088
+ "full_access",
1089
+ }:
1090
+ raise StudioError("SETTINGS_INVALID", "sandbox 取值非法", status_code=422)
1091
+ path = self.workspace.resolve(".agentkit/settings.yaml")
1092
+ self.workspace.atomic_write_yaml(path, data)
1093
+ self._apply_settings_to_env(data)
1094
+ return self.get_settings()
1095
+
1096
+ def _apply_persisted_settings(self) -> None:
1097
+ """启动时把 settings.yaml 回填到进程环境。
1098
+
1099
+ update_settings 只在 PUT 时桥接 env;重启后 env 丢失,运行解析
1100
+ (如 _resolve_sandbox 读 KSADK_CODEX_SANDBOX)会回落默认,表现为
1101
+ 「设置页显示 workspace-write-auto,实际运行 read-only」。
1102
+ """
1103
+ path = self.workspace.resolve(".agentkit/settings.yaml")
1104
+ if not path.is_file():
1105
+ return
1106
+ try:
1107
+ data = load_yaml_file(path) or {}
1108
+ except Exception:
1109
+ return
1110
+ if isinstance(data, dict):
1111
+ self._apply_settings_to_env(data)
1112
+
1113
+ @staticmethod
1114
+ def _apply_settings_to_env(data: dict[str, Any]) -> None:
1115
+ if data.get("sandbox"):
1116
+ os.environ["KSADK_CODEX_SANDBOX"] = data["sandbox"]
1117
+ if data.get("codexProxy"):
1118
+ os.environ["KSADK_CODEX_USE_PROXY"] = data["codexProxy"]
1119
+ if data.get("cloudAccessKey"):
1120
+ os.environ["KINGSOFTCLOUD_ACCESS_KEY"] = data["cloudAccessKey"]
1121
+ if data.get("cloudSecretKey"):
1122
+ os.environ["KINGSOFTCLOUD_SECRET_KEY"] = data["cloudSecretKey"]
1123
+ if data.get("cloudRegion"):
1124
+ os.environ["KSYUN_REGION"] = data["cloudRegion"]
1125
+ if "traceContent" in data:
1126
+ os.environ["KSADK_STUDIO_TRACE_CONTENT"] = "1" if data["traceContent"] else "0"
1127
+
1128
+ @staticmethod
1129
+ def builtin_capabilities():
1130
+ return list(builtin_tool_contracts().values())
1131
+
1132
+ def list_capabilities(
1133
+ self,
1134
+ *,
1135
+ kind: str | None = None,
1136
+ query: str = "",
1137
+ ) -> list[dict]:
1138
+ return [
1139
+ item.model_dump(by_alias=True, exclude_none=True, mode="json")
1140
+ for item in self.catalog.list(kind=kind, query=query, limit=200)
1141
+ ]