agentengine-sdk-python 0.8.1__py3-none-any.whl → 0.8.2__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 (411) hide show
  1. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +22 -2
  2. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/RECORD +356 -222
  3. ksadk/a2a/_space_client_events.py +381 -0
  4. ksadk/a2a/event_adapter.py +156 -64
  5. ksadk/a2a/executor.py +179 -63
  6. ksadk/a2a/space_client.py +6 -333
  7. ksadk/a2ui/core.py +222 -53
  8. ksadk/agui/_agent_helpers.py +243 -0
  9. ksadk/agui/a2ui_projection.py +12 -5
  10. ksadk/agui/agent.py +443 -259
  11. ksadk/api/client.py +525 -27
  12. ksadk/builders/code_builder.py +284 -8
  13. ksadk/builders/container_builder.py +8 -1
  14. ksadk/builders/managed_runtime_builder.py +39 -35
  15. ksadk/cli/__init__.py +17 -0
  16. ksadk/cli/cmd_dashboard.py +15 -1
  17. ksadk/cli/cmd_deploy.py +10 -2
  18. ksadk/cli/cmd_eval.py +66 -9
  19. ksadk/cli/cmd_evalset.py +284 -0
  20. ksadk/cli/cmd_files.py +5 -1
  21. ksadk/cli/cmd_hermes.py +1 -126
  22. ksadk/cli/cmd_invoke.py +28 -38
  23. ksadk/cli/cmd_managed_runtime.py +95 -0
  24. ksadk/cli/cmd_observe.py +85 -0
  25. ksadk/cli/cmd_openclaw.py +1 -435
  26. ksadk/cli/cmd_replay.py +28 -4
  27. ksadk/cli/cmd_studio.py +99 -8
  28. ksadk/cli/cmd_web.py +10 -2
  29. ksadk/cli/hermes_env.py +151 -0
  30. ksadk/cli/invoke_payload.py +49 -0
  31. ksadk/cli/openclaw_env.py +458 -0
  32. ksadk/codex/client.py +180 -30
  33. ksadk/codex/runtime.py +428 -326
  34. ksadk/configs/env_registry.py +66 -12
  35. ksadk/configs/env_registry_pcm.py +181 -0
  36. ksadk/configs/env_var_spec.py +18 -0
  37. ksadk/configs/global_config.py +5 -0
  38. ksadk/context_engine/__init__.py +98 -0
  39. ksadk/context_engine/assembler.py +176 -0
  40. ksadk/context_engine/baseline.py +419 -0
  41. ksadk/context_engine/cache_observability.py +228 -0
  42. ksadk/context_engine/capabilities.py +443 -0
  43. ksadk/context_engine/contributors.py +344 -0
  44. ksadk/context_engine/hosted_pipeline.py +417 -0
  45. ksadk/context_engine/models.py +117 -0
  46. ksadk/context_engine/planner.py +698 -0
  47. ksadk/context_engine/policies.py +319 -0
  48. ksadk/context_engine/projection.py +31 -0
  49. ksadk/context_engine/shadow_plan.py +266 -0
  50. ksadk/context_engine/tokenizer.py +164 -0
  51. ksadk/conversations/context.py +126 -6
  52. ksadk/conversations/message_projection.py +292 -28
  53. ksadk/conversations/model_context.py +49 -3
  54. ksadk/conversations/runtime_compaction.py +207 -5
  55. ksadk/conversations/runtime_input.py +184 -2
  56. ksadk/conversations/runtime_invocation.py +81 -3
  57. ksadk/conversations/runtime_observability.py +141 -0
  58. ksadk/conversations/runtime_payloads.py +42 -0
  59. ksadk/conversations/runtime_preparation.py +272 -2
  60. ksadk/conversations/runtime_resume.py +20 -1
  61. ksadk/conversations/runtime_stream_events.py +94 -9
  62. ksadk/conversations/semantic_summary.py +311 -1
  63. ksadk/conversations/session_lock.py +51 -0
  64. ksadk/deployment/env_forward.py +72 -0
  65. ksadk/deployment/managed_runtime.py +5 -0
  66. ksadk/deployment/providers/serverless.py +143 -69
  67. ksadk/evaluation/__init__.py +32 -0
  68. ksadk/evaluation/a2a_adapter.py +9 -1
  69. ksadk/evaluation/adapters.py +18 -5
  70. ksadk/evaluation/agent_eval_client.py +395 -0
  71. ksadk/evaluation/cloud_binding.py +80 -0
  72. ksadk/evaluation/cloud_converter.py +194 -0
  73. ksadk/evaluation/cloud_service.py +199 -0
  74. ksadk/evaluation/contracts.py +73 -4
  75. ksadk/evaluation/evaluators.py +183 -17
  76. ksadk/evaluation/evidence.py +258 -0
  77. ksadk/evaluation/executor.py +31 -6
  78. ksadk/evaluation/local_adapter.py +550 -0
  79. ksadk/evaluation/service_env.py +27 -0
  80. ksadk/evaluation/studio_build_adapter.py +253 -0
  81. ksadk/evaluation/target.py +15 -6
  82. ksadk/events/__init__.py +13 -13
  83. ksadk/events/_v1_compat/__init__.py +1 -0
  84. ksadk/events/_v1_compat/models.py +299 -0
  85. ksadk/events/_v1_compat/parser.py +247 -0
  86. ksadk/events/_v1_compat/projection.py +753 -0
  87. ksadk/events/adapters/__init__.py +34 -0
  88. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  89. ksadk/events/adapters/_a2a_support.py +275 -0
  90. ksadk/events/adapters/_codex_interactions.py +375 -0
  91. ksadk/events/adapters/_codex_items.py +801 -0
  92. ksadk/events/adapters/_codex_validators.py +311 -0
  93. ksadk/events/adapters/_langgraph_support.py +785 -0
  94. ksadk/events/adapters/a2a.py +841 -0
  95. ksadk/events/adapters/adk.py +503 -0
  96. ksadk/events/adapters/codex.py +717 -0
  97. ksadk/events/adapters/langgraph.py +745 -0
  98. ksadk/events/canonical.py +440 -0
  99. ksadk/events/canonical_replay.py +497 -0
  100. ksadk/events/canonical_store.py +468 -0
  101. ksadk/events/cold_recovery.py +257 -0
  102. ksadk/events/content.py +89 -0
  103. ksadk/events/identity.py +86 -0
  104. ksadk/events/pipeline.py +455 -0
  105. ksadk/events/projections.py +66 -0
  106. ksadk/events/reducer.py +661 -0
  107. ksadk/events/replay.py +3 -36
  108. ksadk/events/runtime_event.py +20 -265
  109. ksadk/events/session_event.py +324 -0
  110. ksadk/events/store.py +3 -316
  111. ksadk/events/v1_compat.py +41 -0
  112. ksadk/harness/runtime.py +160 -57
  113. ksadk/identity/resolver.py +4 -3
  114. ksadk/interaction/__init__.py +28 -0
  115. ksadk/interaction/contracts.py +136 -0
  116. ksadk/interaction/ledger.py +189 -0
  117. ksadk/interaction/provider.py +122 -0
  118. ksadk/interaction/providers/__init__.py +52 -0
  119. ksadk/interaction/providers/adk.py +40 -0
  120. ksadk/interaction/providers/codex.py +94 -0
  121. ksadk/interaction/providers/langgraph.py +58 -0
  122. ksadk/kernel/__init__.py +117 -0
  123. ksadk/kernel/authorization.py +258 -0
  124. ksadk/kernel/bootstrap.py +1074 -0
  125. ksadk/kernel/contract_fingerprints.py +61 -0
  126. ksadk/kernel/contracts.py +362 -0
  127. ksadk/kernel/control.py +219 -0
  128. ksadk/kernel/errors.py +79 -0
  129. ksadk/kernel/ingress.py +1102 -0
  130. ksadk/kernel/mapping.py +111 -0
  131. ksadk/kernel/memory_store.py +1133 -0
  132. ksadk/kernel/postgres_store.py +1756 -0
  133. ksadk/kernel/recovery.py +452 -0
  134. ksadk/kernel/runtime_identity.py +103 -0
  135. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  136. ksadk/kernel/sqlite_store.py +1410 -0
  137. ksadk/kernel/state.py +145 -0
  138. ksadk/kernel/store.py +232 -0
  139. ksadk/kernel/worker.py +953 -0
  140. ksadk/knowledge_base/client.py +7 -0
  141. ksadk/knowledge_base/service.py +32 -5
  142. ksadk/memory/__init__.py +61 -0
  143. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  144. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  145. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  146. ksadk/memory/adk/backends/sdk_ltm_backend.py +384 -2
  147. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  148. ksadk/memory/coordinator.py +461 -0
  149. ksadk/memory/events.py +202 -0
  150. ksadk/memory/extraction.py +228 -0
  151. ksadk/memory/ltm_backend_factory.py +16 -3
  152. ksadk/memory/models.py +316 -0
  153. ksadk/memory/policy.py +215 -0
  154. ksadk/memory/provider.py +47 -0
  155. ksadk/memory/provider_adapter.py +159 -0
  156. ksadk/memory/provider_resolver.py +71 -0
  157. ksadk/memory/providers/__init__.py +5 -0
  158. ksadk/memory/providers/local_sqlite.py +490 -0
  159. ksadk/memory/resolved_policy.py +145 -0
  160. ksadk/memory/service.py +188 -6
  161. ksadk/model_proxy/bootstrap.py +16 -9
  162. ksadk/model_proxy/detect.py +202 -9
  163. ksadk/model_proxy/namespace.py +39 -15
  164. ksadk/model_proxy/server.py +24 -5
  165. ksadk/model_proxy/transform.py +60 -2
  166. ksadk/observability/__init__.py +25 -0
  167. ksadk/observability/session_log.py +420 -0
  168. ksadk/observability/trajectory.py +105 -0
  169. ksadk/prompts/__init__.py +71 -0
  170. ksadk/prompts/compiler.py +215 -0
  171. ksadk/prompts/models.py +82 -0
  172. ksadk/prompts/projection.py +89 -0
  173. ksadk/prompts/resolved.py +137 -0
  174. ksadk/prompts/sources.py +233 -0
  175. ksadk/runners/_langgraph_runner_streams.py +822 -0
  176. ksadk/runners/adk_runner.py +5 -5
  177. ksadk/runners/base_runner.py +16 -0
  178. ksadk/runners/factory.py +1 -2
  179. ksadk/runners/langgraph_runner.py +198 -437
  180. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  181. ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
  182. ksadk/runtime/adapter.py +118 -2
  183. ksadk/runtime/conversation_execution.py +316 -182
  184. ksadk/runtime/executor.py +144 -3
  185. ksadk/runtime/factory.py +193 -7
  186. ksadk/runtime/hosted_finalizer.py +268 -0
  187. ksadk/runtime/launch.py +14 -1
  188. ksadk/runtime/preprocessing.py +25 -3
  189. ksadk/runtime/runner_adapter.py +288 -508
  190. ksadk/runtime/usage.py +33 -0
  191. ksadk/sandbox/backends/e2b.py +35 -2
  192. ksadk/server/composition.py +8 -0
  193. ksadk/server/factory.py +69 -6
  194. ksadk/server/routes/kernel_ingress.py +258 -0
  195. ksadk/server/routes/openai_compat.py +88 -8
  196. ksadk/server/routes/projection.py +35 -20
  197. ksadk/server/routes/run.py +94 -0
  198. ksadk/server/routes/sessions.py +2 -0
  199. ksadk/server/routes/streaming.py +5 -2
  200. ksadk/server/static/assets/{ArtifactsPanel-CakCqxEN.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
  201. ksadk/server/static/assets/{CodeBlock-CynLknyO.js → CodeBlock-DOH6MVcn.js} +4 -4
  202. ksadk/server/static/assets/{MathMessageMarkdown-3sQdOysS.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
  203. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  204. ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
  205. ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
  206. ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
  207. ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
  208. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
  209. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
  210. ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
  211. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
  212. ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
  213. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
  214. ksadk/server/static/assets/{chunk-FMBD7UC4-B_fH2YuH.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
  215. ksadk/server/static/assets/{chunk-ND2GUHAM-D6rFLaVV.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
  216. ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
  217. ksadk/server/static/assets/{chunk-4BX2VUAB-B9drTgOW.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
  218. ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
  219. ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
  220. ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
  221. ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
  222. ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
  223. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
  224. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
  225. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-ChNs_Mdk.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
  226. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
  227. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
  228. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  229. ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
  230. ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
  231. ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
  232. ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
  233. ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
  234. ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
  235. ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
  236. ksadk/server/static/assets/{dist-Dli7qW-B.js → dist-8hqcx0sU.js} +1 -1
  237. ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
  238. ksadk/server/static/assets/{dist-C1sz5Eo3.js → dist-BE7bu-DL.js} +1 -1
  239. ksadk/server/static/assets/{dist-fhOuWds5.js → dist-BVDffZ0U.js} +1 -1
  240. ksadk/server/static/assets/{dist-BjOdlDjj.js → dist-BX8z72IC.js} +1 -1
  241. ksadk/server/static/assets/{dist-DsHPdk3W.js → dist-Bf2M8m3N.js} +1 -1
  242. ksadk/server/static/assets/{dist-o2OVmKvt.js → dist-BjU6y-A2.js} +1 -1
  243. ksadk/server/static/assets/{dist-DWKByxWV.js → dist-BytlxIDT.js} +1 -1
  244. ksadk/server/static/assets/{dist-DJN_6Y39.js → dist-CSh_DE14.js} +1 -1
  245. ksadk/server/static/assets/{dist-DQU9EWw-.js → dist-CXYYBw3_.js} +1 -1
  246. ksadk/server/static/assets/{dist-4N2NMVYg.js → dist-C_wsv-Qd.js} +1 -1
  247. ksadk/server/static/assets/{dist-gLnrGsoU.js → dist-ClxGviKw.js} +1 -1
  248. ksadk/server/static/assets/{dist-j6Dxmf_j.js → dist-CttYUqzS.js} +1 -1
  249. ksadk/server/static/assets/{dist-D6MpCZtz.js → dist-DNp6rLRA.js} +1 -1
  250. ksadk/server/static/assets/{dist-BB3-OwTQ.js → dist-DUX-id_F.js} +1 -1
  251. ksadk/server/static/assets/{dist-_pHPTyZ-.js → dist-DmldrHd_.js} +1 -1
  252. ksadk/server/static/assets/{dist-CWV4lDr1.js → dist-DnfXs8Vn.js} +2 -2
  253. ksadk/server/static/assets/{dist-B5oS1zcj.js → dist-Dq9gLD7L.js} +1 -1
  254. ksadk/server/static/assets/{dist-B-jNR6Vn.js → dist-W-TIVntx.js} +1 -1
  255. ksadk/server/static/assets/{dist-BIlKoW0k.js → dist-dDdADKFA.js} +1 -1
  256. ksadk/server/static/assets/{dist-X4TnqwOK.js → dist-dydu68Fl.js} +1 -1
  257. ksadk/server/static/assets/{dist-CmZHzlwZ.js → dist-ngtN0DJB.js} +1 -1
  258. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
  259. ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
  260. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
  261. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
  262. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
  263. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
  264. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
  265. ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
  266. ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
  267. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
  268. ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
  269. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-K0OOfVna.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
  270. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-8LeOJaZp.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
  271. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-C6uCgZrW.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
  272. ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
  273. ksadk/server/static/assets/{linear-hdBcYzM8.js → linear-BHjG8b-J.js} +1 -1
  274. ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
  275. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-Bjy_2v4_.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
  276. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
  277. ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
  278. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
  279. ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
  280. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-BmkRbwCg.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
  281. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
  282. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
  283. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
  284. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
  285. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
  286. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
  287. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
  288. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-l6iXmU65.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
  289. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-Cq6UBeQB.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
  290. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
  291. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
  292. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
  293. ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
  294. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
  295. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-DEz24vV0.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
  296. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
  297. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
  298. ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
  299. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
  300. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
  301. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
  302. ksadk/server/static/index.html +2 -2
  303. ksadk/sessions/__init__.py +26 -9
  304. ksadk/sessions/_local_service_sync.py +688 -0
  305. ksadk/sessions/_local_tables.py +21 -0
  306. ksadk/sessions/_postgres_schema.py +305 -0
  307. ksadk/sessions/_postgres_tables.py +15 -0
  308. ksadk/sessions/base.py +80 -1
  309. ksadk/sessions/in_memory.py +53 -2
  310. ksadk/sessions/local_service.py +63 -604
  311. ksadk/sessions/postgres_service.py +58 -148
  312. ksadk/sessions/resilient.py +35 -1
  313. ksadk/studio/api.py +577 -25
  314. ksadk/studio/api_contracts.py +114 -5
  315. ksadk/studio/api_memory_routes.py +82 -0
  316. ksadk/studio/authoring.py +252 -27
  317. ksadk/studio/authoring_coordinator.py +799 -67
  318. ksadk/studio/builder.py +88 -11
  319. ksadk/studio/capabilities.py +17 -0
  320. ksadk/studio/cloud.py +1916 -95
  321. ksadk/studio/codex_agent_service.py +125 -14
  322. ksadk/studio/codex_authoring.py +469 -0
  323. ksadk/studio/codex_builder.py +138 -25
  324. ksadk/studio/codex_manifest.py +51 -22
  325. ksadk/studio/codex_run.py +46 -3
  326. ksadk/studio/compiler.py +1 -0
  327. ksadk/studio/contracts.py +114 -3
  328. ksadk/studio/event_store.py +25 -95
  329. ksadk/studio/framework_run.py +231 -3
  330. ksadk/studio/hosted_kernel.py +317 -0
  331. ksadk/studio/manifest_resolver.py +131 -0
  332. ksadk/studio/model_client.py +95 -9
  333. ksadk/studio/model_profile_service.py +1 -1
  334. ksadk/studio/operations.py +37 -5
  335. ksadk/studio/otel_trace.py +348 -42
  336. ksadk/studio/pcm_memory.py +85 -0
  337. ksadk/studio/repository.py +23 -2
  338. ksadk/studio/resource_catalog.py +43 -0
  339. ksadk/studio/run_service.py +563 -137
  340. ksadk/studio/runtime_source.py +42 -16
  341. ksadk/studio/service.py +1180 -72
  342. ksadk/studio/shared_web.py +32 -22
  343. ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
  344. ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
  345. ksadk/studio/static/index.html +2 -2
  346. ksadk/studio/templates.py +100 -8
  347. ksadk/studio/validator.py +19 -0
  348. ksadk/studio/workspace.py +30 -32
  349. ksadk/tracing/setup.py +304 -3
  350. ksadk/version.py +1 -1
  351. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  352. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  353. ksadk/events/parser.py +0 -191
  354. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  355. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +0 -303
  356. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +0 -1
  357. ksadk/server/static/assets/arc-DrgjcKhl.js +0 -1
  358. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +0 -1
  359. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-BXoVRbQ6.js +0 -36
  360. ksadk/server/static/assets/blockDiagram-GPEHLZMM-BnaB3Ywv.js +0 -132
  361. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dw4weZcp.js +0 -10
  362. ksadk/server/static/assets/channel-Dt3rQTFI.js +0 -1
  363. ksadk/server/static/assets/chunk-2J33WTMH-ChjpLK7j.js +0 -1
  364. ksadk/server/static/assets/chunk-55IACEB6-CK4ROATy.js +0 -1
  365. ksadk/server/static/assets/chunk-727SXJPM-B9KtTTgw.js +0 -206
  366. ksadk/server/static/assets/chunk-AQP2D5EJ-1O1mki3m.js +0 -231
  367. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +0 -1
  368. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +0 -1
  369. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +0 -1
  370. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  371. ksadk/server/static/assets/dagre-BM42HDAG-D0QXg_MQ.js +0 -4
  372. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  373. ksadk/server/static/assets/diagram-2AECGRRQ-DBDDKwBQ.js +0 -43
  374. ksadk/server/static/assets/diagram-5GNKFQAL-BkwDOxmO.js +0 -10
  375. ksadk/server/static/assets/diagram-KO2AKTUF-Bv8waYvY.js +0 -3
  376. ksadk/server/static/assets/diagram-LMA3HP47-e1VECDdu.js +0 -24
  377. ksadk/server/static/assets/diagram-OG6HWLK6-Ds9adfRl.js +0 -24
  378. ksadk/server/static/assets/dist-B5J2uhNk.js +0 -1
  379. ksadk/server/static/assets/erDiagram-TEJ5UH35-BPItFKH6.js +0 -85
  380. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +0 -1
  381. ksadk/server/static/assets/flowDiagram-I6XJVG4X-BbYB9w5Y.js +0 -162
  382. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-TQXa0KXv.js +0 -292
  383. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +0 -1
  384. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-bKblCnpa.js +0 -106
  385. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  386. ksadk/server/static/assets/index-R52pJJvg.js +0 -177
  387. ksadk/server/static/assets/index-jJr3_955.css +0 -2
  388. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +0 -1
  389. ksadk/server/static/assets/infoDiagram-5YYISTIA-BGVT7J_i.js +0 -2
  390. ksadk/server/static/assets/katex-CYWseY5E.js +0 -265
  391. ksadk/server/static/assets/mermaid-parser.core-BWrDjSZM.js +0 -161
  392. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +0 -1
  393. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +0 -1
  394. ksadk/server/static/assets/pieDiagram-4H26LBE5-GmmqNiVH.js +0 -30
  395. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +0 -1
  396. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DSWFqL7c.js +0 -84
  397. ksadk/server/static/assets/stateDiagram-AJRCARHV-qzTQpg3Y.js +0 -1
  398. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +0 -1
  399. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +0 -1
  400. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +0 -1
  401. ksadk/server/static/assets/vennDiagram-CIIHVFJN-CMCixki2.js +0 -34
  402. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +0 -1
  403. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-CVzB8F9K.js +0 -78
  404. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-BFBqBLc1.js +0 -7
  405. ksadk/studio/evaluation.py +0 -192
  406. ksadk/studio/static/assets/index-CaEN0eTR.css +0 -1
  407. ksadk/studio/static/assets/index-DI2eY_NH.js +0 -252
  408. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +0 -0
  409. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
  410. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
  411. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,34 @@
1
+ """Framework-native adapters for canonical RuntimeEvent schema v2.
2
+
3
+ ADK adapter 依赖可选 extra ``ksadk[adk]``(google-adk)。托管 Codex 镜像只装
4
+ 默认依赖,这里必须惰性导出,否则 ``ksadk.events.adapters`` 的传递 import 会
5
+ 让 codex-only 环境在启动期直接崩溃。
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import TYPE_CHECKING, Any
11
+
12
+ if TYPE_CHECKING: # pragma: no cover - typing only
13
+ from ksadk.events.adapters.adk import ADKAdapterContext, ADKEventAdapter
14
+
15
+ __all__ = ["ADKAdapterContext", "ADKEventAdapter"]
16
+
17
+ _LAZY_ATTRS = {"ADKAdapterContext", "ADKEventAdapter"}
18
+
19
+
20
+ def __getattr__(name: str) -> Any:
21
+ if name in _LAZY_ATTRS:
22
+ try:
23
+ from ksadk.events.adapters import adk as _adk
24
+ except ModuleNotFoundError as exc: # google.adk missing -> optional extra
25
+ raise ImportError(
26
+ "ADK event adapter requires the optional 'adk' extra "
27
+ "(pip install ksadk[adk])"
28
+ ) from exc
29
+ return getattr(_adk, name)
30
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
31
+
32
+
33
+ def __dir__() -> list[str]:
34
+ return sorted(__all__)
@@ -0,0 +1,622 @@
1
+ """A2AEventAdapter 的 task 快照映射方法(纯移动自 adapters.a2a,行为不变)。
2
+
3
+ 以 mixin 形式被 :class:`A2AEventAdapter` 继承。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import base64
9
+ from collections.abc import Mapping
10
+ from typing import Literal, cast
11
+
12
+ from a2a.types import (
13
+ Artifact,
14
+ Message,
15
+ Part,
16
+ Role,
17
+ Task,
18
+ TaskState,
19
+ )
20
+ from google.protobuf.json_format import MessageToDict
21
+ from pydantic import JsonValue
22
+
23
+ from ksadk.events.adapters._a2a_support import (
24
+ A2AAdapterContext,
25
+ _ArtifactState,
26
+ _fail,
27
+ _MessageState,
28
+ _metadata,
29
+ _Occurrence,
30
+ _optional_metadata_string,
31
+ _parts_text,
32
+ _proto_fingerprint,
33
+ _required_metadata_string,
34
+ _required_string,
35
+ _SnapshotScope,
36
+ _validate_unique_parts,
37
+ )
38
+ from ksadk.events.canonical import (
39
+ ErrorInfo,
40
+ InteractionResolved,
41
+ ItemCompleted,
42
+ ItemFailed,
43
+ ItemSnapshotReplaced,
44
+ ItemStarted,
45
+ ItemUpdated,
46
+ OutputRef,
47
+ RunCanceled,
48
+ RunCompleted,
49
+ RunFailed,
50
+ RuntimeEvent,
51
+ StructuredInputResponse,
52
+ )
53
+ from ksadk.events.content import (
54
+ ArtifactContent,
55
+ ContentSnapshot,
56
+ ContentValue,
57
+ DataContent,
58
+ TextContent,
59
+ ToolCallContent,
60
+ ToolResultContent,
61
+ )
62
+ from ksadk.events.identity import (
63
+ stable_item_id,
64
+ stable_part_id,
65
+ )
66
+
67
+ ReconciliationReason = Literal["terminal", "reconnect", "subscription_rebuild"]
68
+
69
+ _ACTIVE_STATES = frozenset({TaskState.TASK_STATE_SUBMITTED, TaskState.TASK_STATE_WORKING})
70
+ _INTERACTION_STATES = frozenset(
71
+ {TaskState.TASK_STATE_INPUT_REQUIRED, TaskState.TASK_STATE_AUTH_REQUIRED}
72
+ )
73
+ _TERMINAL_STATES = frozenset(
74
+ {
75
+ TaskState.TASK_STATE_COMPLETED,
76
+ TaskState.TASK_STATE_FAILED,
77
+ TaskState.TASK_STATE_CANCELED,
78
+ TaskState.TASK_STATE_REJECTED,
79
+ }
80
+ )
81
+
82
+
83
+ class _A2ATaskSnapshotMixin:
84
+ def _map_task_snapshot(
85
+ self,
86
+ task: Task,
87
+ context: A2AAdapterContext,
88
+ reason: ReconciliationReason,
89
+ attempt_id: str,
90
+ timestamp: float,
91
+ ) -> tuple[RuntimeEvent, ...]:
92
+ state = task.status.state
93
+ occurrence = _Occurrence(
94
+ native_event_id=None,
95
+ native_cursor=None,
96
+ identity=(
97
+ f"get-task:{reason}:{attempt_id}:"
98
+ f"{TaskState.Name(state)}:{_proto_fingerprint(task)}"
99
+ ),
100
+ provisional=False,
101
+ )
102
+ scope = _SnapshotScope(
103
+ task=task,
104
+ context=context,
105
+ source=self._source(
106
+ context,
107
+ occurrence,
108
+ native_item_id=task.id,
109
+ metadata={
110
+ "provisional": False,
111
+ "consistent": True,
112
+ "reconciliation_reason": reason,
113
+ "reconciliation_attempt_id": attempt_id,
114
+ "terminal": state in _TERMINAL_STATES,
115
+ },
116
+ ),
117
+ timestamp=timestamp,
118
+ occurrence=occurrence,
119
+ terminal=state in _TERMINAL_STATES,
120
+ reason=reason,
121
+ attempt_id=attempt_id,
122
+ )
123
+ self._ensure_run_started(scope.events, context, scope.source, timestamp, occurrence)
124
+ self._snapshot_artifacts(scope)
125
+ interaction_state = state in _INTERACTION_STATES
126
+ status_message_id = (
127
+ task.status.message.message_id if task.status.HasField("message") else ""
128
+ )
129
+ self._snapshot_messages(scope, interaction_state, status_message_id)
130
+ if interaction_state:
131
+ interaction_events = self._map_status(
132
+ task.status,
133
+ {"event_id": occurrence.identity},
134
+ context,
135
+ timestamp,
136
+ native_item_id=status_message_id or None,
137
+ occurrence_payload=task,
138
+ )
139
+ scope.events.extend(
140
+ event.model_copy(update={"source": scope.source}) for event in interaction_events
141
+ )
142
+ return tuple(scope.events)
143
+ self._snapshot_terminal_run(scope, state)
144
+ if scope.terminal:
145
+ self._run_interrupted = False
146
+ self._terminal_snapshot_fingerprint = _proto_fingerprint(task)
147
+ return tuple(scope.events)
148
+
149
+ def _snapshot_artifacts(self, scope: _SnapshotScope) -> None:
150
+ task, context, source, occurrence = (
151
+ scope.task,
152
+ scope.context,
153
+ scope.source,
154
+ scope.occurrence,
155
+ )
156
+ env = self._env_builder(context, source, scope.timestamp, occurrence)
157
+ snapshot_artifact_ids: set[str] = set()
158
+
159
+ for artifact in task.artifacts:
160
+ artifact_id = _required_string(artifact.artifact_id, "task.artifacts.artifact_id")
161
+ snapshot_artifact_ids.add(artifact_id)
162
+ item_id = stable_item_id(
163
+ "a2a", context.context_id, context.task_id, "artifact", artifact_id
164
+ )
165
+ parts = self._convert_parts(artifact, item_id, start_index=0)
166
+ if not parts:
167
+ _fail(
168
+ "empty_artifact_snapshot",
169
+ "task.artifacts.parts",
170
+ "A2A GetTask artifact snapshot requires supported parts",
171
+ )
172
+ _validate_unique_parts(parts, "task.artifacts.parts")
173
+ snapshot = ContentSnapshot(parts=parts)
174
+ artifact_state = self._artifacts.get(artifact_id)
175
+ artifact_source = source.model_copy(update={"native_item_id": artifact_id})
176
+ if artifact_state is None:
177
+ artifact_state = _ArtifactState(artifact_id=artifact_id, item_id=item_id)
178
+ self._artifacts[artifact_id] = artifact_state
179
+ scope.events.append(
180
+ ItemStarted(
181
+ **env(
182
+ item_id, "item.started", "artifact", len(scope.events), artifact_source
183
+ ),
184
+ item_id=item_id,
185
+ item_kind="artifact",
186
+ phase="final_answer",
187
+ )
188
+ )
189
+ elif artifact_state.closed:
190
+ if artifact_state.snapshot() != snapshot:
191
+ _fail(
192
+ "trusted_snapshot_collision",
193
+ "task.artifacts",
194
+ f"GetTask changed already completed artifact {artifact_id!r}",
195
+ )
196
+ if scope.terminal:
197
+ scope.add_output_ref(item_id)
198
+ continue
199
+ artifact_state.parts = {part.part_id: part for part in parts}
200
+ artifact_state.part_order = [part.part_id for part in parts]
201
+ artifact_state.present = True
202
+ if scope.terminal:
203
+ artifact_state.closed = True
204
+ scope.events.append(
205
+ ItemCompleted(
206
+ **env(
207
+ item_id,
208
+ "item.completed",
209
+ "snapshot",
210
+ len(scope.events),
211
+ artifact_source,
212
+ ),
213
+ item_id=item_id,
214
+ item_kind="artifact",
215
+ snapshot=snapshot,
216
+ )
217
+ )
218
+ scope.add_output_ref(item_id)
219
+ else:
220
+ scope.events.append(
221
+ ItemSnapshotReplaced(
222
+ **env(
223
+ item_id,
224
+ "item.snapshot_replaced",
225
+ "snapshot",
226
+ len(scope.events),
227
+ artifact_source,
228
+ ),
229
+ item_id=item_id,
230
+ item_kind="artifact",
231
+ snapshot=snapshot,
232
+ )
233
+ )
234
+
235
+ for artifact_id, artifact_state in self._artifacts.items():
236
+ if artifact_id in snapshot_artifact_ids or artifact_state.closed:
237
+ continue
238
+ removed_source = source.model_copy(update={"native_item_id": artifact_id})
239
+ artifact_state.present = False
240
+ artifact_state.parts = {}
241
+ artifact_state.part_order = []
242
+ if scope.terminal:
243
+ artifact_state.closed = True
244
+ scope.events.append(
245
+ ItemFailed(
246
+ **env(
247
+ artifact_state.item_id,
248
+ "item.failed",
249
+ "artifact",
250
+ len(scope.events),
251
+ removed_source,
252
+ ),
253
+ item_id=artifact_state.item_id,
254
+ item_kind="artifact",
255
+ error=ErrorInfo(
256
+ code="a2a_artifact_removed_by_snapshot",
257
+ message=(
258
+ "provisional artifact absent from authoritative GetTask snapshot"
259
+ ),
260
+ source="a2a",
261
+ scope_id=context.scope_id,
262
+ item_id=artifact_state.item_id,
263
+ source_ref=removed_source,
264
+ ),
265
+ )
266
+ )
267
+ else:
268
+ scope.events.append(
269
+ ItemSnapshotReplaced(
270
+ **env(
271
+ artifact_state.item_id,
272
+ "item.snapshot_replaced",
273
+ "snapshot",
274
+ len(scope.events),
275
+ removed_source,
276
+ ),
277
+ item_id=artifact_state.item_id,
278
+ item_kind="artifact",
279
+ snapshot=ContentSnapshot(parts=()),
280
+ )
281
+ )
282
+
283
+ def _snapshot_messages(
284
+ self,
285
+ scope: _SnapshotScope,
286
+ interaction_state: bool,
287
+ status_message_id: str,
288
+ ) -> None:
289
+ task = scope.task
290
+ snapshot_messages = [
291
+ message
292
+ for message in task.history
293
+ if not (interaction_state and message.message_id == status_message_id)
294
+ ]
295
+ if (
296
+ not interaction_state
297
+ and task.status.HasField("message")
298
+ and all(
299
+ message.message_id != task.status.message.message_id
300
+ for message in snapshot_messages
301
+ )
302
+ ):
303
+ snapshot_messages.append(task.status.message)
304
+ for nested_message in snapshot_messages:
305
+ message = self._normalize_nested_message(nested_message, scope.context)
306
+ if message.role != Role.ROLE_AGENT:
307
+ continue
308
+ scope.events.extend(
309
+ self._map_message(
310
+ message,
311
+ scope.context,
312
+ scope.timestamp,
313
+ consistent=True,
314
+ occurrence_identity=(
315
+ f"get-task:{scope.reason}:{scope.attempt_id}:message:{message.message_id}"
316
+ ),
317
+ )
318
+ )
319
+ message_id = self._message_item_id(
320
+ scope.context, _required_string(message.message_id, "message.message_id")
321
+ )
322
+ if scope.terminal:
323
+ scope.add_output_ref(message_id)
324
+
325
+ def _snapshot_terminal_run(self, scope: _SnapshotScope, state: TaskState) -> None:
326
+ context, events = scope.context, scope.events
327
+ terminal_source = scope.source.model_copy(update={"native_item_id": scope.task.id})
328
+ env = self._env_builder(context, terminal_source, scope.timestamp, scope.occurrence)
329
+
330
+ if state in _TERMINAL_STATES and self._active_interaction is not None:
331
+ interaction_id, _ = self._active_interaction
332
+ events.append(
333
+ InteractionResolved(
334
+ **env(interaction_id, "interaction.resolved", "interaction", len(events)),
335
+ interaction_id=interaction_id,
336
+ interaction_kind="structured_input",
337
+ response=StructuredInputResponse(data={"state": TaskState.Name(state)}),
338
+ )
339
+ )
340
+ self._active_interaction = None
341
+
342
+ def status_text() -> str | None:
343
+ if not scope.task.status.HasField("message"):
344
+ return None
345
+ return _parts_text(
346
+ self._normalize_nested_message(scope.task.status.message, context).parts
347
+ )
348
+
349
+ if state == TaskState.TASK_STATE_COMPLETED:
350
+ events.append(
351
+ RunCompleted(
352
+ **env(context.run_id, "run.completed", "run", len(events)),
353
+ status="completed",
354
+ output_refs=tuple(scope._output_refs),
355
+ )
356
+ )
357
+ elif state in {TaskState.TASK_STATE_FAILED, TaskState.TASK_STATE_REJECTED}:
358
+ events.append(
359
+ RunFailed(
360
+ **env(context.run_id, "run.failed", "run", len(events)),
361
+ status="failed",
362
+ error=ErrorInfo(
363
+ code=(
364
+ "a2a_task_rejected"
365
+ if state == TaskState.TASK_STATE_REJECTED
366
+ else "a2a_task_failed"
367
+ ),
368
+ message=status_text(),
369
+ source="a2a",
370
+ scope_id=context.scope_id,
371
+ source_ref=terminal_source,
372
+ ),
373
+ )
374
+ )
375
+ elif state == TaskState.TASK_STATE_CANCELED:
376
+ events.append(
377
+ RunCanceled(
378
+ **env(context.run_id, "run.canceled", "run", len(events)),
379
+ status="canceled",
380
+ reason=status_text(),
381
+ )
382
+ )
383
+ else:
384
+ events.append(
385
+ self._run_progress_event(
386
+ context,
387
+ terminal_source,
388
+ scope.timestamp,
389
+ scope.occurrence,
390
+ len(events),
391
+ message=f"authoritative {TaskState.Name(state)} snapshot",
392
+ )
393
+ )
394
+
395
+ def _map_message(
396
+ self,
397
+ message: Message,
398
+ context: A2AAdapterContext,
399
+ timestamp: float,
400
+ *,
401
+ consistent: bool,
402
+ occurrence_identity: str | None = None,
403
+ direct_response: bool = False,
404
+ ) -> tuple[RuntimeEvent, ...]:
405
+ message_id = _required_string(message.message_id, "message.message_id")
406
+ message_metadata = _metadata(message.metadata)
407
+ producer_event_id = _optional_metadata_string(
408
+ message_metadata, "event_id", "ksadk_event_id"
409
+ )
410
+ if producer_event_id is not None:
411
+ occurrence = self._occurrence(
412
+ message_metadata, provisional_key=f"message:{message_id}", payload=message
413
+ )
414
+ if occurrence.duplicate:
415
+ return ()
416
+ else:
417
+ cursor = _optional_metadata_string(message_metadata, "seq", "ksadk_seq")
418
+ occurrence = _Occurrence(
419
+ native_event_id=message_id,
420
+ native_cursor=cursor,
421
+ identity=occurrence_identity or message_id,
422
+ provisional=False,
423
+ )
424
+ signature = message.SerializeToString(deterministic=True)
425
+ existing = self._messages.get(message_id)
426
+ if existing is not None:
427
+ if existing.signature != signature:
428
+ _fail(
429
+ "message_identity_collision",
430
+ "message.message_id",
431
+ f"A2A message {message_id!r} changed after completion",
432
+ )
433
+ return ()
434
+ if producer_event_id is not None and occurrence_identity is not None:
435
+ occurrence = _Occurrence(
436
+ native_event_id=occurrence.native_event_id,
437
+ native_cursor=occurrence.native_cursor,
438
+ identity=occurrence_identity,
439
+ provisional=False,
440
+ )
441
+ item_id = self._message_item_id(context, message_id)
442
+ parts = self._convert_parts(message, item_id)
443
+ if not parts:
444
+ _fail(
445
+ "empty_message", "message.parts", "A2A message requires at least one supported part"
446
+ )
447
+ _validate_unique_parts(parts, "message.parts")
448
+ source = self._source(
449
+ context,
450
+ occurrence,
451
+ native_item_id=message_id,
452
+ metadata={
453
+ "provisional": False,
454
+ "consistent": consistent,
455
+ "role": Role.Name(message.role),
456
+ },
457
+ )
458
+
459
+ env = self._env_builder(context, source, timestamp, occurrence)
460
+ events: list[RuntimeEvent] = []
461
+ if direct_response:
462
+ self._ensure_run_started(events, context, source, timestamp, occurrence)
463
+ events.append(
464
+ ItemStarted(
465
+ **env(item_id, "item.started", "message", 0),
466
+ item_id=item_id,
467
+ item_kind="message",
468
+ phase="final_answer",
469
+ )
470
+ )
471
+ for index, part in enumerate(parts, start=1):
472
+ events.append(
473
+ ItemUpdated(
474
+ **env(item_id, "item.updated", part.part_id, index),
475
+ item_id=item_id,
476
+ item_kind="message",
477
+ op="replace",
478
+ update=part,
479
+ )
480
+ )
481
+ events.append(
482
+ ItemCompleted(
483
+ **env(item_id, "item.completed", "snapshot", len(parts) + 1),
484
+ item_id=item_id,
485
+ item_kind="message",
486
+ snapshot=ContentSnapshot(parts=parts),
487
+ )
488
+ )
489
+ self._messages[message_id] = _MessageState(signature=signature)
490
+ if direct_response:
491
+ events.append(
492
+ RunCompleted(
493
+ **env(context.run_id, "run.completed", "run", len(parts) + 2),
494
+ status="completed",
495
+ output_refs=(OutputRef(scope_id=context.scope_id, item_id=item_id),),
496
+ )
497
+ )
498
+ return tuple(events)
499
+
500
+ def _convert_parts(
501
+ self,
502
+ owner: Artifact | Message,
503
+ item_id: str,
504
+ *,
505
+ start_index: int = 0,
506
+ ) -> tuple[ContentValue, ...]:
507
+ converted: list[ContentValue] = []
508
+ for index, part in enumerate(owner.parts, start=start_index):
509
+ converted.append(self._convert_part(owner, part, item_id, index))
510
+ return tuple(converted)
511
+
512
+ def _convert_part(
513
+ self,
514
+ owner: Artifact | Message,
515
+ part: Part,
516
+ item_id: str,
517
+ index: int,
518
+ ) -> ContentValue:
519
+ metadata = _metadata(part.metadata)
520
+ content_kind = part.WhichOneof("content")
521
+ kind = _optional_metadata_string(metadata, "kind", "ksadk_kind")
522
+ if content_kind == "text":
523
+ native_part = _optional_metadata_string(metadata, "part_id") or f"text:{index}"
524
+ return TextContent(
525
+ part_id=stable_part_id("a2a", item_id, native_part),
526
+ text=part.text,
527
+ )
528
+ if content_kind == "data":
529
+ native_kind = kind or "data"
530
+ native_part = _optional_metadata_string(metadata, "part_id") or f"{native_kind}:{index}"
531
+ part_id = stable_part_id("a2a", item_id, native_part)
532
+ value = cast(JsonValue, MessageToDict(part.data))
533
+ if native_kind == "tool_call":
534
+ return ToolCallContent(
535
+ part_id=part_id,
536
+ call_id=_required_metadata_string(metadata, "call_id"),
537
+ name=_required_metadata_string(metadata, "name"),
538
+ arguments=value,
539
+ )
540
+ if native_kind == "tool_result":
541
+ return ToolResultContent(
542
+ part_id=part_id,
543
+ call_id=_required_metadata_string(metadata, "call_id"),
544
+ result=value,
545
+ is_error=bool(metadata.get("is_error", False)),
546
+ )
547
+ if native_kind != "data":
548
+ _fail(
549
+ "unknown_part_kind",
550
+ "part.metadata.kind",
551
+ f"unsupported A2A data part kind {native_kind!r}",
552
+ )
553
+ return DataContent(part_id=part_id, data=value)
554
+ if content_kind in {"url", "raw"}:
555
+ native_part = _optional_metadata_string(metadata, "part_id") or f"file:{index}"
556
+ artifact_id = (
557
+ owner.artifact_id
558
+ if isinstance(owner, Artifact)
559
+ else f"message:{owner.message_id}:part:{index}"
560
+ )
561
+ name = part.filename or (owner.name if isinstance(owner, Artifact) else "attachment")
562
+ data: JsonValue = None
563
+ if content_kind == "raw":
564
+ data = {"base64": base64.b64encode(part.raw).decode("ascii")}
565
+ return ArtifactContent(
566
+ part_id=stable_part_id("a2a", item_id, native_part),
567
+ artifact_id=artifact_id,
568
+ name=name,
569
+ mime_type=part.media_type or None,
570
+ uri=part.url if content_kind == "url" else None,
571
+ data=data,
572
+ )
573
+ _fail(
574
+ "empty_part",
575
+ "parts",
576
+ f"A2A part at index {index} has no supported payload",
577
+ )
578
+
579
+ def _occurrence(
580
+ self,
581
+ metadata: Mapping[str, JsonValue],
582
+ *,
583
+ provisional_key: str,
584
+ payload: object,
585
+ ) -> _Occurrence:
586
+ native_event_id = _optional_metadata_string(metadata, "event_id", "ksadk_event_id")
587
+ native_cursor = _optional_metadata_string(metadata, "seq", "ksadk_seq")
588
+ if native_event_id is not None:
589
+ fingerprint = _proto_fingerprint(payload)
590
+ previous = self._seen_occurrences.get(native_event_id)
591
+ if previous is not None:
592
+ if previous != fingerprint:
593
+ _fail(
594
+ "producer_event_id_collision",
595
+ "metadata.event_id",
596
+ f"A2A producer event_id {native_event_id!r} changed payload",
597
+ )
598
+ self._seen_occurrences.move_to_end(native_event_id)
599
+ return _Occurrence(
600
+ native_event_id=native_event_id,
601
+ native_cursor=native_cursor,
602
+ identity=native_event_id,
603
+ provisional=False,
604
+ duplicate=True,
605
+ )
606
+ self._seen_occurrences[native_event_id] = fingerprint
607
+ while len(self._seen_occurrences) > self.OCCURRENCE_CACHE_LIMIT:
608
+ self._seen_occurrences.popitem(last=False)
609
+ return _Occurrence(
610
+ native_event_id=native_event_id,
611
+ native_cursor=native_cursor,
612
+ identity=native_event_id,
613
+ provisional=False,
614
+ )
615
+ ordinal = self._provisional_ordinals.get(provisional_key, 0)
616
+ self._provisional_ordinals[provisional_key] = ordinal + 1
617
+ return _Occurrence(
618
+ native_event_id=None,
619
+ native_cursor=native_cursor,
620
+ identity=f"provisional:{provisional_key}:{ordinal}",
621
+ provisional=True,
622
+ )