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
ksadk/events/store.py ADDED
@@ -0,0 +1,317 @@
1
+ """RuntimeEventStore — 统一事件 store + 两类订阅 + projection (goal-10,H2 §4.3)。
2
+
3
+ 复用现有 ``SessionEvent(seq_id cursor)`` 持久化骨架(session service),**不另造存储、
4
+ 不改表**:RuntimeEvent 的 ``phase``/``payload``/``schema_version``/``user_id`` 打包进
5
+ ``SessionEvent.content``/``metadata``(均为自由 dict),并以 ``_RUNTIME_MARKER`` 标记区分
6
+ legacy session 事件(assistant_message/run_status 等),读取时只还原 runtime 事件。
7
+
8
+ - ``append`` / ``list``:RuntimeEvent ↔ SessionEvent 双向映射。
9
+ - ``subscribe_run``:单 invocation,终态(completed/failed/canceled)后关闭(对齐现有
10
+ run 级 SSE 语义,新 schema)。
11
+ - ``subscribe_session``:session 级 cursor stream,跨 invocation,支持 run 后 action 与
12
+ replay(A2UI 依赖)。
13
+ - ``project``:replay / 增量 projection(fold)。
14
+ - cursor 断线续传:订阅方持 ``last_seq_id``,断线后按 ``after_seq_id`` 重连,不丢不重。
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import asyncio
20
+ import logging
21
+ from typing import Any, AsyncIterator, Callable, Iterable, Optional
22
+
23
+ from ksadk.events.runtime_event import EventType, RuntimeEvent
24
+ from ksadk.sessions.base import SessionEvent
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ #: SessionEvent.metadata 中的标记:该条是由 RuntimeEvent 持久化来的(区分 legacy 事件)。
29
+ _RUNTIME_MARKER = "ksadk_runtime_event"
30
+ _A2A_TASK_AGENT_STATE_KEY = "__ksadk_a2a_task_agents"
31
+
32
+ #: run 终态(subscribe_run 遇到即关闭;interrupted 是 input-required 暂停,非终态)。
33
+ _RUN_TERMINAL_EVENT_TYPES = frozenset(
34
+ {
35
+ EventType.RUN_COMPLETED,
36
+ EventType.RUN_FAILED,
37
+ EventType.RUN_CANCELED,
38
+ }
39
+ )
40
+
41
+ #: 默认订阅轮询间隔(秒)与单条流上限(秒,防泄漏)。
42
+ _DEFAULT_POLL_INTERVAL = 0.25
43
+ _DEFAULT_STREAM_TIMEOUT = 5 * 60
44
+
45
+
46
+ # ---------------------------------------------------------------------------
47
+ # RuntimeEvent ↔ SessionEvent 映射
48
+ # ---------------------------------------------------------------------------
49
+
50
+
51
+ def runtime_event_to_session_event(event: RuntimeEvent) -> SessionEvent:
52
+ """把 RuntimeEvent 打包为 SessionEvent(content/metadata 承载新 schema 字段,不改表)。"""
53
+ event.validate_conformance()
54
+ return SessionEvent(
55
+ id=event.event_id,
56
+ session_id=event.session_id,
57
+ author=event.agent_id,
58
+ event_type=event.event_type,
59
+ content={"phase": event.phase, "payload": dict(event.payload)},
60
+ timestamp=event.timestamp,
61
+ seq_id=event.seq_id,
62
+ invocation_id=event.invocation_id,
63
+ metadata={
64
+ _RUNTIME_MARKER: True,
65
+ "user_id": event.user_id,
66
+ "schema_version": event.schema_version,
67
+ },
68
+ )
69
+
70
+
71
+ def session_event_to_runtime_event(event: SessionEvent) -> Optional[RuntimeEvent]:
72
+ """把 SessionEvent 还原为 RuntimeEvent;非 runtime 事件(无标记)返回 None。"""
73
+ if not (event.metadata or {}).get(_RUNTIME_MARKER):
74
+ return None
75
+ content = event.content or {}
76
+ return RuntimeEvent.create(
77
+ event.event_type,
78
+ agent_id=event.author,
79
+ user_id=str(event.metadata.get("user_id") or ""),
80
+ session_id=event.session_id,
81
+ invocation_id=event.invocation_id or "",
82
+ seq_id=event.seq_id,
83
+ payload=dict(content.get("payload") or {}),
84
+ phase=content.get("phase"),
85
+ event_id=event.id,
86
+ timestamp=event.timestamp,
87
+ )
88
+
89
+
90
+ # ---------------------------------------------------------------------------
91
+ # RuntimeEventStore
92
+ # ---------------------------------------------------------------------------
93
+
94
+
95
+ class RuntimeEventStore:
96
+ """统一事件 store(复用 session service 的 seq_id cursor 持久化骨架)。"""
97
+
98
+ def __init__(self, session_service: Any) -> None:
99
+ self._service = session_service
100
+
101
+ # ---- append ----
102
+
103
+ async def append(self, events: Iterable[RuntimeEvent]) -> list[RuntimeEvent]:
104
+ """持久化一组 RuntimeEvent,返回存储层分配 cursor 后的事件。"""
105
+ appended: list[RuntimeEvent] = []
106
+ for event in events:
107
+ appended.append(await self.append_one(event))
108
+ return appended
109
+
110
+ async def append_one(self, event: RuntimeEvent) -> RuntimeEvent:
111
+ """Idempotently persist one event using its durable ``event_id``.
112
+
113
+ Replayed wire events return their original store-assigned cursor. Reuse
114
+ of an ID for different content is rejected rather than silently losing a
115
+ legal event.
116
+ """
117
+ persisted, _created = await self.reserve_once(event)
118
+ return persisted
119
+
120
+ async def reserve_once(self, event: RuntimeEvent) -> tuple[RuntimeEvent, bool]:
121
+ """Durably claim ``event.event_id`` and report whether this caller won.
122
+
123
+ SQL backends enforce a unique event id, so this is also the command
124
+ reservation seam for side effects such as checkpoint resume. A loser
125
+ receives the existing identical fact with ``created=False`` and must
126
+ not repeat the side effect.
127
+ """
128
+ existing = await self._event_by_id(event.session_id, event.event_id)
129
+ if existing is not None:
130
+ self._assert_same_event(existing, event)
131
+ return existing, False
132
+ try:
133
+ stored = await self._service.append_event(
134
+ event.session_id, runtime_event_to_session_event(event)
135
+ )
136
+ except Exception:
137
+ # Durable backends enforce a unique event id. A concurrent writer
138
+ # may win between the read and append; resolve that race by reading
139
+ # the persisted fact and validating its content.
140
+ existing = await self._event_by_id(event.session_id, event.event_id)
141
+ if existing is None:
142
+ raise
143
+ self._assert_same_event(existing, event)
144
+ return existing, False
145
+ persisted = session_event_to_runtime_event(stored)
146
+ if persisted is None: # pragma: no cover - marker is set above by construction
147
+ raise RuntimeError("RuntimeEvent 持久化后缺少 runtime marker")
148
+ return persisted, True
149
+
150
+ async def _event_by_id(self, session_id: str, event_id: str) -> RuntimeEvent | None:
151
+ raw = await self._service.get_events(session_id)
152
+ for stored in raw:
153
+ if stored.id != event_id:
154
+ continue
155
+ return session_event_to_runtime_event(stored)
156
+ return None
157
+
158
+ @staticmethod
159
+ def _assert_same_event(existing: RuntimeEvent, candidate: RuntimeEvent) -> None:
160
+ comparable = (
161
+ "event_type",
162
+ "agent_id",
163
+ "user_id",
164
+ "session_id",
165
+ "invocation_id",
166
+ "phase",
167
+ "payload",
168
+ )
169
+ if any(getattr(existing, field) != getattr(candidate, field) for field in comparable):
170
+ raise ValueError(f"RuntimeEvent id collision for {candidate.event_id!r}")
171
+
172
+ async def set_task_agent(self, session_id: str, task_id: str, agent_id: str) -> None:
173
+ """Persist the outbound A2A task locator in session state."""
174
+ session = await self._service.get_session_metadata(session_id)
175
+ if session is None:
176
+ raise ValueError(f"A2A space session {session_id!r} not found")
177
+ current = await self._service.get_state(
178
+ session.agent_id,
179
+ session.user_id,
180
+ session.id,
181
+ scope="session",
182
+ )
183
+ mapping = dict((current.state if current else {}).get(_A2A_TASK_AGENT_STATE_KEY) or {})
184
+ existing = mapping.get(task_id)
185
+ if existing and existing != agent_id:
186
+ raise ValueError(f"A2A task {task_id!r} is already bound to another agent")
187
+ mapping[task_id] = agent_id
188
+ await self._service.update_state(
189
+ agent_id=session.agent_id,
190
+ user_id=session.user_id,
191
+ session_id=session.id,
192
+ scope="session",
193
+ state_delta={_A2A_TASK_AGENT_STATE_KEY: mapping},
194
+ )
195
+
196
+ async def get_task_agent(self, session_id: str, task_id: str) -> str | None:
197
+ """Resolve a persisted outbound A2A task locator."""
198
+ session = await self._service.get_session_metadata(session_id)
199
+ if session is None:
200
+ return None
201
+ current = await self._service.get_state(
202
+ session.agent_id,
203
+ session.user_id,
204
+ session.id,
205
+ scope="session",
206
+ )
207
+ mapping = dict((current.state if current else {}).get(_A2A_TASK_AGENT_STATE_KEY) or {})
208
+ value = mapping.get(task_id)
209
+ return str(value) if value else None
210
+
211
+ # ---- list ----
212
+
213
+ async def list(
214
+ self,
215
+ session_id: str,
216
+ *,
217
+ after_seq_id: int = 0,
218
+ before_seq_id: Optional[int] = None,
219
+ invocation_id: Optional[str] = None,
220
+ limit: Optional[int] = None,
221
+ ) -> list[RuntimeEvent]:
222
+ """按 seq cursor 读 RuntimeEvent(升序;可按 invocation 过滤 / before 上界回放)。"""
223
+ raw = await self._service.get_events(
224
+ session_id,
225
+ after_seq_id=after_seq_id,
226
+ before_seq_id=before_seq_id,
227
+ limit=limit,
228
+ )
229
+ events = [e for e in (session_event_to_runtime_event(se) for se in raw) if e is not None]
230
+ if invocation_id is not None:
231
+ events = [e for e in events if e.invocation_id == invocation_id]
232
+ events.sort(key=lambda e: e.seq_id)
233
+ return events
234
+
235
+ # ---- 两类订阅 ----
236
+
237
+ async def subscribe_run(
238
+ self,
239
+ session_id: str,
240
+ invocation_id: str,
241
+ *,
242
+ after_seq_id: int = 0,
243
+ poll_interval: float = _DEFAULT_POLL_INTERVAL,
244
+ timeout: float = _DEFAULT_STREAM_TIMEOUT,
245
+ ) -> AsyncIterator[RuntimeEvent]:
246
+ """单 invocation 订阅:只产该 invocation 的 RuntimeEvent,终态后关闭。
247
+
248
+ 断线续传:调用方持返回事件的 ``seq_id``,断线后以 ``after_seq_id`` 重连即可续传,
249
+ 不丢(>after 的全部重发)、不重(<=after 的不重发)。
250
+ """
251
+ last = int(after_seq_id or 0)
252
+ deadline = asyncio.get_event_loop().time() + timeout
253
+ while True:
254
+ events = await self.list(session_id, after_seq_id=last, invocation_id=invocation_id)
255
+ for event in events:
256
+ last = max(last, event.seq_id)
257
+ yield event
258
+ if event.event_type in _RUN_TERMINAL_EVENT_TYPES:
259
+ return
260
+ if asyncio.get_event_loop().time() > deadline:
261
+ return
262
+ await asyncio.sleep(poll_interval)
263
+
264
+ async def subscribe_session(
265
+ self,
266
+ session_id: str,
267
+ *,
268
+ after_seq_id: int = 0,
269
+ poll_interval: float = _DEFAULT_POLL_INTERVAL,
270
+ timeout: float = _DEFAULT_STREAM_TIMEOUT,
271
+ ) -> AsyncIterator[RuntimeEvent]:
272
+ """session 级 cursor stream:跨 invocation 产全部 RuntimeEvent(replay + live)。
273
+
274
+ 支持 run 后 action 与跨 invocation replay(A2UI 依赖);断线续传同 subscribe_run。
275
+ """
276
+ last = int(after_seq_id or 0)
277
+ deadline = asyncio.get_event_loop().time() + timeout
278
+ while True:
279
+ events = await self.list(session_id, after_seq_id=last)
280
+ for event in events:
281
+ last = max(last, event.seq_id)
282
+ yield event
283
+ if asyncio.get_event_loop().time() > deadline:
284
+ return
285
+ await asyncio.sleep(poll_interval)
286
+
287
+ # ---- projection / replay ----
288
+
289
+ async def project(
290
+ self,
291
+ session_id: str,
292
+ projection: Optional[Callable[[Any, RuntimeEvent], Any]] = None,
293
+ *,
294
+ initial: Any = None,
295
+ after_seq_id: int = 0,
296
+ before_seq_id: Optional[int] = None,
297
+ ) -> Any:
298
+ """replay / projection。
299
+
300
+ 默认(``projection=None``):返回按 seq 升序的 RuntimeEvent 序列(replay)。
301
+ 给定 ``projection(acc, event) -> acc``:自 ``initial`` 起 fold 全部事件,支持
302
+ 增量 projection(以 ``after_seq_id`` 从某个 checkpoint 续投影)。
303
+ """
304
+ events = await self.list(session_id, after_seq_id=after_seq_id, before_seq_id=before_seq_id)
305
+ if projection is None:
306
+ return events
307
+ acc = initial
308
+ for event in events:
309
+ acc = projection(acc, event)
310
+ return acc
311
+
312
+
313
+ __all__ = [
314
+ "RuntimeEventStore",
315
+ "runtime_event_to_session_event",
316
+ "session_event_to_runtime_event",
317
+ ]
@@ -0,0 +1,35 @@
1
+ """HarnessApp — 统一 Runtime 的可部署交付物 / composition root (goal-08)。"""
2
+
3
+ from ksadk.harness.app import HarnessApp, HarnessCapabilities, HarnessPlugin
4
+ from ksadk.harness.config import (
5
+ HarnessConfig,
6
+ HarnessConfigError,
7
+ McpToolSpec,
8
+ SandboxPolicy,
9
+ )
10
+ from ksadk.harness.reasoner import (
11
+ HarnessReasoner,
12
+ HarnessReasoningTurn,
13
+ HarnessToolCall,
14
+ LiteLLMHarnessReasoner,
15
+ )
16
+ from ksadk.harness.runtime import HarnessRuntime, HarnessRuntimeAdapter
17
+ from ksadk.harness.sandbox import HarnessSandboxExecutor, SandboxPolicyDenied
18
+
19
+ __all__ = [
20
+ "HarnessApp",
21
+ "HarnessCapabilities",
22
+ "HarnessConfig",
23
+ "HarnessConfigError",
24
+ "HarnessPlugin",
25
+ "HarnessReasoner",
26
+ "HarnessRuntime",
27
+ "HarnessRuntimeAdapter",
28
+ "HarnessReasoningTurn",
29
+ "HarnessSandboxExecutor",
30
+ "HarnessToolCall",
31
+ "LiteLLMHarnessReasoner",
32
+ "McpToolSpec",
33
+ "SandboxPolicy",
34
+ "SandboxPolicyDenied",
35
+ ]
ksadk/harness/app.py ADDED
@@ -0,0 +1,269 @@
1
+ """RuntimeAdapter-first deployable Harness composition root."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import tempfile
6
+ from dataclasses import dataclass, replace
7
+ from pathlib import Path
8
+ from typing import Any, Callable, Optional, Protocol, Sequence
9
+
10
+ from fastapi import FastAPI
11
+
12
+ from ksadk.harness.config import HarnessConfig
13
+ from ksadk.harness.reasoner import HarnessReasoner
14
+ from ksadk.harness.runtime import HarnessRuntimeAdapter
15
+ from ksadk.runtime import (
16
+ RuntimeAdapter,
17
+ RuntimeExecutor,
18
+ RuntimeLaunchContext,
19
+ RuntimeRegistry,
20
+ StartRequest,
21
+ )
22
+ from ksadk.runtime.factory import create_runtime_adapter
23
+ from ksadk.server.factory import RuntimeAppConfig, create_runtime_app
24
+ from ksadk.server.routes.routers import GROUP_ROUTERS, load_route_modules
25
+
26
+
27
+ class HarnessPlugin(Protocol):
28
+ def before_build(self, config: HarnessConfig) -> None: # pragma: no cover
29
+ ...
30
+
31
+ def after_build(self, app: FastAPI, config: HarnessConfig) -> None: # pragma: no cover
32
+ ...
33
+
34
+
35
+ _OVERRIDEABLE = ("model", "prompt")
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class HarnessCapabilities:
40
+ responses: bool = True
41
+ sessions: bool = True
42
+ files: bool = False
43
+ a2a: bool = False
44
+ agui: bool = False
45
+
46
+
47
+ class HarnessApp:
48
+ """Own one adapter/executor/context tuple for a deployable YAML agent."""
49
+
50
+ def __init__(
51
+ self,
52
+ config: HarnessConfig,
53
+ *,
54
+ plugins: Sequence[HarnessPlugin] = (),
55
+ adapter_builder: Optional[
56
+ Callable[[HarnessConfig, Path, HarnessReasoner | None], RuntimeAdapter]
57
+ ] = None,
58
+ reasoner: HarnessReasoner | None = None,
59
+ workspace_root: str | Path | None = None,
60
+ a2a: Any | None = None,
61
+ ) -> None:
62
+ self._config = config
63
+ self._plugins = list(plugins)
64
+ self._adapter_builder = adapter_builder
65
+ self._reasoner = reasoner
66
+ self._a2a = a2a
67
+ self._owned_workspace: tempfile.TemporaryDirectory[str] | None
68
+ if workspace_root is None:
69
+ self._owned_workspace = tempfile.TemporaryDirectory(prefix="ksadk-harness-")
70
+ resolved_workspace: str | Path = self._owned_workspace.name
71
+ else:
72
+ self._owned_workspace = None
73
+ resolved_workspace = workspace_root
74
+ self._workspace_root = Path(resolved_workspace).resolve()
75
+ self._adapter: RuntimeAdapter | None = None
76
+ self._fastapi_app: FastAPI | None = None
77
+ self._capabilities = HarnessCapabilities(a2a=a2a is not None)
78
+ self._runtime_type = "codex" if config.runtime == "codex" else "harness"
79
+ self._launch_context = RuntimeLaunchContext(
80
+ runtime_type=self._runtime_type,
81
+ project_dir=self._workspace_root,
82
+ config={
83
+ "model": config.model,
84
+ "base_instructions": config.prompt,
85
+ "sandbox_read_only": config.sandbox.read_only,
86
+ },
87
+ )
88
+ registry = RuntimeRegistry()
89
+ registry.register(self._runtime_type, lambda _context: self.adapter())
90
+ self._executor = RuntimeExecutor(registry)
91
+
92
+ from ksadk.sessions import create_session_service
93
+
94
+ self._session_service = create_session_service(
95
+ backend="memory",
96
+ project_dir=str(self._workspace_root),
97
+ )
98
+
99
+ @classmethod
100
+ def from_yaml(cls, path: str | Path, **kwargs: Any) -> "HarnessApp":
101
+ return cls(HarnessConfig.from_yaml(path), **kwargs)
102
+
103
+ @property
104
+ def config(self) -> HarnessConfig:
105
+ return self._config
106
+
107
+ @property
108
+ def workspace_root(self) -> Path:
109
+ return self._workspace_root
110
+
111
+ @property
112
+ def session_service(self) -> Any:
113
+ return self._session_service
114
+
115
+ @property
116
+ def capabilities(self) -> HarnessCapabilities:
117
+ return self._capabilities
118
+
119
+ @property
120
+ def executor(self) -> RuntimeExecutor:
121
+ return self._executor
122
+
123
+ @property
124
+ def launch_context(self) -> RuntimeLaunchContext:
125
+ return self._launch_context
126
+
127
+ def apply_overrides(self, overrides: Optional[dict[str, Any]]) -> HarnessConfig:
128
+ if not overrides:
129
+ return self._config
130
+ unknown = set(overrides) - set(_OVERRIDEABLE)
131
+ if unknown:
132
+ raise ValueError(
133
+ f"override 仅允许 {list(_OVERRIDEABLE)}(最小子集),不支持: {sorted(unknown)}"
134
+ )
135
+ return replace(self._config, **overrides)
136
+
137
+ def adapter(self, overrides: Optional[dict[str, Any]] = None) -> RuntimeAdapter:
138
+ if overrides is not None:
139
+ raise ValueError("adapter 不接受 invocation override;请传给 start(request)")
140
+ if self._adapter is not None:
141
+ return self._adapter
142
+ for plugin in self._plugins:
143
+ plugin.before_build(self._config)
144
+ if self._adapter_builder is not None:
145
+ adapter = self._adapter_builder(
146
+ self._config,
147
+ self._workspace_root,
148
+ self._reasoner,
149
+ )
150
+ elif self._runtime_type == "codex":
151
+ adapter = create_runtime_adapter(self._launch_context)
152
+ else:
153
+ adapter = HarnessRuntimeAdapter(
154
+ self._config,
155
+ reasoner=self._reasoner,
156
+ workspace_root=self._workspace_root,
157
+ )
158
+ if not isinstance(adapter, RuntimeAdapter):
159
+ raise TypeError("Harness adapter builder must return RuntimeAdapter")
160
+ self._adapter = adapter
161
+ return adapter
162
+
163
+ def _route_groups(self) -> set[str]:
164
+ groups = {"health_meta", "models", "feedback", "tools", "ui_bootstrap"}
165
+ if self._capabilities.responses:
166
+ groups.update({"run", "openai_compat"})
167
+ if self._capabilities.sessions:
168
+ groups.update({"sessions", "sessions_adk_compat"})
169
+ if self._capabilities.files:
170
+ groups.add("workspace")
171
+ if self._capabilities.agui:
172
+ groups.add("agui")
173
+ return groups
174
+
175
+ def _request_with_overrides(
176
+ self,
177
+ request: StartRequest,
178
+ overrides: Optional[dict[str, Any]],
179
+ ) -> StartRequest:
180
+ effective = self.apply_overrides(overrides)
181
+ metadata = dict(request.metadata or {})
182
+ model = request.model or effective.model
183
+ prompt = str(
184
+ request.config.get("base_instructions")
185
+ or request.config.get("instructions")
186
+ or request.config.get("prompt")
187
+ or effective.prompt
188
+ )
189
+ metadata["model_override"] = model
190
+ metadata["prompt_override"] = prompt
191
+ config = dict(request.config)
192
+ config["base_instructions"] = prompt
193
+ return request.model_copy(
194
+ update={
195
+ "model": model,
196
+ "config": config,
197
+ "metadata": metadata,
198
+ }
199
+ )
200
+
201
+ async def start(
202
+ self,
203
+ request: StartRequest,
204
+ overrides: Optional[dict[str, Any]] = None,
205
+ ):
206
+ return await self._executor.start(
207
+ self._launch_context,
208
+ self._request_with_overrides(request, overrides),
209
+ )
210
+
211
+ def stream(self, handle: Any):
212
+ return self._executor.stream(handle)
213
+
214
+ async def cancel(self, handle: Any):
215
+ return await self._executor.cancel(handle)
216
+
217
+ async def resume(self, handle: Any, target: Any, payload: Any = None):
218
+ return await self._executor.resume(handle, target, payload)
219
+
220
+ async def checkpoint(self, handle: Any):
221
+ return await self._executor.checkpoint(handle)
222
+
223
+ async def close(self, handle: Any):
224
+ return await self._executor.close(handle)
225
+
226
+ @staticmethod
227
+ def _configure_routes(app: FastAPI, state: Any, groups: set[str]) -> None:
228
+ del state
229
+ load_route_modules()
230
+ ordered = sorted(group for group in groups if group != "health_meta")
231
+ if "health_meta" in groups:
232
+ ordered.append("health_meta")
233
+ for group in ordered:
234
+ router = GROUP_ROUTERS.get(group)
235
+ if router is not None:
236
+ app.include_router(router)
237
+
238
+ def build_app(self, overrides: Optional[dict[str, Any]] = None) -> FastAPI:
239
+ if overrides is not None:
240
+ raise ValueError("build_app 不接受 invocation override;请传给 start(request)")
241
+ if self._fastapi_app is not None:
242
+ return self._fastapi_app
243
+ adapter = self.adapter()
244
+ app = create_runtime_app(
245
+ RuntimeAppConfig(
246
+ runtime_type=self._runtime_type,
247
+ route_groups=self._route_groups(),
248
+ a2a=self._a2a,
249
+ a2a_runtime_adapter=adapter if self._a2a is not None else None,
250
+ runtime_executor=self._executor,
251
+ launch_context=self._launch_context,
252
+ session_backend_provider=lambda: {
253
+ "Backend": "memory",
254
+ "Shared": False,
255
+ "ProductionSafe": False,
256
+ "ContinuityDefault": "local_only",
257
+ },
258
+ ),
259
+ self._configure_routes,
260
+ )
261
+ app.state.runtime.session_service = self._session_service
262
+ app.state.runtime.harness_capabilities = self._capabilities
263
+ for plugin in self._plugins:
264
+ plugin.after_build(app, self._config)
265
+ self._fastapi_app = app
266
+ return app
267
+
268
+
269
+ __all__ = ["HarnessApp", "HarnessCapabilities", "HarnessPlugin"]