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,841 @@
1
+ """A2A SDK 1.1.0 protobuf events to RuntimeEvent schema version 2."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import copy
6
+ from collections import OrderedDict
7
+ from collections.abc import Mapping
8
+ from typing import Any, Literal
9
+
10
+ from a2a.types import (
11
+ Artifact,
12
+ GetTaskRequest,
13
+ Message,
14
+ Role,
15
+ StreamResponse,
16
+ Task,
17
+ TaskArtifactUpdateEvent,
18
+ TaskState,
19
+ TaskStatus,
20
+ TaskStatusUpdateEvent,
21
+ )
22
+ from pydantic import JsonValue
23
+
24
+ from ksadk.events.adapters._a2a_snapshot import _A2ATaskSnapshotMixin
25
+ from ksadk.events.adapters._a2a_support import (
26
+ A2AAdapterContext,
27
+ A2AMappingError,
28
+ A2AReconciliationResult,
29
+ _A2AClient,
30
+ _ArtifactState,
31
+ _fail,
32
+ _MessageState,
33
+ _metadata,
34
+ _Occurrence,
35
+ _parts_text,
36
+ _proto_fingerprint,
37
+ _required_string,
38
+ _status_message_id,
39
+ _timestamp,
40
+ _validate_unique_parts,
41
+ )
42
+ from ksadk.events.canonical import (
43
+ ContinuationCreated,
44
+ ContinuationResumed,
45
+ InteractionRequested,
46
+ InteractionResolved,
47
+ ItemSnapshotReplaced,
48
+ ItemStarted,
49
+ ItemUpdated,
50
+ RunInterrupted,
51
+ RunProgress,
52
+ RunStarted,
53
+ RuntimeEvent,
54
+ SourceRef,
55
+ StructuredInputRequest,
56
+ StructuredInputResponse,
57
+ )
58
+ from ksadk.events.identity import (
59
+ stable_event_id,
60
+ stable_item_id,
61
+ )
62
+
63
+ ReconciliationReason = Literal["terminal", "reconnect", "subscription_rebuild"]
64
+
65
+ _ACTIVE_STATES = frozenset({TaskState.TASK_STATE_SUBMITTED, TaskState.TASK_STATE_WORKING})
66
+ _INTERACTION_STATES = frozenset(
67
+ {TaskState.TASK_STATE_INPUT_REQUIRED, TaskState.TASK_STATE_AUTH_REQUIRED}
68
+ )
69
+ _TERMINAL_STATES = frozenset(
70
+ {
71
+ TaskState.TASK_STATE_COMPLETED,
72
+ TaskState.TASK_STATE_FAILED,
73
+ TaskState.TASK_STATE_CANCELED,
74
+ TaskState.TASK_STATE_REJECTED,
75
+ }
76
+ )
77
+
78
+
79
+ class A2AEventAdapter(_A2ATaskSnapshotMixin):
80
+ """Map A2A 1.1.0 typed protobuf delivery into canonical events.
81
+
82
+ A delivery without a producer occurrence id is deliberately provisional.
83
+ In particular, its ``last_chunk`` records source closure but does not emit
84
+ the irreversible canonical ``item.completed``; GetTask closes it with one
85
+ authoritative snapshot. A trusted last chunk may close immediately, and a
86
+ later GetTask snapshot must then be byte-for-byte equivalent or fail closed.
87
+ """
88
+
89
+ OCCURRENCE_CACHE_LIMIT = 1024
90
+
91
+ def __init__(self) -> None:
92
+ self._artifacts: dict[str, _ArtifactState] = {}
93
+ self._messages: dict[str, _MessageState] = {}
94
+ self._seen_occurrences: OrderedDict[str, str] = OrderedDict()
95
+ self._provisional_ordinals: dict[str, int] = {}
96
+ self._interaction_payloads: dict[tuple[int, str], str] = {}
97
+ self._run_started = False
98
+ self._run_interrupted = False
99
+ self._active_interaction: tuple[str, str] | None = None
100
+ self._terminal_snapshot_fingerprint: str | None = None
101
+
102
+ def map_event(
103
+ self,
104
+ native_event: object,
105
+ context: A2AAdapterContext,
106
+ *,
107
+ timestamp: float,
108
+ ) -> tuple[RuntimeEvent, ...]:
109
+ """Map one real A2A protobuf object in source delivery order."""
110
+
111
+ timestamp = _timestamp(timestamp)
112
+ shadow = copy.deepcopy(self)
113
+ shadow_context = copy.deepcopy(context)
114
+ events = shadow._map_event(native_event, shadow_context, timestamp=timestamp)
115
+ self._commit_shadow(shadow, context, shadow_context)
116
+ return events
117
+
118
+ def _map_event(
119
+ self,
120
+ native_event: object,
121
+ context: A2AAdapterContext,
122
+ *,
123
+ timestamp: float,
124
+ ) -> tuple[RuntimeEvent, ...]:
125
+ if isinstance(native_event, StreamResponse):
126
+ payload_name = native_event.WhichOneof("payload")
127
+ if payload_name is None:
128
+ _fail(
129
+ "empty_stream_response",
130
+ "StreamResponse.payload",
131
+ "A2A StreamResponse has no payload",
132
+ )
133
+ return self._map_event(
134
+ getattr(native_event, payload_name), context, timestamp=timestamp
135
+ )
136
+ if isinstance(native_event, TaskArtifactUpdateEvent):
137
+ return self._map_artifact_update(native_event, context, timestamp)
138
+ if isinstance(native_event, TaskStatusUpdateEvent):
139
+ return self._map_status_update(native_event, context, timestamp)
140
+ if isinstance(native_event, Message):
141
+ self._validate_message_identity(native_event, context)
142
+ context.bind_direct_message(native_event.message_id)
143
+ self._require_agent_message(native_event, field_name="Message.role")
144
+ return self._map_message(
145
+ native_event, context, timestamp, consistent=True, direct_response=True
146
+ )
147
+ if isinstance(native_event, Task):
148
+ self._validate_identity(native_event.context_id, native_event.id, context)
149
+ self._require_task_status(native_event)
150
+ return self._map_status(
151
+ native_event.status,
152
+ _metadata(native_event.metadata),
153
+ context,
154
+ timestamp,
155
+ native_item_id=native_event.id,
156
+ occurrence_payload=native_event,
157
+ )
158
+ _fail(
159
+ "unsupported_event",
160
+ "event",
161
+ f"unsupported A2A event: {type(native_event).__name__}",
162
+ )
163
+
164
+ async def reconcile(
165
+ self,
166
+ client: _A2AClient,
167
+ context: A2AAdapterContext,
168
+ *,
169
+ reason: ReconciliationReason,
170
+ attempt_id: str | None = None,
171
+ timestamp: float,
172
+ ) -> A2AReconciliationResult:
173
+ """Call GetTask and project its authoritative state.
174
+
175
+ The method intentionally accepts a client, not a caller-supplied Task,
176
+ so terminal, reconnect, and subscription rebuild cannot accidentally
177
+ claim consistency from the notification that triggered reconciliation.
178
+ """
179
+
180
+ timestamp = _timestamp(timestamp)
181
+ resolved_attempt_id = _required_string(
182
+ attempt_id or f"{reason}:{context.task_id}",
183
+ "reconciliation attempt_id",
184
+ )
185
+ task_id = _required_string(context.task_id, "task_id")
186
+ try:
187
+ task = await client.get_task(GetTaskRequest(id=task_id))
188
+ self._validate_identity(task.context_id, task.id, context)
189
+ self._require_task_status(task)
190
+ task_fingerprint = _proto_fingerprint(task)
191
+ if self._terminal_snapshot_fingerprint is not None:
192
+ if task_fingerprint != self._terminal_snapshot_fingerprint:
193
+ _fail(
194
+ "terminal_snapshot_collision",
195
+ "Task",
196
+ "A2A terminal GetTask snapshot changed after completion",
197
+ )
198
+ return A2AReconciliationResult(
199
+ events=(),
200
+ consistent=True,
201
+ terminal=True,
202
+ attempt_id=resolved_attempt_id,
203
+ )
204
+ shadow = copy.deepcopy(self)
205
+ shadow_context = copy.deepcopy(context)
206
+ events = shadow._map_task_snapshot(
207
+ task, shadow_context, reason, resolved_attempt_id, timestamp
208
+ )
209
+ except Exception as exc: # the result must remain usable after a transport/mapping failure
210
+ error = exc.code if isinstance(exc, A2AMappingError) else "get_task_failed"
211
+ diagnostic = self._reconciliation_diagnostic(
212
+ context,
213
+ reason=reason,
214
+ timestamp=timestamp,
215
+ error=error,
216
+ exception_type=type(exc).__name__,
217
+ attempt_id=resolved_attempt_id,
218
+ )
219
+ return A2AReconciliationResult(
220
+ events=(diagnostic,),
221
+ consistent=False,
222
+ terminal=False,
223
+ attempt_id=resolved_attempt_id,
224
+ error=error,
225
+ )
226
+ self._commit_shadow(shadow, context, shadow_context)
227
+ return A2AReconciliationResult(
228
+ events=events,
229
+ consistent=True,
230
+ terminal=task.status.state in _TERMINAL_STATES,
231
+ attempt_id=resolved_attempt_id,
232
+ )
233
+
234
+ def _commit_shadow(
235
+ self,
236
+ shadow: A2AEventAdapter,
237
+ context: A2AAdapterContext,
238
+ shadow_context: A2AAdapterContext,
239
+ ) -> None:
240
+ self.__dict__.clear()
241
+ self.__dict__.update(shadow.__dict__)
242
+ context._next_seq = shadow_context._next_seq
243
+ context._direct_message_id = shadow_context._direct_message_id
244
+
245
+ def _ensure_run_started(
246
+ self,
247
+ events: list[RuntimeEvent],
248
+ context: A2AAdapterContext,
249
+ source: SourceRef,
250
+ timestamp: float,
251
+ occurrence: _Occurrence,
252
+ ) -> None:
253
+ if not self._run_started:
254
+ events.append(
255
+ self._run_started_event(context, source, timestamp, occurrence, len(events))
256
+ )
257
+ self._run_started = True
258
+
259
+ def _env_builder(
260
+ self,
261
+ context: A2AAdapterContext,
262
+ source: SourceRef,
263
+ timestamp: float,
264
+ occurrence: _Occurrence,
265
+ ) -> Any:
266
+ """Return a closure building envelope kwargs for one event burst."""
267
+
268
+ def env(
269
+ item_id: str,
270
+ event_type: str,
271
+ part_id: str,
272
+ ordinal: int,
273
+ src: SourceRef = source,
274
+ ) -> dict[str, Any]:
275
+ return self._envelope(
276
+ context,
277
+ src,
278
+ timestamp,
279
+ item_id=item_id,
280
+ event_type=event_type,
281
+ part_id=part_id,
282
+ occurrence=occurrence,
283
+ ordinal=ordinal,
284
+ )
285
+
286
+ return env
287
+
288
+ def _map_artifact_update(
289
+ self,
290
+ update: TaskArtifactUpdateEvent,
291
+ context: A2AAdapterContext,
292
+ timestamp: float,
293
+ ) -> tuple[RuntimeEvent, ...]:
294
+ self._validate_identity(update.context_id, update.task_id, context)
295
+ if not update.HasField("artifact"):
296
+ _fail("missing_artifact", "artifact", "A2A artifact update requires artifact")
297
+ artifact = update.artifact
298
+ artifact_id = _required_string(artifact.artifact_id, "artifact.artifact_id")
299
+ occurrence = self._occurrence(
300
+ _metadata(update.metadata),
301
+ provisional_key=f"artifact:{artifact_id}",
302
+ payload=update,
303
+ )
304
+ if occurrence.duplicate:
305
+ return ()
306
+
307
+ state = self._artifacts.get(artifact_id)
308
+ if update.append and (state is None or not state.present):
309
+ _fail(
310
+ "artifact_missing",
311
+ "append",
312
+ "A2A artifact_missing: append=True requires an authoritative base",
313
+ )
314
+ if state is not None and state.closed:
315
+ _fail(
316
+ "artifact_already_closed",
317
+ "artifact.artifact_id",
318
+ f"A2A artifact {artifact_id!r} is already closed",
319
+ )
320
+ item_id = stable_item_id(
321
+ "a2a", context.context_id, context.task_id, "artifact", artifact_id
322
+ )
323
+ source = self._source(
324
+ context,
325
+ occurrence,
326
+ native_item_id=artifact_id,
327
+ metadata=self._source_metadata(
328
+ provisional=occurrence.provisional,
329
+ consistent=False,
330
+ artifact_closed=bool(update.last_chunk),
331
+ artifact=artifact,
332
+ ),
333
+ )
334
+
335
+ env = self._env_builder(context, source, timestamp, occurrence)
336
+
337
+ events: list[RuntimeEvent] = []
338
+ if state is None:
339
+ state = _ArtifactState(artifact_id=artifact_id, item_id=item_id)
340
+ self._artifacts[artifact_id] = state
341
+ events.append(
342
+ ItemStarted(
343
+ **env(item_id, "item.started", "artifact", 0),
344
+ item_id=item_id,
345
+ item_kind="artifact",
346
+ phase="final_answer",
347
+ )
348
+ )
349
+
350
+ absolute_start = len(state.part_order) if update.append else 0
351
+ converted = self._convert_parts(artifact, item_id, start_index=absolute_start)
352
+ if not converted:
353
+ _fail(
354
+ "empty_artifact",
355
+ "artifact.parts",
356
+ "A2A artifact requires at least one supported part",
357
+ )
358
+ _validate_unique_parts(converted, "artifact.parts")
359
+ previous_parts = dict(state.parts)
360
+ for part in converted:
361
+ previous = previous_parts.get(part.part_id)
362
+ if previous is not None and previous.content_type != part.content_type:
363
+ _fail(
364
+ "part_identity_collision",
365
+ "artifact.parts",
366
+ f"A2A part {part.part_id!r} changed content type",
367
+ )
368
+ if not update.append:
369
+ state.present = True
370
+ state.parts = {part.part_id: part for part in converted}
371
+ state.part_order = [part.part_id for part in converted]
372
+ events.append(
373
+ ItemSnapshotReplaced(
374
+ **env(item_id, "item.snapshot_replaced", "snapshot", 1),
375
+ item_id=item_id,
376
+ item_kind="artifact",
377
+ snapshot=state.snapshot(),
378
+ )
379
+ )
380
+ else:
381
+ for index, part in enumerate(converted):
382
+ if part.part_id in state.parts:
383
+ _fail(
384
+ "part_identity_collision",
385
+ "artifact.parts",
386
+ f"A2A append reused existing part {part.part_id!r}",
387
+ )
388
+ state.parts[part.part_id] = part
389
+ state.part_order.append(part.part_id)
390
+ events.append(
391
+ ItemUpdated(
392
+ **env(item_id, "item.updated", part.part_id, index + 1),
393
+ item_id=item_id,
394
+ item_kind="artifact",
395
+ op="append",
396
+ update=part,
397
+ )
398
+ )
399
+ return tuple(events)
400
+
401
+ def _map_status_update(
402
+ self,
403
+ update: TaskStatusUpdateEvent,
404
+ context: A2AAdapterContext,
405
+ timestamp: float,
406
+ ) -> tuple[RuntimeEvent, ...]:
407
+ self._validate_identity(update.context_id, update.task_id, context)
408
+ if not update.HasField("status"):
409
+ _fail("missing_status", "status", "A2A status update requires status")
410
+ return self._map_status(
411
+ update.status,
412
+ _metadata(update.metadata),
413
+ context,
414
+ timestamp,
415
+ native_item_id=_status_message_id(update.status),
416
+ occurrence_payload=update,
417
+ )
418
+
419
+ def _map_status(
420
+ self,
421
+ status: TaskStatus,
422
+ metadata: Mapping[str, JsonValue],
423
+ context: A2AAdapterContext,
424
+ timestamp: float,
425
+ *,
426
+ native_item_id: str | None,
427
+ occurrence_payload: object,
428
+ ) -> tuple[RuntimeEvent, ...]:
429
+ occurrence = self._occurrence(
430
+ metadata, provisional_key="status", payload=occurrence_payload
431
+ )
432
+ if occurrence.duplicate:
433
+ return ()
434
+ source = self._source(
435
+ context,
436
+ occurrence,
437
+ native_item_id=native_item_id,
438
+ metadata={"provisional": occurrence.provisional, "consistent": False},
439
+ )
440
+ state = status.state
441
+ if state in _ACTIVE_STATES:
442
+ return self._map_active_status(state, context, source, timestamp, occurrence)
443
+ if state in _INTERACTION_STATES:
444
+ return self._map_interaction_status(
445
+ status, state, context, source, timestamp, occurrence
446
+ )
447
+ if state in _TERMINAL_STATES:
448
+ return self._map_awaiting_terminal_status(context, source, timestamp, occurrence)
449
+ _fail("unknown_task_state", "status.state", f"unsupported A2A TaskState {state}")
450
+
451
+ def _map_active_status(
452
+ self,
453
+ state: TaskState,
454
+ context: A2AAdapterContext,
455
+ source: SourceRef,
456
+ timestamp: float,
457
+ occurrence: _Occurrence,
458
+ ) -> tuple[RuntimeEvent, ...]:
459
+ env = self._env_builder(context, source, timestamp, occurrence)
460
+ events: list[RuntimeEvent] = []
461
+ if self._active_interaction is not None:
462
+ interaction_id, continuation_id = self._active_interaction
463
+ events.append(
464
+ InteractionResolved(
465
+ **env(interaction_id, "interaction.resolved", "interaction", len(events)),
466
+ interaction_id=interaction_id,
467
+ interaction_kind="structured_input",
468
+ response=StructuredInputResponse(data={"state": TaskState.Name(state)}),
469
+ )
470
+ )
471
+ events.append(
472
+ ContinuationResumed(
473
+ **env(continuation_id, "continuation.resumed", "continuation", len(events)),
474
+ continuation_id=continuation_id,
475
+ continuation_kind="task_resume",
476
+ resume_attempt_id=stable_item_id(
477
+ "a2a", context.scope_id, continuation_id, occurrence.identity
478
+ ),
479
+ )
480
+ )
481
+ self._active_interaction = None
482
+ if not self._run_started:
483
+ self._ensure_run_started(events, context, source, timestamp, occurrence)
484
+ else:
485
+ events.append(
486
+ self._run_progress_event(
487
+ context,
488
+ source,
489
+ timestamp,
490
+ occurrence,
491
+ len(events),
492
+ message=TaskState.Name(state),
493
+ )
494
+ )
495
+ self._run_interrupted = False
496
+ return tuple(events)
497
+
498
+ def _map_interaction_status(
499
+ self,
500
+ status: TaskStatus,
501
+ state: TaskState,
502
+ context: A2AAdapterContext,
503
+ source: SourceRef,
504
+ timestamp: float,
505
+ occurrence: _Occurrence,
506
+ ) -> tuple[RuntimeEvent, ...]:
507
+ if not status.HasField("message"):
508
+ _fail(
509
+ "missing_interaction_message",
510
+ "status.message",
511
+ "A2A input/auth required status requires a message identity",
512
+ )
513
+ message = self._normalize_nested_message(status.message, context)
514
+ message_id = _required_string(message.message_id, "status.message.message_id")
515
+ lifecycle_key = (state, message_id)
516
+ payload_fingerprint = _proto_fingerprint(message)
517
+ previous_fingerprint = self._interaction_payloads.get(lifecycle_key)
518
+ if previous_fingerprint is not None:
519
+ if previous_fingerprint == payload_fingerprint:
520
+ return ()
521
+ _fail(
522
+ "interaction_payload_collision",
523
+ "status.message",
524
+ f"A2A interaction payload changed for message {message_id!r}",
525
+ )
526
+ self._interaction_payloads[lifecycle_key] = payload_fingerprint
527
+ env = self._env_builder(context, source, timestamp, occurrence)
528
+ events: list[RuntimeEvent] = []
529
+ if self._active_interaction is not None:
530
+ previous_interaction_id, _ = self._active_interaction
531
+ events.append(
532
+ InteractionResolved(
533
+ **env(
534
+ previous_interaction_id, "interaction.resolved", "interaction", len(events)
535
+ ),
536
+ interaction_id=previous_interaction_id,
537
+ interaction_kind="structured_input",
538
+ response=StructuredInputResponse(
539
+ data={"state": "SUPERSEDED_BY_NEW_A2A_INTERACTION"}
540
+ ),
541
+ )
542
+ )
543
+ self._active_interaction = None
544
+ self._ensure_run_started(events, context, source, timestamp, occurrence)
545
+ interaction_id = stable_item_id(
546
+ "a2a", context.scope_id, "interaction", TaskState.Name(state), message_id
547
+ )
548
+ continuation_id = stable_item_id(
549
+ "a2a", context.scope_id, "continuation", context.task_id, message_id
550
+ )
551
+ prompt = _parts_text(message.parts) or None
552
+ message_metadata = _metadata(message.metadata)
553
+ schema = message_metadata.get("input_schema")
554
+ if not isinstance(schema, dict):
555
+ schema = {"type": "object" if state == TaskState.TASK_STATE_AUTH_REQUIRED else "string"}
556
+ events.append(
557
+ InteractionRequested(
558
+ **env(interaction_id, "interaction.requested", "interaction", len(events)),
559
+ interaction_id=interaction_id,
560
+ interaction_kind="structured_input",
561
+ request=StructuredInputRequest(prompt=prompt, schema=schema),
562
+ )
563
+ )
564
+ events.append(
565
+ ContinuationCreated(
566
+ **env(continuation_id, "continuation.created", "continuation", len(events)),
567
+ continuation_id=continuation_id,
568
+ continuation_kind="task_resume",
569
+ resumable=True,
570
+ ref={"context_id": context.context_id, "task_id": context.task_id},
571
+ )
572
+ )
573
+ if not self._run_interrupted:
574
+ events.append(
575
+ RunInterrupted(
576
+ **env(context.run_id, "run.interrupted", "run", len(events)),
577
+ status="interrupted",
578
+ reason=TaskState.Name(state),
579
+ interaction_id=interaction_id,
580
+ continuation_id=continuation_id,
581
+ )
582
+ )
583
+ self._run_interrupted = True
584
+ self._active_interaction = (interaction_id, continuation_id)
585
+ return tuple(events)
586
+
587
+ def _map_awaiting_terminal_status(
588
+ self,
589
+ context: A2AAdapterContext,
590
+ source: SourceRef,
591
+ timestamp: float,
592
+ occurrence: _Occurrence,
593
+ ) -> tuple[RuntimeEvent, ...]:
594
+ events: list[RuntimeEvent] = []
595
+ self._ensure_run_started(events, context, source, timestamp, occurrence)
596
+ events.append(
597
+ self._run_progress_event(
598
+ context,
599
+ source,
600
+ timestamp,
601
+ occurrence,
602
+ len(events),
603
+ message="awaiting authoritative A2A GetTask snapshot",
604
+ )
605
+ )
606
+ self._run_interrupted = False
607
+ return tuple(events)
608
+
609
+ @staticmethod
610
+ def _source_metadata(
611
+ *,
612
+ provisional: bool,
613
+ consistent: bool,
614
+ artifact_closed: bool,
615
+ artifact: Artifact,
616
+ ) -> dict[str, JsonValue]:
617
+ return {
618
+ "provisional": provisional,
619
+ "consistent": consistent,
620
+ "artifact_closed": artifact_closed,
621
+ "artifact_name": artifact.name,
622
+ "artifact_description": artifact.description,
623
+ "artifact_extensions": list(artifact.extensions),
624
+ }
625
+
626
+ @staticmethod
627
+ def _source(
628
+ context: A2AAdapterContext,
629
+ occurrence: _Occurrence,
630
+ *,
631
+ native_item_id: str | None,
632
+ metadata: Mapping[str, JsonValue],
633
+ ) -> SourceRef:
634
+ return SourceRef(
635
+ framework="a2a",
636
+ native_event_id=occurrence.native_event_id,
637
+ native_cursor=occurrence.native_cursor,
638
+ native_run_id=context.native_run_id,
639
+ native_item_id=native_item_id,
640
+ metadata=dict(metadata),
641
+ )
642
+
643
+ @staticmethod
644
+ def _validate_identity(
645
+ context_id: str,
646
+ task_id: str,
647
+ context: A2AAdapterContext,
648
+ ) -> None:
649
+ native_context = _required_string(context_id, "context_id")
650
+ native_task = _required_string(task_id, "task_id")
651
+ expected_task = _required_string(context.task_id, "task_id")
652
+ if native_context != context.context_id or native_task != expected_task:
653
+ _fail(
654
+ "scope_identity_mismatch",
655
+ "context_id/task_id",
656
+ "A2A event identity does not match adapter context",
657
+ )
658
+
659
+ @staticmethod
660
+ def _validate_message_identity(
661
+ message: Message,
662
+ context: A2AAdapterContext,
663
+ ) -> None:
664
+ native_context = _required_string(message.context_id, "message.context_id")
665
+ if native_context != context.context_id:
666
+ _fail(
667
+ "scope_identity_mismatch",
668
+ "message.context_id",
669
+ "A2A Message context_id does not match adapter context",
670
+ )
671
+ if context.task_id is None:
672
+ if message.task_id:
673
+ _fail(
674
+ "scope_identity_mismatch",
675
+ "message.task_id",
676
+ "taskless A2A direct Message must not introduce a task_id",
677
+ )
678
+ elif message.task_id and message.task_id != context.task_id:
679
+ _fail(
680
+ "scope_identity_mismatch",
681
+ "message.task_id",
682
+ "A2A Message task_id does not match adapter context",
683
+ )
684
+
685
+ @staticmethod
686
+ def _message_item_id(context: A2AAdapterContext, message_id: str) -> str:
687
+ if context.task_id is not None:
688
+ return stable_item_id("a2a", context.context_id, context.task_id, "message", message_id)
689
+ return stable_item_id("a2a", context.context_id, "message", message_id)
690
+
691
+ @staticmethod
692
+ def _require_task_status(task: Task) -> None:
693
+ if not task.HasField("status"):
694
+ _fail("missing_task_status", "Task.status", "A2A Task.status is required")
695
+
696
+ @staticmethod
697
+ def _require_agent_message(message: Message, *, field_name: str) -> None:
698
+ if message.role != Role.ROLE_AGENT:
699
+ _fail(
700
+ "unexpected_message_role",
701
+ field_name,
702
+ "A2A output Message.role must be ROLE_AGENT",
703
+ )
704
+
705
+ def _normalize_nested_message(
706
+ self,
707
+ message: Message,
708
+ context: A2AAdapterContext,
709
+ ) -> Message:
710
+ if message.context_id and message.context_id != context.context_id:
711
+ _fail(
712
+ "nested_message_identity_mismatch",
713
+ "Task Message.context_id",
714
+ "nested A2A Message context_id does not match outer Task",
715
+ )
716
+ if message.task_id and message.task_id != context.task_id:
717
+ _fail(
718
+ "nested_message_identity_mismatch",
719
+ "Task Message.task_id",
720
+ "nested A2A Message task_id does not match outer Task",
721
+ )
722
+ normalized = Message()
723
+ normalized.CopyFrom(message)
724
+ normalized.context_id = context.context_id
725
+ normalized.task_id = _required_string(context.task_id, "task_id")
726
+ return normalized
727
+
728
+ def _envelope(
729
+ self,
730
+ context: A2AAdapterContext,
731
+ source: SourceRef,
732
+ timestamp: float,
733
+ *,
734
+ item_id: str,
735
+ event_type: str,
736
+ part_id: str,
737
+ occurrence: _Occurrence,
738
+ ordinal: int,
739
+ ) -> dict[str, Any]:
740
+ return {
741
+ "schema_version": 2,
742
+ "event_id": stable_event_id(
743
+ "a2a",
744
+ context.scope_id,
745
+ item_id,
746
+ event_type,
747
+ part_id,
748
+ occurrence.identity,
749
+ ordinal,
750
+ ),
751
+ "seq": context.allocate_placeholder_seq(),
752
+ "timestamp": timestamp,
753
+ "run_id": context.run_id,
754
+ "scope_id": context.scope_id,
755
+ "source": source,
756
+ }
757
+
758
+ def _run_started_event(
759
+ self,
760
+ context: A2AAdapterContext,
761
+ source: SourceRef,
762
+ timestamp: float,
763
+ occurrence: _Occurrence,
764
+ ordinal: int,
765
+ ) -> RunStarted:
766
+ env = self._env_builder(context, source, timestamp, occurrence)
767
+ return RunStarted(**env(context.run_id, "run.started", "run", ordinal), status="running")
768
+
769
+ def _run_progress_event(
770
+ self,
771
+ context: A2AAdapterContext,
772
+ source: SourceRef,
773
+ timestamp: float,
774
+ occurrence: _Occurrence,
775
+ ordinal: int,
776
+ *,
777
+ message: str,
778
+ ) -> RunProgress:
779
+ env = self._env_builder(context, source, timestamp, occurrence)
780
+ return RunProgress(
781
+ **env(context.run_id, "run.progress", "run", ordinal),
782
+ status="running",
783
+ message=message,
784
+ )
785
+
786
+ def _reconciliation_diagnostic(
787
+ self,
788
+ context: A2AAdapterContext,
789
+ *,
790
+ reason: ReconciliationReason,
791
+ timestamp: float,
792
+ error: str,
793
+ exception_type: str,
794
+ attempt_id: str,
795
+ ) -> RunProgress:
796
+ occurrence = _Occurrence(
797
+ native_event_id=None,
798
+ native_cursor=None,
799
+ identity=(f"get-task:{reason}:{attempt_id}:failure:{error}:{exception_type}"),
800
+ provisional=True,
801
+ )
802
+ source = self._source(
803
+ context,
804
+ occurrence,
805
+ native_item_id=context.task_id,
806
+ metadata={
807
+ "provisional": True,
808
+ "consistent": False,
809
+ "reconciliation_reason": reason,
810
+ "reconciliation_attempt_id": attempt_id,
811
+ "reconciliation_error": exception_type,
812
+ "mapping_error": error,
813
+ },
814
+ )
815
+ return RunProgress(
816
+ schema_version=2,
817
+ event_id=stable_event_id(
818
+ "a2a",
819
+ context.scope_id,
820
+ context.run_id,
821
+ "run.progress",
822
+ "run",
823
+ occurrence.identity,
824
+ 0,
825
+ ),
826
+ seq=context.peek_placeholder_seq(),
827
+ timestamp=timestamp,
828
+ run_id=context.run_id,
829
+ scope_id=context.scope_id,
830
+ source=source,
831
+ status="running",
832
+ message="A2A GetTask reconciliation failed",
833
+ )
834
+
835
+
836
+ __all__ = [
837
+ "A2AAdapterContext",
838
+ "A2AEventAdapter",
839
+ "A2AMappingError",
840
+ "A2AReconciliationResult",
841
+ ]