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/a2a/executor.py CHANGED
@@ -1,190 +1,411 @@
1
- """A2A executor that adapts a KsADK runner to the A2A server contract."""
1
+ """A2ARuntimeExecutor — 把 RuntimeAdapter 桥接进 A2A 请求生命周期。
2
+
3
+ 契约 §7.2:A2A ``context_id`` ↔ Runtime ``session_id``;``canceled`` ↔
4
+ ``RuntimeAdapter.cancel(invocation_id)``。executor 不在此自造 cancel,而是委托
5
+ :class:`~ksadk.a2a.task_adapter.A2ARuntimeTaskAdapter`(其内部走 RuntimeAdapter.cancel,
6
+ G0.3 已冻结)。
7
+
8
+ wire 对象在 a2a-sdk 1.1.0 是 protobuf(``a2a_pb2``);文本用 ``Part(text=...)``,
9
+ 消息用 ``Message(role=Role.ROLE_AGENT, parts=[...])``。
10
+ """
2
11
 
3
12
  from __future__ import annotations
4
13
 
14
+ import inspect
5
15
  import json
6
16
  import logging
7
- from collections.abc import AsyncIterator
8
- from typing import Any
17
+ from typing import Any, Literal
9
18
 
10
19
  from a2a.server.agent_execution import AgentExecutor, RequestContext
11
20
  from a2a.server.events import EventQueue
12
21
  from a2a.server.tasks import TaskUpdater
13
- from a2a.types import Part, TextPart
22
+ from a2a.types import Part, Task, TaskState, TaskStatus
23
+ from a2a.utils.errors import TaskNotCancelableError
24
+
25
+ from ksadk.a2a.resume_store import A2AResumePayloadKind
26
+ from ksadk.events import EventType, RuntimeEvent
27
+ from ksadk.runtime import CancelResult, RunHandle
14
28
 
15
29
  logger = logging.getLogger(__name__)
16
30
 
31
+ #: ADK v2 A2A 集成扩展标记 URI(adk.dev/a2a/a2a-extension)。
32
+ #: 在 Task/status metadata 里塞入该 key 且值非空时,ADK ``RemoteA2aAgent`` 走
33
+ #: ``_handle_a2a_response_v2``——处理每个 ``artifact_update``(含 append=True 增量),
34
+ #: 不再像 v1 那样只放行首块+末块、丢弃中间增量(remote_a2a_agent.py:546/762)。
35
+ #: ksadk 自研 executor 必须带这个标记,否则编排侧 sub-agent 流式被压成"一次性"。
36
+ ADK_V2_INTEGRATION_EXTENSION_URI = "https://google.github.io/adk-docs/a2a/a2a-extension/"
37
+
38
+ #: 扩展标记值(与 google.adk ``A2aAgentExecutor._get_invocation_metadata`` 对齐)。
39
+ ADK_V2_INTEGRATION_METADATA: dict[str, Any] = {
40
+ ADK_V2_INTEGRATION_EXTENSION_URI: {"adk_agent_executor_v2": True}
41
+ }
42
+
43
+ _OUTPUT_SNAPSHOT_METADATA = {"ksadk_output_snapshot": True}
44
+ _ArtifactKind = Literal["text", "thinking"]
17
45
 
18
- class KsAgentExecutor(AgentExecutor):
19
- """Execute a KsADK runner inside the A2A request lifecycle."""
20
46
 
21
- def __init__(self, runner: Any, prefer_stream: bool = True) -> None:
22
- self.runner = runner
23
- self.prefer_stream = prefer_stream
47
+ def _thought_part(text: str) -> Part:
48
+ """构造可被 ADK RemoteA2aAgent 识别为 thought 的 A2A Part。"""
49
+ return Part(text=text, metadata={"adk_thought": True})
24
50
 
