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,192 @@
1
+ """Local evaluation suites and deterministic assertions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from collections.abc import Awaitable, Callable
7
+ from pathlib import Path
8
+ from typing import cast
9
+ from uuid import uuid4
10
+
11
+ from jsonschema import ( # type: ignore[import-untyped]
12
+ ValidationError as JSONSchemaValidationError,
13
+ )
14
+ from jsonschema import validate as validate_json # type: ignore[import-untyped]
15
+
16
+ from ksadk.studio.contracts import (
17
+ AssertionResult,
18
+ AssertionSpec,
19
+ EvaluationCaseResult,
20
+ EvaluationRun,
21
+ EvaluationSuite,
22
+ RunRecord,
23
+ RunStatus,
24
+ )
25
+ from ksadk.studio.errors import StudioError
26
+ from ksadk.studio.event_store import RunEventStore
27
+ from ksadk.studio.repository import BuildRepository, load_yaml_file
28
+ from ksadk.studio.workspace import Workspace
29
+
30
+
31
+ class EvaluationRunner:
32
+ def __init__(
33
+ self,
34
+ workspace: Workspace,
35
+ *,
36
+ run_agent: Callable[[str, str, str | None], Awaitable[RunRecord]],
37
+ event_store: RunEventStore,
38
+ build_repository: BuildRepository | None = None,
39
+ ) -> None:
40
+ self.workspace = workspace
41
+ self.run_agent = run_agent
42
+ self.event_store = event_store
43
+ self.build_repository = build_repository or BuildRepository(workspace)
44
+
45
+ async def run(
46
+ self,
47
+ build_id: str,
48
+ suite_refs: list[str],
49
+ *,
50
+ fail_fast: bool = False,
51
+ ) -> EvaluationRun:
52
+ build = self.build_repository.get(build_id)
53
+ suites = [
54
+ self._load_suite(build.agent_id, reference) for reference in suite_refs
55
+ ]
56
+ evaluation = EvaluationRun(
57
+ id=f"eval_{uuid4().hex}",
58
+ build_id=build_id,
59
+ status=RunStatus.RUNNING,
60
+ )
61
+ for suite in suites:
62
+ for case in suite.cases:
63
+ run = await self.run_agent(
64
+ build_id,
65
+ case.input,
66
+ f"eval_{evaluation.id}_{case.id}",
67
+ )
68
+ assertion_results = [
69
+ self._assert(assertion, run) for assertion in case.assertions
70
+ ]
71
+ passed = run.status == RunStatus.COMPLETED and all(
72
+ result.passed for result in assertion_results
73
+ )
74
+ evaluation.results.append(
75
+ EvaluationCaseResult(
76
+ case_id=case.id,
77
+ run_id=run.id,
78
+ passed=passed,
79
+ assertions=assertion_results,
80
+ )
81
+ )
82
+ if fail_fast and not passed:
83
+ break
84
+ if fail_fast and evaluation.results and not evaluation.results[-1].passed:
85
+ break
86
+ evaluation.total = len(evaluation.results)
87
+ evaluation.passed = sum(1 for result in evaluation.results if result.passed)
88
+ evaluation.failed = evaluation.total - evaluation.passed
89
+ evaluation.pass_rate = (
90
+ evaluation.passed / evaluation.total if evaluation.total else 0
91
+ )
92
+ evaluation.status = (
93
+ RunStatus.COMPLETED if evaluation.failed == 0 else RunStatus.FAILED
94
+ )
95
+ self._save(evaluation)
96
+ return evaluation
97
+
98
+ def get(self, evaluation_id: str) -> EvaluationRun:
99
+ path = self.workspace.resolve(
100
+ Path(".agentkit/evaluations") / f"{evaluation_id}.json"
101
+ )
102
+ if not path.is_file():
103
+ raise StudioError(
104
+ "EVALUATION_NOT_FOUND",
105
+ "Evaluation 不存在",
106
+ status_code=404,
107
+ details={"id": evaluation_id},
108
+ )
109
+ return cast(
110
+ EvaluationRun,
111
+ EvaluationRun.model_validate_json(path.read_text(encoding="utf-8")),
112
+ )
113
+
114
+ def _load_suite(self, agent_id: str, reference: str) -> EvaluationSuite:
115
+ candidates = [
116
+ Path("agents") / agent_id / reference,
117
+ Path(reference),
118
+ ]
119
+ for candidate in candidates:
120
+ path = self.workspace.resolve(candidate)
121
+ if path.is_file():
122
+ try:
123
+ return cast(
124
+ EvaluationSuite,
125
+ EvaluationSuite.model_validate(load_yaml_file(path)),
126
+ )
127
+ except ValueError as exc:
128
+ raise StudioError(
129
+ "EVALUATION_SUITE_INVALID",
130
+ "评测集格式无效",
131
+ status_code=422,
132
+ details={"reference": reference, "reason": str(exc)},
133
+ ) from exc
134
+ raise StudioError(
135
+ "EVALUATION_SUITE_NOT_FOUND",
136
+ "评测集不存在",
137
+ status_code=404,
138
+ details={"reference": reference},
139
+ )
140
+
141
+ def _assert(self, assertion: AssertionSpec, run: RunRecord) -> AssertionResult:
142
+ value = assertion.value
143
+ passed = False
144
+ message = ""
145
+ if assertion.type == "contains":
146
+ passed = str(value) in run.output
147
+ elif assertion.type == "equals":
148
+ passed = run.output == str(value)
149
+ elif assertion.type == "notContains":
150
+ passed = str(value) not in run.output
151
+ elif assertion.type == "maxLatencyMs":
152
+ passed = (run.duration_ms or 0) <= int(value)
153
+ elif assertion.type == "maxInputTokens":
154
+ passed = run.usage.input_tokens <= int(value)
155
+ elif assertion.type == "maxOutputTokens":
156
+ passed = run.usage.output_tokens <= int(value)
157
+ elif assertion.type == "jsonSchema":
158
+ try:
159
+ validate_json(json.loads(run.output), value)
160
+ passed = True
161
+ except (ValueError, JSONSchemaValidationError) as exc:
162
+ message = str(exc)
163
+ elif assertion.type in {"toolCalled", "toolNotCalled"}:
164
+ called = {
165
+ event.data.get("tool")
166
+ for event in self.event_store.events(run.id)
167
+ if event.type == "tool.requested"
168
+ }
169
+ passed = (
170
+ str(value) in called
171
+ if assertion.type == "toolCalled"
172
+ else str(value) not in called
173
+ )
174
+ if not message and not passed:
175
+ message = f"断言 {assertion.type} 未通过"
176
+ return AssertionResult(assertion=assertion, passed=passed, message=message)
177
+
178
+ def _save(self, evaluation: EvaluationRun) -> None:
179
+ directory = self.workspace.resolve(".agentkit/evaluations")
180
+ directory.mkdir(parents=True, exist_ok=True)
181
+ self.workspace.atomic_write_text(
182
+ directory / f"{evaluation.id}.json",
183
+ json.dumps(
184
+ evaluation.model_dump(
185
+ by_alias=True, exclude_none=True, mode="json"
186
+ ),
187
+ ensure_ascii=False,
188
+ sort_keys=True,
189
+ indent=2,
190
+ )
191
+ + "\n",
192
+ )
@@ -0,0 +1,284 @@
1
+ """Persistent local Run and Event store."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import shutil
7
+ from datetime import datetime, timezone
8
+ from pathlib import Path
9
+ from typing import List
10
+
11
+ from pydantic import ValidationError
12
+
13
+ from ksadk.studio.contracts import RunEvent, RunRecord, RunStatus
14
+ from ksadk.studio.errors import StudioError, not_found
15
+ from ksadk.studio.otel_trace import OtlpTraceStore
16
+ from ksadk.studio.workspace import Workspace
17
+
18
+
19
+ class RunEventStore:
20
+ def __init__(self, workspace: Workspace) -> None:
21
+ self.workspace = workspace
22
+ self.trace_store = OtlpTraceStore(workspace)
23
+
24
+ def _path(self, run_id: str) -> Path:
25
+ return self.workspace.resolve(Path(".agentkit/runs") / f"{run_id}.json")
26
+
27
+ def create(self, record: RunRecord) -> RunRecord:
28
+ path = self._path(record.id)
29
+ if path.exists():
30
+ raise StudioError("RUN_ALREADY_EXISTS", "Run 已存在", status_code=409)
31
+ self._write(record, [])
32
+ return record
33
+
34
+ def save(self, record: RunRecord) -> RunRecord:
35
+ _, events = self._read(record.id)
36
+ self._write(record, events)
37
+ return record
38
+
39
+ def append(self, run_id: str, event_type: str, data: dict) -> RunEvent:
40
+ record, events = self._read(run_id)
41
+ event = RunEvent(
42
+ id=len(events) + 1,
43
+ run_id=run_id,
44
+ type=event_type,
45
+ data=data,
46
+ )
47
+ events.append(event)
48
+ self._write(record, events)
49
+ return event
50
+
51
+ def get(self, run_id: str) -> RunRecord:
52
+ record, _ = self._read(run_id)
53
+ return record
54
+
55
+ def events(self, run_id: str, *, after: int = 0) -> list[RunEvent]:
56
+ _, events = self._read(run_id)
57
+ return [event for event in events if event.id > after]
58
+
59
+ def list_runs(
60
+ self,
61
+ *,
62
+ session_id: str | None = None,
63
+ agent_id: str | None = None,
64
+ ) -> List[RunRecord]:
65
+ records: list[RunRecord] = []
66
+ directory = self.workspace.resolve(".agentkit/runs")
67
+ for path in sorted(directory.glob("run_*.json")):
68
+ try:
69
+ payload = json.loads(path.read_text(encoding="utf-8"))
70
+ record = RunRecord.model_validate(payload["record"])
71
+ except (OSError, ValueError, KeyError, ValidationError):
72
+ continue
73
+ if session_id and record.session_id != session_id:
74
+ continue
75
+ if agent_id and record.agent_id != agent_id:
76
+ continue
77
+ records.append(record)
78
+ records.sort(
79
+ key=lambda item: (
80
+ item.started_at or item.completed_at or datetime.min.replace(tzinfo=timezone.utc)
81
+ ),
82
+ reverse=False,
83
+ )
84
+ return records
85
+
86
+ def delete_session(self, session_id: str) -> int:
87
+ """Delete every persisted run that belongs to one local chat session."""
88
+
89
+ deleted = 0
90
+ for record in self.list_runs(session_id=session_id):
91
+ path = self._path(record.id)
92
+ if path.is_file():
93
+ self.trace_store.delete(record.trace_id, purge=True)
94
+ path.unlink()
95
+ deleted += 1
96
+ return deleted
97
+
98
+ def delete_agent(
99
+ self,
100
+ agent_id: str,
101
+ *,
102
+ purge: bool,
103
+ trash_directory: Path | None = None,
104
+ ) -> int:
105
+ """Remove the persisted Runs and Trace events owned by one Agent."""
106
+
107
+ deleted = 0
108
+ for record in self.list_runs(agent_id=agent_id):
109
+ path = self._path(record.id)
110
+ if not path.is_file():
111
+ continue
112
+ if purge:
113
+ self.trace_store.delete(record.trace_id, purge=True)
114
+ path.unlink()
115
+ else:
116
+ if trash_directory is None:
117
+ raise ValueError("recoverable deletion requires a trash directory")
118
+ destination = self.workspace.resolve(trash_directory / "runs" / path.name)
119
+ destination.parent.mkdir(parents=True, exist_ok=True)
120
+ self.trace_store.delete(
121
+ record.trace_id,
122
+ purge=False,
123
+ trash_directory=trash_directory,
124
+ )
125
+ shutil.move(str(path), str(destination))
126
+ deleted += 1
127
+ return deleted
128
+
129
+ def recover_interrupted(self) -> int:
130
+ """Reconcile non-terminal records left behind by a stopped Studio.
131
+
132
+ Events are persisted before the final RunRecord update. A browser
133
+ disconnect or process stop can therefore leave a terminal event next
134
+ to a stale ``RUNNING`` record. On startup the event log wins; a run
135
+ without any terminal event is explicitly marked interrupted because
136
+ its in-memory runtime task cannot survive a Studio restart.
137
+ """
138
+
139
+ recovered = 0
140
+ for record in self.list_runs():
141
+ if record.status not in {
142
+ RunStatus.CREATED,
143
+ RunStatus.RUNNING,
144
+ RunStatus.PAUSED,
145
+ RunStatus.WAITING_INPUT,
146
+ }:
147
+ continue
148
+ events = self.events(record.id)
149
+ terminal = next(
150
+ (
151
+ event
152
+ for event in reversed(events)
153
+ if event.type
154
+ in {
155
+ "run.completed",
156
+ "run.failed",
157
+ "run.cancelled",
158
+ "run.interrupted",
159
+ }
160
+ ),
161
+ None,
162
+ )
163
+ if terminal is None:
164
+ terminal = self.append(
165
+ record.id,
166
+ "run.interrupted",
167
+ {
168
+ "status": "interrupted",
169
+ "reason": "studio_restarted",
170
+ },
171
+ )
172
+
173
+ if terminal.type == "run.completed":
174
+ record.status = RunStatus.COMPLETED
175
+ record.error = None
176
+ elif terminal.type == "run.failed":
177
+ record.status = RunStatus.FAILED
178
+ record.error = {
179
+ "code": "RUNTIME_RUN_FAILED",
180
+ "message": str(
181
+ terminal.data.get("error")
182
+ or terminal.data.get("message")
183
+ or "Agent 运行失败"
184
+ ),
185
+ }
186
+ elif terminal.type == "run.cancelled":
187
+ record.status = RunStatus.CANCELLED
188
+ record.error = {"code": "RUN_CANCELLED", "message": "运行已取消"}
189
+ else:
190
+ record.status = RunStatus.INTERRUPTED
191
+ record.error = {
192
+ "code": "RUN_INTERRUPTED",
193
+ "message": "Studio 重启后无法重新 attach 上一次本地运行",
194
+ }
195
+ record.completed_at = terminal.created_at
196
+ if record.started_at is not None:
197
+ record.duration_ms = max(
198
+ 0,
199
+ int((record.completed_at - record.started_at).total_seconds() * 1000),
200
+ )
201
+ self.save(record)
202
+ recovered += 1
203
+ return recovered
204
+
205
+ def trace(self, trace_id: str) -> dict:
206
+ return self.trace_store.get_trace_view(trace_id)
207
+
208
+ def trace_otlp(self, trace_id: str) -> dict:
209
+ return self.trace_store.get_otlp(trace_id)
210
+
211
+ def list_traces(
212
+ self,
213
+ *,
214
+ agent_id: str | None = None,
215
+ status: str | None = None,
216
+ limit: int = 200,
217
+ ) -> list[dict]:
218
+ return self.trace_store.list_trace_summaries(
219
+ agent_id=agent_id,
220
+ status=status,
221
+ limit=limit,
222
+ )
223
+
224
+ def list_traces_page(
225
+ self,
226
+ *,
227
+ agent_id: str | None = None,
228
+ status: str | None = None,
229
+ query: str = "",
230
+ limit: int = 50,
231
+ cursor: str | None = None,
232
+ sort: str = "startedAt:desc",
233
+ ) -> dict:
234
+ return self.trace_store.paginate_trace_summaries(
235
+ agent_id=agent_id,
236
+ status=status,
237
+ query=query,
238
+ limit=limit,
239
+ cursor=cursor,
240
+ sort=sort,
241
+ )
242
+
243
+ def trace_overview(
244
+ self,
245
+ *,
246
+ range_name: str = "24h",
247
+ agent_id: str | None = None,
248
+ status: str | None = None,
249
+ ) -> dict:
250
+ return self.trace_store.trace_overview(
251
+ range_name=range_name,
252
+ agent_id=agent_id,
253
+ status=status,
254
+ )
255
+
256
+ def _read(self, run_id: str) -> tuple[RunRecord, List[RunEvent]]:
257
+ path = self._path(run_id)
258
+ if not path.is_file():
259
+ raise not_found("run", run_id)
260
+ try:
261
+ payload = json.loads(path.read_text(encoding="utf-8"))
262
+ record = RunRecord.model_validate(payload["record"])
263
+ events = [RunEvent.model_validate(item) for item in payload["events"]]
264
+ return record, events
265
+ except (OSError, ValueError, KeyError, ValidationError) as exc:
266
+ raise StudioError(
267
+ "RUN_RECORD_INVALID",
268
+ "Run 记录损坏",
269
+ status_code=500,
270
+ details={"id": run_id},
271
+ ) from exc
272
+
273
+ def _write(self, record: RunRecord, events: List[RunEvent]) -> None:
274
+ payload = {
275
+ "record": record.model_dump(by_alias=True, exclude_none=True, mode="json"),
276
+ "events": [
277
+ event.model_dump(by_alias=True, exclude_none=True, mode="json") for event in events
278
+ ],
279
+ }
280
+ self.workspace.atomic_write_text(
281
+ self._path(record.id),
282
+ json.dumps(payload, ensure_ascii=False, sort_keys=True, indent=2) + "\n",
283
+ )
284
+ self.trace_store.sync(record, events)
@@ -0,0 +1,114 @@
1
+ """Resolve immutable ADK/LangGraph Studio builds into RuntimeLaunchContext."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+
7
+ from ksadk.detection.detector import FrameworkDetector
8
+ from ksadk.runtime import RuntimeLaunchContext
9
+ from ksadk.studio.errors import StudioError
10
+ from ksadk.studio.repository import BuildRepository
11
+ from ksadk.studio.run_service import StudioRunSpec
12
+ from ksadk.studio.workspace import Workspace
13
+ from ksadk.tools.gateway import normalize_tool_approval_mode
14
+
15
+
16
+ class FrameworkRunSpecResolver:
17
+ def __init__(
18
+ self,
19
+ workspace: Workspace,
20
+ *,
21
+ build_repository: BuildRepository | None = None,
22
+ ) -> None:
23
+ self.workspace = workspace
24
+ self.builds = build_repository or BuildRepository(workspace)
25
+
26
+ def resolve(
27
+ self,
28
+ build_id: str,
29
+ *,
30
+ model: str | None = None,
31
+ approval_mode: str | None = None,
32
+ ) -> StudioRunSpec:
33
+ build = self.builds.get(build_id)
34
+ runtime_type = build.runtime_type.strip().lower()
35
+ if runtime_type not in {"adk", "langgraph"}:
36
+ raise StudioError(
37
+ "BUILD_RUNTIME_UNSUPPORTED",
38
+ "Build 没有可由 RuntimeAdapter 启动的 ADK/LangGraph Runtime",
39
+ status_code=422,
40
+ details={"buildId": build_id, "runtimeType": runtime_type},
41
+ )
42
+ if not build.artifact_path:
43
+ raise StudioError("BUILD_NOT_READY", "Build 尚未生成制品", status_code=409)
44
+ artifact_root = self.workspace.resolve(build.artifact_path, must_exist=True).parent
45
+ bundle_root = artifact_root / "agent-bundle"
46
+ project_dir = bundle_root / "runtime"
47
+ if not project_dir.is_dir():
48
+ raise StudioError(
49
+ "BUILD_RUNTIME_SOURCE_MISSING",
50
+ "Build 缺少不可变 Runtime 源码快照",
51
+ status_code=500,
52
+ )
53
+ detection = FrameworkDetector(str(project_dir)).detect()
54
+ if not detection.is_valid or detection.type.value != runtime_type:
55
+ raise StudioError(
56
+ "BUILD_RUNTIME_DETECTION_MISMATCH",
57
+ "Build 中的 Runtime 源码与 Runtime Lock 不一致",
58
+ status_code=422,
59
+ details={
60
+ "expected": runtime_type,
61
+ "detected": detection.type.value,
62
+ },
63
+ )
64
+ selected_model = self._select_model(build.runtime_lock, model)
65
+ resolved_path = bundle_root / "resolved-agent-spec.json"
66
+ resolved = json.loads(resolved_path.read_text(encoding="utf-8"))
67
+ instructions = resolved.get("instructions") if isinstance(resolved, dict) else {}
68
+ request_config = {
69
+ "base_instructions": str((instructions or {}).get("system") or ""),
70
+ "entry_point": detection.entry_point,
71
+ "agent_variable": detection.agent_variable,
72
+ }
73
+ if approval_mode:
74
+ request_config["tool_approval_mode"] = normalize_tool_approval_mode(
75
+ approval_mode
76
+ )
77
+ return StudioRunSpec(
78
+ launch_context=RuntimeLaunchContext(
79
+ runtime_type=runtime_type,
80
+ project_dir=project_dir,
81
+ detection=detection,
82
+ config=dict(detection.raw_config or {}),
83
+ ),
84
+ build_id=build.id,
85
+ agent_id=build.agent_id,
86
+ model=selected_model,
87
+ request_config=request_config,
88
+ manifest_sha256=build.resolved_digest,
89
+ )
90
+
91
+ @staticmethod
92
+ def _select_model(runtime_lock: dict, requested: str | None) -> str:
93
+ allowed = [str(value) for value in runtime_lock.get("models") or [] if str(value)]
94
+ default = str(runtime_lock.get("model") or "").strip()
95
+ if default and default not in allowed:
96
+ allowed.insert(0, default)
97
+ selected = str(requested or default).strip()
98
+ if not selected:
99
+ raise StudioError(
100
+ "AGENT_MODEL_REQUIRED",
101
+ "Build 没有绑定可运行模型",
102
+ status_code=422,
103
+ )
104
+ if allowed and selected not in allowed:
105
+ raise StudioError(
106
+ "MODEL_NOT_BOUND",
107
+ "请求模型未绑定到当前 Agent Build",
108
+ status_code=422,
109
+ details={"model": selected, "allowedModels": allowed},
110
+ )
111
+ return selected
112
+
113
+
114
+ __all__ = ["FrameworkRunSpecResolver"]
@@ -0,0 +1,33 @@
1
+ """Server-owned local identifiers for Studio resources."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ import secrets
7
+ from collections.abc import Callable
8
+
9
+ from ksadk.studio.errors import StudioError
10
+
11
+ _GENERATED_AGENT_SLUG = re.compile(r"^agentkit-[0-9a-f]{8}$")
12
+
13
+
14
+ def generate_agent_slug(exists: Callable[[str], bool]) -> str:
15
+ """Allocate a short opaque Agent ID without trusting a client-side default."""
16
+
17
+ for _attempt in range(32):
18
+ candidate = f"agentkit-{secrets.token_hex(4)}"
19
+ if not exists(candidate):
20
+ return candidate
21
+ raise StudioError(
22
+ "AGENT_ID_EXHAUSTED",
23
+ "无法分配唯一的本地标识",
24
+ status_code=503,
25
+ field="slug",
26
+ )
27
+
28
+
29
+ def is_generated_agent_slug(value: str) -> bool:
30
+ return bool(_GENERATED_AGENT_SLUG.fullmatch(str(value or "").strip()))
31
+
32
+
33
+ __all__ = ["generate_agent_slug", "is_generated_agent_slug"]