25
- async def execute(
51
+
52
+ class _ArtifactStreamEmitter:
53
+ """按连续类型分段输出 A2A artifact,并正确终止每个 artifact stream。"""
54
+
55
+ def __init__(self, updater: TaskUpdater, task_id: str) -> None:
56
+ self._updater = updater
57
+ self._task_id = task_id
58
+ self._active_kind: _ArtifactKind | None = None
59
+ self._segments: dict[_ArtifactKind, int] = {"text": 0, "thinking": 0}
60
+ self._emitted: dict[tuple[_ArtifactKind, int], int] = {}
61
+ self._pending: tuple[_ArtifactKind, str, bool, int] | None = None
62
+
63
+ async def push(
26
64
  self,
27
- context: RequestContext,
28
- event_queue: EventQueue,
65
+ kind: _ArtifactKind,
66
+ text: str,
67
+ *,
68
+ replace_snapshot: bool = False,
69
+ ) -> None:
70
+ if self._pending is not None:
71
+ switched = self._pending[0] != kind
72
+ await self._emit(self._pending, last_chunk=switched)
73
+ if self._active_kind != kind:
74
+ self._segments[kind] += 1
75
+ self._active_kind = kind
76
+ self._pending = (kind, text, replace_snapshot, self._segments[kind])
77
+
78
+ async def close(self) -> None:
79
+ if self._pending is None:
80
+ return
81
+ await self._emit(self._pending, last_chunk=True)
82
+ self._pending = None
83
+
84
+ async def _emit(
85
+ self,
86
+ pending: tuple[_ArtifactKind, str, bool, int],
87
+ *,
88
+ last_chunk: bool,
29
89
  ) -> None:
90
+ kind, text, replace_snapshot, segment = pending
91
+ key = (kind, segment)
92
+ self._emitted[key] = self._emitted.get(key, 0) + 1
93
+ is_reasoning = kind == "thinking"
94
+ base_id = (
95
+ f"{self._task_id}-reasoning"
96
+ if is_reasoning
97
+ else f"{self._task_id}-response"
98
+ )
99
+ artifact_id = base_id if segment == 1 else f"{base_id}-{segment}"
100
+ part = (
101
+ _thought_part(text)
102
+ if is_reasoning
103
+ else Part(
104
+ text=text,
105
+ metadata=(
106
+ dict(_OUTPUT_SNAPSHOT_METADATA)
107
+ if replace_snapshot
108
+ else None
109
+ ),
110
+ )
111
+ )
112
+ await self._updater.add_artifact(
113
+ parts=[part],
114
+ artifact_id=artifact_id,
115
+ name="reasoning" if is_reasoning else "response",
116
+ append=False if replace_snapshot else self._emitted[key] > 1,
117
+ last_chunk=last_chunk,
118
+ )
119
+
120
+
121
+ async def _enqueue_initial_task(context: RequestContext, event_queue: EventQueue) -> None:
122
+ """先入队初始 ``Task`` 对象,再发状态更新(a2a-sdk 1.1.0 生命周期要求:
123
+ TaskStatusUpdateEvent 之前必须已有 Task)。``current_task`` 为续跑任务时直接用,
124
+ 否则新建 submitted 任务。Task metadata 带 ADK v2 扩展标记,让 RemoteA2aAgent
125
+ 走 v2 handler 保留全部流式增量。
126
+ """
127
+ task = getattr(context, "current_task", None)
128
+ if task is None:
129
+ task = Task(
130
+ id=context.task_id,
131
+ context_id=context.context_id,
132
+ status=TaskStatus(state=TaskState.TASK_STATE_SUBMITTED),
133
+ metadata=dict(ADK_V2_INTEGRATION_METADATA),
134
+ )
135
+ await event_queue.enqueue_event(task)
136
+
137
+
138
+ class _InputRequired(Exception):
139
+ """Runtime 请求用户输入的信号(内部用于跳出 execute,task 停 input-required)。"""
140
+
141
+
142
+ class _RunCanceled(Exception):
143
+ """Runtime 已取消本次执行,executor 不得再发 completed。"""
144
+
145
+
146
+ class A2ARuntimeExecutor(AgentExecutor):
147
+ """在 A2A 请求生命周期内执行 RuntimeAdapter。
148
+
149
+ start/stream/resume/cancel 全部委托 ``A2ARuntimeTaskAdapter``;协议层不再
150
+ 保留 Runner fallback,因此所有入口共享同一 RuntimeEvent 合同。
151
+ """
152
+
153
+ def __init__(
154
+ self,
155
+ task_adapter: Any,
156
+ include_reasoning: bool = False,
157
+ ) -> None:
158
+ if task_adapter is None:
159
+ raise TypeError("task_adapter is required")
160
+ self.task_adapter = task_adapter
161
+ self.include_reasoning = include_reasoning
162
+
163
+ async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
164
+ current_task = getattr(context, "current_task", None)
165
+ durable_context_id = str(
166
+ getattr(current_task, "context_id", "") or context.context_id or "unknown-context"
167
+ )
30
168
  updater = TaskUpdater(
31
169
  event_queue=event_queue,
32
170
  task_id=context.task_id or "unknown-task",
33
- context_id=context.context_id or "unknown-context",
171
+ context_id=durable_context_id,
34
172
  )
173
+ is_resume = (
174
+ current_task is not None
175
+ and getattr(getattr(current_task, "status", None), "state", None)
176
+ == TaskState.TASK_STATE_INPUT_REQUIRED
177
+ )
178
+ interaction_response: Any = None
179
+ # Third-party/local adapters written before durable context mapping do not
180
+ # necessarily provide this optional lifecycle hook.
181
+ prepare_context = getattr(self.task_adapter, "prepare_context", None)
182
+ if callable(prepare_context):
183
+ await prepare_context(context)
184
+ if is_resume:
185
+ interaction_response = self.task_adapter.answer_from_context(context)
186
+ # Invalid resume tokens/decisions are request errors. Validate before emitting
187
+ # working so the durable Task remains input-required and retryable.
188
+ await self.task_adapter.validate_resume_task(
189
+ context.task_id or "",
190
+ context,
191
+ answer=interaction_response,
192
+ )
35
193
 
194
+ handle: RunHandle | None = None
36
195
  try:
37
- await updater.start_work()
38
- runner_input = self._build_runner_input(context)
39
- output = await self._run_runner(context, updater, runner_input)
196
+ # §7.2:当前任务处于 input-required 时,本条消息是续跑回包(checkpoint/resume)。
197
+ if not is_resume:
198
+ await _enqueue_initial_task(context, event_queue)
199
+ # start_work 不透传 metadata;直接 update_status 以带 ADK v2 扩展标记
200
+ # (RemoteA2aAgent 读 task/status metadata 决定走 v2 全增量 handler)。
201
+ await updater.update_status(
202
+ TaskState.TASK_STATE_WORKING,
203
+ metadata=dict(ADK_V2_INTEGRATION_METADATA),
204
+ )
205
+ if is_resume:
206
+ handle = await self.task_adapter.resume_task(
207
+ context.task_id or "",
208
+ context,
209
+ answer=interaction_response,
210
+ )
211
+ output = await self._run_runtime(context, updater, handle)
212
+ else:
213
+ handle = await self.task_adapter.start_task(
214
+ task_id=str(context.task_id or ""),
215
+ context=context,
216
+ input_data=context.get_user_input(),
217
+ )
218
+ output = await self._run_runtime(context, updater, handle)
219
+ # completed 携带全文消息:非流式消费端与 text.completed 投影(§ event_adapter
220
+ # message_to_event final)依赖它拿最终结果;流式消费端的重复由 adk_runner
221
+ # 在 handoff 分支对"增量累积"去重解决(不在此处删消息)。
40
222
  completion_message = (
41
- updater.new_agent_message(parts=[Part(root=TextPart(text=output))])
42
- if output
43
- else None
223
+ updater.new_agent_message(parts=[Part(text=output)]) if output else None
44
224
  )
45
225
  await updater.complete(message=completion_message)
46
- except Exception as exc:
47
- logger.exception("A2A task execution failed")
48
- error_text = self._coerce_text(exc)
226
+ await self._forget_task(context, handle)
227
+ except _InputRequired:
228
+ # runner 请求输入:task 已停在 input-required(附 resume token),不 complete。
229
+ logger.info("A2A task %s 进入 input-required", context.task_id)
230
+ except _RunCanceled:
231
+ logger.info("A2A task %s 已由 runtime 取消", context.task_id)
232
+ await self._forget_task(context, handle)
233
+ except Exception as exc: # noqa: BLE001
234
+ logger.error("A2A task execution failed (%s)", type(exc).__name__)
49
235
  await updater.failed(
50
- message=updater.new_agent_message(
51
- parts=[Part(root=TextPart(text=error_text))]
52
- )
236
+ message=updater.new_agent_message(parts=[Part(text="A2A task execution failed")])
53
237
  )
238
+ await self._forget_task(context, handle)
54
239
 
55
- async def cancel(
56
- self,
57
- context: RequestContext,
58
- event_queue: EventQueue,
59
- ) -> None:
240
+ async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None:
241
+ # §7.4:cancel 统一由 adapter 提供。有 RuntimeAdapter → 尊重其 CancelResult,
242
+ # 只有底层真取消(CANCELLED)才把协议 Task 置 canceled;其余状态如实抛
243
+ # TaskNotCancelableError 拒绝,不伪造终态。无 adapter 时底层状态未知,
244
+ # 同样拒绝取消。
245
+ current_task = getattr(context, "current_task", None)
60
246
  updater = TaskUpdater(
61
247
  event_queue=event_queue,
62
248
  task_id=context.task_id or "unknown-task",
63
- context_id=context.context_id or "unknown-context",
249
+ context_id=str(
250
+ getattr(current_task, "context_id", "") or context.context_id or "unknown-context"
251
+ ),
64
252
  )
65
- await updater.cancel(
66
- message=updater.new_agent_message(
67
- parts=[Part(root=TextPart(text="Request canceled"))]
253
+ result = await self.task_adapter.cancel_task(context.task_id or "", context)
254
+ # 只有底层真的接受了取消(已中断活跃 turn,或已登记 pending cancel)才把
255
+ # 协议 Task 置 canceled;其他结果如实拒绝,包括未来新增的 UNSUPPORTED。
256
+ if result not in (
257
+ CancelResult.INTERRUPTED_ACTIVE_TURN,
258
+ CancelResult.PENDING_CANCEL_RECORDED,
259
+ ):
260
+ result_value = getattr(result, "value", result)
261
+ raise TaskNotCancelableError(
262
+ message=f"underlying runtime cancel did not apply: {result_value}"
68
263
  )
264
+ await updater.cancel(
265
+ message=updater.new_agent_message(parts=[Part(text="Request canceled")])
69
266
  )
267
+ clear_resume_state = getattr(self.task_adapter, "clear_resume_state", None)
268
+ if callable(clear_resume_state):
269
+ result = clear_resume_state(context.task_id or "", context)
270
+ if inspect.isawaitable(result):
271
+ await result
70
272
 
71
- async def _run_runner(
273
+ async def _run_runtime(
72
274
  self,
73
275
  context: RequestContext,
74
276
  updater: TaskUpdater,
75
- runner_input: dict[str, Any],
76
- ) -> str:
77
- stream = getattr(self.runner, "stream", None)
78
- if self.prefer_stream and callable(stream):
79
- return await self._run_streaming(context, updater, stream, runner_input)
80
-
81
- result = await self.runner.invoke(runner_input)
82
- text = self._coerce_text(result)
83
- if text:
84
- await updater.add_artifact(
85
- parts=[Part(root=TextPart(text=text))],
86
- artifact_id=f"{context.task_id}-response",
87
- name="response",
88
- last_chunk=True,
89
- )
90
- return text
91
-
92
- async def _run_streaming(
93
- self,
94
- context: RequestContext,
95
- updater: TaskUpdater,
96
- stream: Any,
97
- runner_input: dict[str, Any],
277
+ handle: RunHandle,
98
278
  ) -> str:
99
279
  output_text = ""
100
- emitted_chunks = 0
101
- artifact_id = f"{context.task_id}-response"
102
-
103
- async for chunk, last_chunk in self._with_last_flag(stream(runner_input)):
104
- chunk_type = chunk.get("type") if isinstance(chunk, dict) else None
105
- if chunk_type == "final":
106
- final_text = (
107
- self._coerce_text(chunk.get("output"))
108
- if isinstance(chunk, dict)
109
- else ""
280
+ artifacts = _ArtifactStreamEmitter(updater, str(context.task_id))
281
+ reasoning_text = ""
282
+ input_required = False
283
+ input_prompt = "Input required"
284
+ checkpoint_id: str | None = None
285
+ call_id: str | None = None
286
+ payload_kind: A2AResumePayloadKind = "hitl_answer"
287
+
288
+ async for event in self.task_adapter.stream_task(handle):
289
+ if not isinstance(event, RuntimeEvent):
290
+ raise TypeError("RuntimeAdapter.stream must yield RuntimeEvent")
291
+ if event.event_type == EventType.RUN_FAILED:
292
+ raise RuntimeError(self._coerce_text(event.payload.get("error")))
293
+ if event.event_type == EventType.RUN_CANCELED:
294
+ await artifacts.close()
295
+ if not self._cancel_was_accepted(context, handle):
296
+ await updater.cancel(
297
+ message=updater.new_agent_message(parts=[Part(text="Request canceled")])
298
+ )
299
+ raise _RunCanceled()
300
+ if event.event_type == EventType.APPROVAL_REQUESTED:
301
+ input_required = True
302
+ payload_kind = "approval_decision"
303
+ call_id = (
304
+ str(event.payload.get("call_id") or event.payload.get("approval_id") or "")
305
+ or None
110
306
  )
111
- if not final_text:
112
- continue
113
- if not output_text:
114
- output_text = final_text
115
- elif final_text.startswith(output_text):
116
- suffix = final_text[len(output_text) :]
117
- output_text = final_text
118
- if suffix:
119
- emitted_chunks += 1
120
- await updater.add_artifact(
121
- parts=[Part(root=TextPart(text=suffix))],
122
- artifact_id=artifact_id,
123
- name="response",
124
- append=bool(emitted_chunks > 1),
125
- last_chunk=last_chunk,
126
- )
127
- continue
128
- else:
129
- output_text = final_text
130
- await updater.add_artifact(
131
- parts=[Part(root=TextPart(text=final_text))],
132
- artifact_id=artifact_id,
133
- name="response",
134
- append=False,
135
- last_chunk=last_chunk,
307
+ detail = event.payload.get("detail")
308
+ if isinstance(detail, dict):
309
+ input_prompt = self._coerce_text(
310
+ detail.get("prompt") or detail.get("message") or input_prompt
136
311
  )
137
312
  continue
138
-
139
- text = self._coerce_text(chunk)
313
+ if event.event_type == EventType.CHECKPOINT_CREATED:
314
+ checkpoint_id = str(event.payload.get("checkpoint_id") or "") or None
315
+ continue
316
+ if event.event_type == EventType.RUN_INTERRUPTED:
317
+ input_required = True
318
+ input_prompt = self._coerce_text(
319
+ event.payload.get("prompt") or event.payload.get("message") or input_prompt
320
+ )
321
+ continue
322
+ if event.event_type not in {
323
+ EventType.TEXT_DELTA,
324
+ EventType.TEXT_COMPLETED,
325
+ EventType.REASONING_DELTA,
326
+ EventType.REASONING_COMPLETED,
327
+ }:
328
+ continue
329
+ text = self._coerce_text(event.payload.get("text"))
140
330
  if not text:
141
331
  continue
142
- output_text += text
143
- emitted_chunks += 1
144
- await updater.add_artifact(
145
- parts=[Part(root=TextPart(text=text))],
146
- artifact_id=artifact_id,
147
- name="response",
148
- append=bool(emitted_chunks > 1),
149
- last_chunk=last_chunk,
332
+ if event.event_type == EventType.REASONING_COMPLETED:
333
+ if not self.include_reasoning:
334
+ continue
335
+ if not reasoning_text:
336
+ delta = text
337
+ reasoning_text = text
338
+ elif text.startswith(reasoning_text):
339
+ delta = text[len(reasoning_text) :]
340
+ reasoning_text = text
341
+ else:
342
+ delta = text
343
+ reasoning_text += text
344
+ if delta:
345
+ await artifacts.push("thinking", delta)
346
+ continue
347
+ if event.event_type == EventType.REASONING_DELTA:
348
+ if not self.include_reasoning:
349
+ continue
350
+ reasoning_text += text
351
+ await artifacts.push("thinking", text)
352
+ continue
353
+ # TEXT_COMPLETED 是累计全文,去重只发新增 suffix;TEXT_DELTA 默认是增量,
354
+ # 但 runner 显式标记 replace 时是权威快照。
355
+ if event.event_type == EventType.TEXT_COMPLETED:
356
+ if not output_text:
357
+ delta = text
358
+ output_text = text
359
+ replace_snapshot = False
360
+ elif text.startswith(output_text):
361
+ delta = text[len(output_text) :]
362
+ output_text = text
363
+ replace_snapshot = False
364
+ else:
365
+ delta = text
366
+ output_text = text
367
+ replace_snapshot = True
368
+ else:
369
+ delta = text
370
+ replace_snapshot = bool(event.payload.get("replace"))
371
+ output_text = text if replace_snapshot else output_text + text
372
+ if not delta:
373
+ continue
374
+ await artifacts.push("text", delta, replace_snapshot=replace_snapshot)
375
+ if self._cancel_was_accepted(context, handle):
376
+ await artifacts.close()
377
+ raise _RunCanceled()
378
+ await artifacts.close()
379
+ if input_required:
380
+ await self.task_adapter.persist_resume_state(
381
+ task_id=str(context.task_id or ""),
382
+ context=context,
383
+ handle=handle,
384
+ checkpoint_id=checkpoint_id,
385
+ call_id=call_id,
386
+ payload_kind=payload_kind,
150
387
  )
151
-
388
+ await updater.update_status(
389
+ TaskState.TASK_STATE_INPUT_REQUIRED,
390
+ message=updater.new_agent_message(parts=[Part(text=input_prompt)]),
391
+ metadata=dict(ADK_V2_INTEGRATION_METADATA),
392
+ )
393
+ raise _InputRequired()
152
394
  return output_text
153
395
 
154
- async def _with_last_flag(
155
- self,
156
- iterator: AsyncIterator[Any],
157
- ) -> AsyncIterator[tuple[Any, bool]]:
158
- try:
159
- previous = await anext(iterator)
160
- except StopAsyncIteration:
161
- return
396
+ def _cancel_was_accepted(self, context: RequestContext, handle: RunHandle) -> bool:
397
+ was_cancel_accepted = getattr(self.task_adapter, "was_cancel_accepted", None)
398
+ return bool(
399
+ callable(was_cancel_accepted)
400
+ and was_cancel_accepted(str(context.task_id or ""), context, handle)
401
+ )
162
402
 
163
- while True:
164
- try:
165
- current = await anext(iterator)
166
- except StopAsyncIteration:
167
- yield previous, True
168
- return
169
- yield previous, False
170
- previous = current
171
-
172
- @staticmethod
173
- def _build_runner_input(context: RequestContext) -> dict[str, Any]:
174
- metadata = dict(context.metadata)
175
- state = metadata.get("state", {})
176
- if not isinstance(state, dict):
177
- state = {}
178
-
179
- return {
180
- "input": context.get_user_input(),
181
- "task_id": context.task_id,
182
- "context_id": context.context_id,
183
- "session_id": context.context_id,
184
- "state": dict(state),
185
- "branch": metadata.get("branch", ""),
186
- "metadata": metadata,
187
- }
403
+ async def _forget_task(self, context: RequestContext, handle: RunHandle | None) -> None:
404
+ forget_task = getattr(self.task_adapter, "forget_task", None)
405
+ if handle is not None and callable(forget_task):
406
+ result = forget_task(str(context.task_id or ""), context, handle)
407
+ if inspect.isawaitable(result):
408
+ await result
188
409
 
189
410
  @classmethod
190
411
  def _coerce_text(cls, payload: Any) -> str:
@@ -199,3 +420,6 @@ class KsAgentExecutor(AgentExecutor):
199
420
  return cls._coerce_text(value)
200
421
  return json.dumps(payload, ensure_ascii=False, default=str)
201
422
  return str(payload)
423
+
424
+
425
+ __all__ = ["A2ARuntimeExecutor"]