agentengine-sdk-python 0.8.1__py3-none-any.whl → 0.8.3__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 (476) hide show
  1. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/METADATA +25 -12
  2. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/RECORD +421 -232
  3. ksadk/_build_provenance.json +1 -0
  4. ksadk/a2a/_space_client_events.py +381 -0
  5. ksadk/a2a/event_adapter.py +156 -64
  6. ksadk/a2a/executor.py +179 -63
  7. ksadk/a2a/space_client.py +6 -333
  8. ksadk/a2ui/core.py +222 -53
  9. ksadk/agui/_agent_helpers.py +247 -0
  10. ksadk/agui/a2ui_projection.py +12 -5
  11. ksadk/agui/agent.py +443 -259
  12. ksadk/api/client.py +528 -27
  13. ksadk/builders/code_builder.py +284 -8
  14. ksadk/builders/container_builder.py +8 -1
  15. ksadk/builders/managed_runtime_builder.py +42 -35
  16. ksadk/cli/__init__.py +23 -0
  17. ksadk/cli/cmd_dashboard.py +15 -1
  18. ksadk/cli/cmd_deploy.py +10 -2
  19. ksadk/cli/cmd_eval.py +66 -9
  20. ksadk/cli/cmd_evalset.py +284 -0
  21. ksadk/cli/cmd_files.py +5 -1
  22. ksadk/cli/cmd_hermes.py +1 -126
  23. ksadk/cli/cmd_invoke.py +28 -38
  24. ksadk/cli/cmd_managed_runtime.py +95 -0
  25. ksadk/cli/cmd_observe.py +85 -0
  26. ksadk/cli/cmd_openclaw.py +1 -435
  27. ksadk/cli/cmd_plugin.py +657 -0
  28. ksadk/cli/cmd_replay.py +28 -4
  29. ksadk/cli/cmd_studio.py +99 -8
  30. ksadk/cli/cmd_web.py +10 -2
  31. ksadk/cli/hermes_env.py +151 -0
  32. ksadk/cli/invoke_payload.py +49 -0
  33. ksadk/cli/openclaw_env.py +458 -0
  34. ksadk/codex/client.py +180 -30
  35. ksadk/codex/runtime.py +475 -331
  36. ksadk/configs/env_registry.py +94 -12
  37. ksadk/configs/env_registry_pcm.py +181 -0
  38. ksadk/configs/env_var_spec.py +18 -0
  39. ksadk/configs/global_config.py +5 -0
  40. ksadk/configs/settings.py +9 -0
  41. ksadk/context_engine/__init__.py +98 -0
  42. ksadk/context_engine/assembler.py +176 -0
  43. ksadk/context_engine/baseline.py +419 -0
  44. ksadk/context_engine/cache_observability.py +228 -0
  45. ksadk/context_engine/capabilities.py +443 -0
  46. ksadk/context_engine/contributors.py +409 -0
  47. ksadk/context_engine/hosted_pipeline.py +417 -0
  48. ksadk/context_engine/models.py +117 -0
  49. ksadk/context_engine/planner.py +698 -0
  50. ksadk/context_engine/policies.py +319 -0
  51. ksadk/context_engine/projection.py +31 -0
  52. ksadk/context_engine/shadow_plan.py +266 -0
  53. ksadk/context_engine/tokenizer.py +164 -0
  54. ksadk/conversations/__init__.py +19 -0
  55. ksadk/conversations/context.py +230 -30
  56. ksadk/conversations/contracts.py +266 -0
  57. ksadk/conversations/message_projection.py +308 -26
  58. ksadk/conversations/model_context.py +49 -3
  59. ksadk/conversations/projector.py +616 -0
  60. ksadk/conversations/reducer.py +98 -0
  61. ksadk/conversations/runtime_compaction.py +207 -5
  62. ksadk/conversations/runtime_input.py +184 -2
  63. ksadk/conversations/runtime_invocation.py +81 -3
  64. ksadk/conversations/runtime_observability.py +141 -0
  65. ksadk/conversations/runtime_payloads.py +42 -0
  66. ksadk/conversations/runtime_preparation.py +272 -2
  67. ksadk/conversations/runtime_resume.py +20 -1
  68. ksadk/conversations/runtime_stream_events.py +94 -9
  69. ksadk/conversations/semantic_summary.py +311 -1
  70. ksadk/conversations/session_lock.py +51 -0
  71. ksadk/deployment/env_forward.py +72 -0
  72. ksadk/deployment/managed_runtime.py +5 -0
  73. ksadk/deployment/providers/serverless.py +143 -69
  74. ksadk/evaluation/__init__.py +32 -0
  75. ksadk/evaluation/a2a_adapter.py +9 -1
  76. ksadk/evaluation/adapters.py +18 -5
  77. ksadk/evaluation/agent_eval_client.py +395 -0
  78. ksadk/evaluation/cloud_binding.py +80 -0
  79. ksadk/evaluation/cloud_converter.py +194 -0
  80. ksadk/evaluation/cloud_service.py +199 -0
  81. ksadk/evaluation/contracts.py +73 -4
  82. ksadk/evaluation/evaluators.py +183 -17
  83. ksadk/evaluation/evidence.py +258 -0
  84. ksadk/evaluation/executor.py +31 -6
  85. ksadk/evaluation/local_adapter.py +550 -0
  86. ksadk/evaluation/service_env.py +27 -0
  87. ksadk/evaluation/studio_build_adapter.py +253 -0
  88. ksadk/evaluation/target.py +15 -6
  89. ksadk/events/__init__.py +13 -13
  90. ksadk/events/_v1_compat/__init__.py +1 -0
  91. ksadk/events/_v1_compat/models.py +299 -0
  92. ksadk/events/_v1_compat/parser.py +247 -0
  93. ksadk/events/_v1_compat/projection.py +755 -0
  94. ksadk/events/adapters/__init__.py +34 -0
  95. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  96. ksadk/events/adapters/_a2a_support.py +275 -0
  97. ksadk/events/adapters/_codex_interactions.py +375 -0
  98. ksadk/events/adapters/_codex_items.py +801 -0
  99. ksadk/events/adapters/_codex_validators.py +311 -0
  100. ksadk/events/adapters/_langgraph_support.py +785 -0
  101. ksadk/events/adapters/a2a.py +841 -0
  102. ksadk/events/adapters/adk.py +503 -0
  103. ksadk/events/adapters/codex.py +907 -0
  104. ksadk/events/adapters/langgraph.py +745 -0
  105. ksadk/events/canonical.py +440 -0
  106. ksadk/events/canonical_replay.py +497 -0
  107. ksadk/events/canonical_store.py +468 -0
  108. ksadk/events/cold_recovery.py +257 -0
  109. ksadk/events/content.py +89 -0
  110. ksadk/events/identity.py +86 -0
  111. ksadk/events/pipeline.py +455 -0
  112. ksadk/events/projections.py +66 -0
  113. ksadk/events/reducer.py +661 -0
  114. ksadk/events/replay.py +3 -36
  115. ksadk/events/runtime_event.py +20 -265
  116. ksadk/events/session_event.py +324 -0
  117. ksadk/events/store.py +3 -316
  118. ksadk/events/v1_compat.py +41 -0
  119. ksadk/harness/__init__.py +45 -35
  120. ksadk/harness/runtime.py +220 -58
  121. ksadk/identity/resolver.py +4 -3
  122. ksadk/interaction/__init__.py +28 -0
  123. ksadk/interaction/contracts.py +136 -0
  124. ksadk/interaction/ledger.py +189 -0
  125. ksadk/interaction/provider.py +122 -0
  126. ksadk/interaction/providers/__init__.py +52 -0
  127. ksadk/interaction/providers/adk.py +40 -0
  128. ksadk/interaction/providers/codex.py +94 -0
  129. ksadk/interaction/providers/langgraph.py +58 -0
  130. ksadk/kernel/__init__.py +117 -0
  131. ksadk/kernel/authorization.py +258 -0
  132. ksadk/kernel/bootstrap.py +1074 -0
  133. ksadk/kernel/contract_fingerprints.py +62 -0
  134. ksadk/kernel/contracts.py +370 -0
  135. ksadk/kernel/control.py +220 -0
  136. ksadk/kernel/errors.py +79 -0
  137. ksadk/kernel/ingress.py +1123 -0
  138. ksadk/kernel/mapping.py +111 -0
  139. ksadk/kernel/memory_store.py +1134 -0
  140. ksadk/kernel/postgres_store.py +1757 -0
  141. ksadk/kernel/recovery.py +452 -0
  142. ksadk/kernel/runtime_identity.py +103 -0
  143. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  144. ksadk/kernel/sqlite_store.py +1411 -0
  145. ksadk/kernel/state.py +145 -0
  146. ksadk/kernel/store.py +232 -0
  147. ksadk/kernel/worker.py +964 -0
  148. ksadk/knowledge_base/client.py +7 -0
  149. ksadk/knowledge_base/service.py +32 -5
  150. ksadk/memory/__init__.py +61 -0
  151. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  152. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  153. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  154. ksadk/memory/adk/backends/sdk_ltm_backend.py +384 -2
  155. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  156. ksadk/memory/coordinator.py +461 -0
  157. ksadk/memory/events.py +202 -0
  158. ksadk/memory/extraction.py +228 -0
  159. ksadk/memory/ltm_backend_factory.py +16 -3
  160. ksadk/memory/models.py +316 -0
  161. ksadk/memory/policy.py +215 -0
  162. ksadk/memory/provider.py +47 -0
  163. ksadk/memory/provider_adapter.py +159 -0
  164. ksadk/memory/provider_resolver.py +71 -0
  165. ksadk/memory/providers/__init__.py +5 -0
  166. ksadk/memory/providers/local_sqlite.py +497 -0
  167. ksadk/memory/resolved_policy.py +145 -0
  168. ksadk/memory/service.py +188 -6
  169. ksadk/model_proxy/bootstrap.py +16 -9
  170. ksadk/model_proxy/detect.py +202 -9
  171. ksadk/model_proxy/namespace.py +39 -15
  172. ksadk/model_proxy/server.py +24 -5
  173. ksadk/model_proxy/transform.py +60 -2
  174. ksadk/observability/__init__.py +25 -0
  175. ksadk/observability/session_log.py +420 -0
  176. ksadk/observability/trajectory.py +105 -0
  177. ksadk/plugins/__init__.py +167 -0
  178. ksadk/plugins/bridges/__init__.py +45 -0
  179. ksadk/plugins/bridges/codex.py +552 -0
  180. ksadk/plugins/bridges/dsh.py +1116 -0
  181. ksadk/plugins/builtins.py +747 -0
  182. ksadk/plugins/bundle.py +246 -0
  183. ksadk/plugins/bundle_security.py +167 -0
  184. ksadk/plugins/composition.py +529 -0
  185. ksadk/plugins/context_contributor.py +437 -0
  186. ksadk/plugins/contracts.py +451 -0
  187. ksadk/plugins/dsh_toolchain.py +935 -0
  188. ksadk/plugins/ecosystem_bridge.py +1105 -0
  189. ksadk/plugins/ecosystem_probe.py +191 -0
  190. ksadk/plugins/host.py +724 -0
  191. ksadk/plugins/providers/__init__.py +85 -0
  192. ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
  193. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
  194. ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
  195. ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
  196. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
  197. ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
  198. ksadk/plugins/providers/codex.py +722 -0
  199. ksadk/plugins/providers/codex_dsh.py +83 -0
  200. ksadk/plugins/providers/dsh.py +951 -0
  201. ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
  202. ksadk/plugins/providers/harness.py +627 -0
  203. ksadk/plugins/providers/harness_dsh.py +91 -0
  204. ksadk/plugins/providers/legacy.py +215 -0
  205. ksadk/plugins/providers/legacy_catalog.py +100 -0
  206. ksadk/plugins/providers/shipped_dsh.py +370 -0
  207. ksadk/plugins/resolver.py +331 -0
  208. ksadk/plugins/subagent_providers/__init__.py +12 -0
  209. ksadk/plugins/subagent_providers/codex.py +443 -0
  210. ksadk/plugins/subagents.py +333 -0
  211. ksadk/prompts/__init__.py +71 -0
  212. ksadk/prompts/compiler.py +215 -0
  213. ksadk/prompts/models.py +82 -0
  214. ksadk/prompts/projection.py +89 -0
  215. ksadk/prompts/resolved.py +137 -0
  216. ksadk/prompts/sources.py +233 -0
  217. ksadk/runners/_langgraph_runner_streams.py +822 -0
  218. ksadk/runners/adk_runner.py +5 -5
  219. ksadk/runners/base_runner.py +16 -0
  220. ksadk/runners/factory.py +1 -2
  221. ksadk/runners/langgraph_runner.py +198 -437
  222. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  223. ksadk/runtime/_runner_adapter/stream_mapping.py +797 -0
  224. ksadk/runtime/adapter.py +119 -2
  225. ksadk/runtime/conversation_execution.py +316 -182
  226. ksadk/runtime/executor.py +144 -3
  227. ksadk/runtime/factory.py +268 -8
  228. ksadk/runtime/framework_adapters.py +18 -0
  229. ksadk/runtime/hosted_finalizer.py +268 -0
  230. ksadk/runtime/launch.py +14 -1
  231. ksadk/runtime/preprocessing.py +25 -3
  232. ksadk/runtime/runner_adapter.py +293 -508
  233. ksadk/runtime/usage.py +33 -0
  234. ksadk/sandbox/__init__.py +2 -1
  235. ksadk/sandbox/backends/e2b.py +35 -2
  236. ksadk/sandbox/factory.py +72 -0
  237. ksadk/scheduler/__init__.py +18 -0
  238. ksadk/scheduler/calendar.py +102 -0
  239. ksadk/scheduler/contracts.py +254 -0
  240. ksadk/scheduler/dispatcher.py +129 -0
  241. ksadk/scheduler/engine.py +416 -0
  242. ksadk/scheduler/sqlite_store.py +563 -0
  243. ksadk/server/composition.py +8 -0
  244. ksadk/server/factory.py +69 -6
  245. ksadk/server/routes/kernel_ingress.py +258 -0
  246. ksadk/server/routes/openai_compat.py +88 -8
  247. ksadk/server/routes/projection.py +35 -20
  248. ksadk/server/routes/run.py +94 -0
  249. ksadk/server/routes/sessions.py +2 -0
  250. ksadk/server/routes/streaming.py +5 -2
  251. ksadk/server/static/assets/{ArtifactsPanel-CakCqxEN.js → ArtifactsPanel-10GPXIJ6.js} +1 -1
  252. ksadk/server/static/assets/{CodeBlock-CynLknyO.js → CodeBlock-BXk1l-G1.js} +4 -4
  253. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  254. ksadk/server/static/assets/{MathMessageMarkdown-3sQdOysS.js → MathMessageMarkdown-D9uB55Oh.js} +4 -4
  255. ksadk/server/static/assets/MermaidBlock--OEYoXIJ.js +312 -0
  256. ksadk/server/static/assets/NativeTerminalPanel-DrEe1syq.js +1 -0
  257. ksadk/server/static/assets/abnfDiagram-VCTEODGH-eeTFJLvo.js +1 -0
  258. ksadk/server/static/assets/arc-S3ZNbIAd.js +1 -0
  259. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +1 -0
  260. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-CRjgEJDX.js +36 -0
  261. ksadk/server/static/assets/blockDiagram-NRAW4CY4-C7bsBoNH.js +129 -0
  262. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-BX3c33Ob.js +38 -0
  263. ksadk/server/static/assets/channel-s354Yo6o.js +1 -0
  264. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +1 -0
  265. ksadk/server/static/assets/{chunk-FMBD7UC4-B_fH2YuH.js → chunk-5VM5RSS4-bZ7ws-8m.js} +1 -1
  266. ksadk/server/static/assets/{chunk-ND2GUHAM-D6rFLaVV.js → chunk-F27PBJKO-D2r0pvhY.js} +1 -1
  267. ksadk/server/static/assets/chunk-G27WJ6UU-CZwF3oUP.js +231 -0
  268. ksadk/server/static/assets/{chunk-4BX2VUAB-B9drTgOW.js → chunk-JWPE2WC7-DigFYCML.js} +1 -1
  269. ksadk/server/static/assets/chunk-LCL6LL3I-CnorGV5q.js +206 -0
  270. ksadk/server/static/assets/chunk-POPQ4Y6H-CexntQA-.js +1 -0
  271. ksadk/server/static/assets/chunk-RHFEMEQ7-CHTC7UxA.js +168 -0
  272. ksadk/server/static/assets/chunk-SVP7TREG-BC1EWt_-.js +88 -0
  273. ksadk/server/static/assets/chunk-XXDRQBXY-BTG24xN0.js +1 -0
  274. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +1 -0
  275. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +1 -0
  276. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-ChNs_Mdk.js → cose-bilkent-JH36ORCC-CkonRdAS.js} +1 -1
  277. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +1 -0
  278. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-DEOCBe15.js +62 -0
  279. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  280. ksadk/server/static/assets/dagre-3AP2YEHR-DBThPuLa.js +4 -0
  281. ksadk/server/static/assets/dagre-ClTPrTht.js +1 -0
  282. ksadk/server/static/assets/diagram-S7CK7UJ4-DsZHrnpJ.js +30 -0
  283. ksadk/server/static/assets/diagram-UQ7AKVKN-BJR4nhVr.js +41 -0
  284. ksadk/server/static/assets/diagram-VSXAHHWV-xzcERX0a.js +3 -0
  285. ksadk/server/static/assets/diagram-VX7I27RA-tn2xM1xu.js +24 -0
  286. ksadk/server/static/assets/diagram-Z3DM3KII-BZPGBkw5.js +24 -0
  287. ksadk/server/static/assets/{dist-gLnrGsoU.js → dist-4zN1_tq5.js} +1 -1
  288. ksadk/server/static/assets/{dist-C1sz5Eo3.js → dist-8VWI-2bZ.js} +1 -1
  289. ksadk/server/static/assets/{dist-BjOdlDjj.js → dist-B-46q3Hk.js} +1 -1
  290. ksadk/server/static/assets/{dist-o2OVmKvt.js → dist-B0gdk4rl.js} +1 -1
  291. ksadk/server/static/assets/{dist-4N2NMVYg.js → dist-B1oWRmrH.js} +1 -1
  292. ksadk/server/static/assets/{dist-CmZHzlwZ.js → dist-BI1qQH4n.js} +1 -1
  293. ksadk/server/static/assets/{dist-X4TnqwOK.js → dist-BJLUwH6W.js} +1 -1
  294. ksadk/server/static/assets/{dist-B5oS1zcj.js → dist-Bbwqa8TG.js} +1 -1
  295. ksadk/server/static/assets/{dist-j6Dxmf_j.js → dist-Btyo4vX4.js} +1 -1
  296. ksadk/server/static/assets/{dist-DQU9EWw-.js → dist-C71CsujO.js} +1 -1
  297. ksadk/server/static/assets/{dist-BIlKoW0k.js → dist-CXpH_Rdd.js} +1 -1
  298. ksadk/server/static/assets/{dist-DJN_6Y39.js → dist-Cq4OL6nO.js} +1 -1
  299. ksadk/server/static/assets/{dist-Dli7qW-B.js → dist-D1V3f1B4.js} +1 -1
  300. ksadk/server/static/assets/{dist-fhOuWds5.js → dist-DJmCPRVB.js} +1 -1
  301. ksadk/server/static/assets/{dist-CWV4lDr1.js → dist-DQAB0qn_.js} +2 -2
  302. ksadk/server/static/assets/{dist-D6MpCZtz.js → dist-DUwKa_l6.js} +1 -1
  303. ksadk/server/static/assets/dist-DdRBIceA.js +1 -0
  304. ksadk/server/static/assets/{dist-DWKByxWV.js → dist-DfGFrb0v.js} +1 -1
  305. ksadk/server/static/assets/{dist-DsHPdk3W.js → dist-DjhwGUgZ.js} +1 -1
  306. ksadk/server/static/assets/{dist-B-jNR6Vn.js → dist-DyqV4fL4.js} +1 -1
  307. ksadk/server/static/assets/{dist-BB3-OwTQ.js → dist-M67Hwu0n.js} +1 -1
  308. ksadk/server/static/assets/{dist-_pHPTyZ-.js → dist-u8tVH5Ak.js} +1 -1
  309. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-DVfMsLge.js +1 -0
  310. ksadk/server/static/assets/erDiagram-SSCWMZ5O-CWEZSYaw.js +99 -0
  311. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +1 -0
  312. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +1 -0
  313. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-TWIxoyYL.js +292 -0
  314. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +1 -0
  315. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-DDh2hd2S.js +106 -0
  316. ksadk/server/static/assets/index-B2k_urY8.js +241 -0
  317. ksadk/server/static/assets/index-ILPt6IWF.css +2 -0
  318. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +1 -0
  319. ksadk/server/static/assets/infoDiagram-RXCK75RN-CgoyWiDR.js +2 -0
  320. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-K0OOfVna.js → ishikawaDiagram-5VMMS53U-CyRIu_om.js} +6 -6
  321. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-8LeOJaZp.js → journeyDiagram-EYS64GPL-DN5JXHzN.js} +6 -6
  322. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-C6uCgZrW.js → kanban-definition-3QL26DDD-CNP3ui66.js} +10 -10
  323. ksadk/server/static/assets/katex-DWEzQy1d.js +257 -0
  324. ksadk/server/static/assets/{linear-hdBcYzM8.js → linear-C-qHp7d2.js} +1 -1
  325. ksadk/server/static/assets/mermaid-parser.core-Cl-K943T.js +166 -0
  326. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-Bjy_2v4_.js → mindmap-definition-FBJOCRG2-D5DB5mYm.js} +29 -29
  327. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +1 -0
  328. ksadk/server/static/assets/pegDiagram-XKGWAZYB-BQVc9ia_.js +1 -0
  329. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +1 -0
  330. ksadk/server/static/assets/pieDiagram-E7YTZNPT-B6UCAvtY.js +39 -0
  331. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-BmkRbwCg.js → quadrantDiagram-AXDQQJYC-mIr2d3eb.js} +6 -6
  332. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +1 -0
  333. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +1 -0
  334. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +1 -0
  335. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +1 -0
  336. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +1 -0
  337. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-Dt3FFDmK.js +1 -0
  338. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-Cz_vQtgF.js +84 -0
  339. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-l6iXmU65.js → sankeyDiagram-P5KCCOFB-wlO1TsH5.js} +7 -7
  340. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-Cq6UBeQB.js → sequenceDiagram-WJ2MYXX4-CHRbElYq.js} +10 -10
  341. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-DXX54iyO.js +1 -0
  342. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-Dp_lw9II.js +1 -0
  343. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +1 -0
  344. ksadk/server/static/assets/swimlanes-XN3QIQJK-D8O5UlLG.js +1 -0
  345. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +8 -0
  346. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-DEz24vV0.js → timeline-definition-24CTP7MA-8mfKcxvG.js} +7 -7
  347. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +1 -0
  348. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +1 -0
  349. ksadk/server/static/assets/vennDiagram-4TSXK5OY-EnNl0DE7.js +34 -0
  350. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +1 -0
  351. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DBu5fbYr.js +78 -0
  352. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-BSVXs4IY.js +7 -0
  353. ksadk/server/static/index.html +2 -2
  354. ksadk/sessions/__init__.py +26 -9
  355. ksadk/sessions/_local_service_sync.py +688 -0
  356. ksadk/sessions/_local_tables.py +21 -0
  357. ksadk/sessions/_postgres_schema.py +305 -0
  358. ksadk/sessions/_postgres_tables.py +15 -0
  359. ksadk/sessions/base.py +80 -1
  360. ksadk/sessions/in_memory.py +53 -2
  361. ksadk/sessions/local_service.py +63 -604
  362. ksadk/sessions/postgres_service.py +58 -148
  363. ksadk/sessions/resilient.py +35 -1
  364. ksadk/skills/service_client.py +48 -0
  365. ksadk/studio/agent_lifecycle.py +26 -20
  366. ksadk/studio/api.py +1063 -69
  367. ksadk/studio/api_catalog_routes.py +5 -0
  368. ksadk/studio/api_contracts.py +148 -6
  369. ksadk/studio/api_memory_routes.py +82 -0
  370. ksadk/studio/api_plugin_routes.py +480 -0
  371. ksadk/studio/attachment_store.py +187 -0
  372. ksadk/studio/authoring.py +259 -28
  373. ksadk/studio/authoring_coordinator.py +809 -67
  374. ksadk/studio/builder.py +197 -40
  375. ksadk/studio/capabilities.py +17 -0
  376. ksadk/studio/cloud.py +1920 -95
  377. ksadk/studio/codex_agent_service.py +137 -15
  378. ksadk/studio/codex_authoring.py +469 -0
  379. ksadk/studio/codex_builder.py +177 -25
  380. ksadk/studio/codex_manifest.py +71 -22
  381. ksadk/studio/codex_run.py +59 -4
  382. ksadk/studio/compatibility_report.py +445 -0
  383. ksadk/studio/compiler.py +7 -1
  384. ksadk/studio/contracts.py +234 -4
  385. ksadk/studio/dsh_provider_registration.py +768 -0
  386. ksadk/studio/event_store.py +79 -101
  387. ksadk/studio/framework_run.py +264 -3
  388. ksadk/studio/hosted_kernel.py +317 -0
  389. ksadk/studio/manifest_resolver.py +131 -0
  390. ksadk/studio/model_client.py +95 -9
  391. ksadk/studio/model_profile_service.py +1 -1
  392. ksadk/studio/operations.py +47 -5
  393. ksadk/studio/otel_trace.py +348 -42
  394. ksadk/studio/pcm_memory.py +85 -0
  395. ksadk/studio/plugin_composition.py +301 -0
  396. ksadk/studio/plugin_kernel_adapter.py +128 -0
  397. ksadk/studio/plugin_runtime.py +652 -0
  398. ksadk/studio/repository.py +23 -2
  399. ksadk/studio/resource_catalog.py +49 -1
  400. ksadk/studio/run_service.py +1266 -202
  401. ksadk/studio/runtime_source.py +51 -17
  402. ksadk/studio/scheduler_runtime.py +374 -0
  403. ksadk/studio/scheduler_service.py +211 -0
  404. ksadk/studio/service.py +1815 -117
  405. ksadk/studio/shared_web.py +199 -50
  406. ksadk/studio/soul.py +52 -0
  407. ksadk/studio/static/assets/index-DXs1Eq4M.css +1 -0
  408. ksadk/studio/static/assets/index-DeDqwTsD.js +283 -0
  409. ksadk/studio/static/index.html +2 -2
  410. ksadk/studio/templates.py +100 -8
  411. ksadk/studio/validator.py +20 -1
  412. ksadk/studio/workspace.py +31 -32
  413. ksadk/tracing/setup.py +304 -3
  414. ksadk/version.py +1 -1
  415. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  416. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  417. ksadk_runtime_common/workspace_files/path_utils.py +41 -0
  418. ksadk/events/parser.py +0 -191
  419. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  420. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +0 -303
  421. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +0 -1
  422. ksadk/server/static/assets/arc-DrgjcKhl.js +0 -1
  423. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +0 -1
  424. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-BXoVRbQ6.js +0 -36
  425. ksadk/server/static/assets/blockDiagram-GPEHLZMM-BnaB3Ywv.js +0 -132
  426. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dw4weZcp.js +0 -10
  427. ksadk/server/static/assets/channel-Dt3rQTFI.js +0 -1
  428. ksadk/server/static/assets/chunk-2J33WTMH-ChjpLK7j.js +0 -1
  429. ksadk/server/static/assets/chunk-55IACEB6-CK4ROATy.js +0 -1
  430. ksadk/server/static/assets/chunk-727SXJPM-B9KtTTgw.js +0 -206
  431. ksadk/server/static/assets/chunk-AQP2D5EJ-1O1mki3m.js +0 -231
  432. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +0 -1
  433. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +0 -1
  434. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +0 -1
  435. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  436. ksadk/server/static/assets/dagre-BM42HDAG-D0QXg_MQ.js +0 -4
  437. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  438. ksadk/server/static/assets/diagram-2AECGRRQ-DBDDKwBQ.js +0 -43
  439. ksadk/server/static/assets/diagram-5GNKFQAL-BkwDOxmO.js +0 -10
  440. ksadk/server/static/assets/diagram-KO2AKTUF-Bv8waYvY.js +0 -3
  441. ksadk/server/static/assets/diagram-LMA3HP47-e1VECDdu.js +0 -24
  442. ksadk/server/static/assets/diagram-OG6HWLK6-Ds9adfRl.js +0 -24
  443. ksadk/server/static/assets/dist-B5J2uhNk.js +0 -1
  444. ksadk/server/static/assets/erDiagram-TEJ5UH35-BPItFKH6.js +0 -85
  445. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +0 -1
  446. ksadk/server/static/assets/flowDiagram-I6XJVG4X-BbYB9w5Y.js +0 -162
  447. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-TQXa0KXv.js +0 -292
  448. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +0 -1
  449. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-bKblCnpa.js +0 -106
  450. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  451. ksadk/server/static/assets/index-R52pJJvg.js +0 -177
  452. ksadk/server/static/assets/index-jJr3_955.css +0 -2
  453. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +0 -1
  454. ksadk/server/static/assets/infoDiagram-5YYISTIA-BGVT7J_i.js +0 -2
  455. ksadk/server/static/assets/katex-CYWseY5E.js +0 -265
  456. ksadk/server/static/assets/mermaid-parser.core-BWrDjSZM.js +0 -161
  457. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +0 -1
  458. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +0 -1
  459. ksadk/server/static/assets/pieDiagram-4H26LBE5-GmmqNiVH.js +0 -30
  460. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +0 -1
  461. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DSWFqL7c.js +0 -84
  462. ksadk/server/static/assets/stateDiagram-AJRCARHV-qzTQpg3Y.js +0 -1
  463. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +0 -1
  464. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +0 -1
  465. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +0 -1
  466. ksadk/server/static/assets/vennDiagram-CIIHVFJN-CMCixki2.js +0 -34
  467. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +0 -1
  468. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-CVzB8F9K.js +0 -78
  469. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-BFBqBLc1.js +0 -7
  470. ksadk/studio/evaluation.py +0 -192
  471. ksadk/studio/static/assets/index-CaEN0eTR.css +0 -1
  472. ksadk/studio/static/assets/index-DI2eY_NH.js +0 -252
  473. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/WHEEL +0 -0
  474. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/entry_points.txt +0 -0
  475. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/licenses/LICENSE +0 -0
  476. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@ from typing import Any
5
5
  from urllib.parse import quote
6
6
 
7
7
  from ksadk.agui.a2ui_projection import project_a2ui_operations
8
- from ksadk.events.runtime_event import EventType
9
8
 
10
9
 
11
10
  def _event_metadata(event: Mapping[str, Any]) -> Mapping[str, Any]:
@@ -20,7 +19,18 @@ def project_session_messages(
20
19
  include_tool_events: bool = False,
21
20
  include_attachments: bool = True,
22
21
  ) -> list[dict[str, Any]]:
23
- """Project persisted runtime events into the chat history contract."""
22
+ """Project persisted runtime events into the chat history contract.
23
+
24
+ 公开承诺字段(契约声明见 ``ksadk/events/projections.py``,执行形态为
25
+ ``tests/protocol/test_cross_projection_golden.py``):
26
+ - 每条消息含 ``Role``/``Content.text``/``SeqId``/``StartSeqId``;
27
+ - 开启 include_reasoning 时含 ``Reasoning``;开启 include_tool_events 时
28
+ 含 ``ToolEvents``(approval 项含 ``ApprovalRequestId``);
29
+ - A2UI 项以 ``Activities`` 携带(内含 ``surfaceId``)。
30
+
31
+ 内部不保证字段:分组实现细节、事件归并产生的中间键、未经开关开启的
32
+ 可选区块。
33
+ """
24
34
 
25
35
  agui_invocations = _agui_invocation_ids(events)
26
36
  normalized = [
@@ -59,7 +69,10 @@ def _project_event_group(
59
69
  for event in events
60
70
  if event.get("EventType") == "reasoning" and _event_text(event)
61
71
  ]
62
- tool_events = (
72
+ # Split tool events: approval-only events before first assistant_message
73
+ # vs all tool events. When approval events precede a text completion, they
74
+ # get their own assistant message placeholder.
75
+ all_tool_events = (
63
76
  _project_tool_events(events, approval_responses=approval_responses)
64
77
  if include_tool_events
65
78
  else []
@@ -71,6 +84,27 @@ def _project_event_group(
71
84
  streamed_text = ""
72
85
  start_seq_id = min((int(event.get("SeqId") or 0) for event in events), default=0)
73
86
 
87
+ # Check if there are approval events before the first assistant_message.
88
+ # When approval events precede a text completion, they get their own
89
+ # assistant message placeholder with empty text.
90
+ has_assistant_message = any(
91
+ str(e.get("EventType") or "") == "assistant_message" for e in events
92
+ )
93
+ pre_assistant_tool_events: list[dict[str, Any]] = []
94
+ post_assistant_tool_events: list[dict[str, Any]] = []
95
+ if has_assistant_message and all_tool_events:
96
+ # Split: approval events go to pre_assistant, tool_call/tool_result
97
+ # go to post_assistant.
98
+ for te in all_tool_events:
99
+ if te.get("Type") == "approval":
100
+ pre_assistant_tool_events.append(te)
101
+ else:
102
+ post_assistant_tool_events.append(te)
103
+ else:
104
+ post_assistant_tool_events = list(all_tool_events)
105
+
106
+ has_pre_assistant_approvals = bool(pre_assistant_tool_events)
107
+
74
108
  for event in events:
75
109
  event_type = str(event.get("EventType") or "")
76
110
  if event_type == "user_message":
@@ -81,13 +115,31 @@ def _project_event_group(
81
115
  message["Attachments"] = attachments
82
116
  projected.append(message)
83
117
  elif event_type == "assistant_message":
118
+ # If there are approval events that preceded this assistant_message,
119
+ # emit a placeholder assistant message for them first.
120
+ if has_pre_assistant_approvals and not assistant_seen:
121
+ anchor = next(
122
+ (e for e in events
123
+ if str(e.get("EventType") or "") == "approval_request"),
124
+ events[0],
125
+ )
126
+ placeholder = _base_message(anchor, "assistant", content="")
127
+ if include_tool_events and pre_assistant_tool_events:
128
+ placeholder["ToolEvents"] = pre_assistant_tool_events
129
+ projected.append(placeholder)
130
+ assistant_seen = True
131
+ # Don't add tool_events/reasoning to the next message — they
132
+ # belong to the placeholder.
84
133
  message = _base_message(event, "assistant")
134
+ # Attach reasoning to the first non-placeholder assistant message.
135
+ # When has_pre_assistant_approvals is True, the placeholder was
136
+ # already emitted, so this is the real assistant message.
85
137
  if include_reasoning and reasoning:
86
138
  message["Reasoning"] = reasoning
87
- if tool_events:
88
- message["ToolEvents"] = tool_events
139
+ if include_tool_events and post_assistant_tool_events:
140
+ message["ToolEvents"] = post_assistant_tool_events
89
141
  if include_reasoning:
90
- blocks = _project_interleaved_blocks(events, tool_events=tool_events)
142
+ blocks = _project_interleaved_blocks(events, tool_events=post_assistant_tool_events)
91
143
  if blocks:
92
144
  message["Blocks"] = blocks
93
145
  projected.append(message)
@@ -98,7 +150,7 @@ def _project_event_group(
98
150
  streamed_text += _event_text(event)
99
151
 
100
152
  if not assistant_seen and (
101
- latest_snapshot is not None or streamed_text or reasoning or tool_events or activities
153
+ latest_snapshot is not None or streamed_text or reasoning or all_tool_events or activities
102
154
  ):
103
155
  anchor = next(
104
156
  (
@@ -111,9 +163,9 @@ def _project_event_group(
111
163
  "approval_request",
112
164
  "tool_call",
113
165
  "reasoning",
114
- EventType.A2UI_SURFACE_BEGIN,
115
- EventType.A2UI_SURFACE_UPDATE,
116
- EventType.A2UI_SURFACE_END,
166
+ "a2ui.surface.begin",
167
+ "a2ui.surface.update",
168
+ "a2ui.surface.end",
117
169
  }
118
170
  ),
119
171
  events[-1],
@@ -127,10 +179,10 @@ def _project_event_group(
127
179
  )
128
180
  if include_reasoning and reasoning:
129
181
  message["Reasoning"] = reasoning
130
- if tool_events:
131
- message["ToolEvents"] = tool_events
182
+ if all_tool_events:
183
+ message["ToolEvents"] = all_tool_events
132
184
  if include_reasoning:
133
- blocks = _project_interleaved_blocks(events, tool_events=tool_events)
185
+ blocks = _project_interleaved_blocks(events, tool_events=all_tool_events)
134
186
  if blocks:
135
187
  message["Blocks"] = blocks
136
188
  projected.append(message)
@@ -462,9 +514,9 @@ def _project_a2ui_activities(events: Sequence[Mapping[str, Any]]) -> list[dict[s
462
514
  for event in events:
463
515
  event_type = str(event.get("EventType") or "")
464
516
  if event_type not in {
465
- EventType.A2UI_SURFACE_BEGIN,
466
- EventType.A2UI_SURFACE_UPDATE,
467
- EventType.A2UI_SURFACE_END,
517
+ "a2ui.surface.begin",
518
+ "a2ui.surface.update",
519
+ "a2ui.surface.end",
468
520
  }:
469
521
  continue
470
522
  content = event.get("Content")
@@ -492,7 +544,7 @@ def _agui_invocation_ids(events: Sequence[Mapping[str, Any]]) -> set[str]:
492
544
  """Locate AG-UI runs so history written before ``payload.protocol`` remains usable."""
493
545
  invocation_ids: set[str] = set()
494
546
  for event in events:
495
- if str(event.get("EventType") or "") != EventType.RUN_STARTED:
547
+ if str(event.get("EventType") or "") != "run.started":
496
548
  continue
497
549
  if not _event_metadata(event).get("ksadk_runtime_event"):
498
550
  continue
@@ -505,16 +557,246 @@ def _agui_invocation_ids(events: Sequence[Mapping[str, Any]]) -> set[str]:
505
557
  return invocation_ids
506
558
 
507
559
 
560
+ _CANONICAL_EVENT_TYPE_MAP = {
561
+ "run.started": "run.started",
562
+ "run.completed": "run.completed",
563
+ "run.failed": "run.failed",
564
+ "run.canceled": "run.canceled",
565
+ "run.interrupted": "run.interrupted",
566
+ "item.started": "item.started",
567
+ "item.updated": "item.updated",
568
+ "item.completed": "item.completed",
569
+ "interaction.requested": "approval.requested",
570
+ }
571
+
572
+
573
+ def _normalize_canonical_event(
574
+ event: Mapping[str, Any],
575
+ content: Mapping[str, Any],
576
+ metadata: Mapping[str, Any],
577
+ ) -> Mapping[str, Any]:
578
+ """Project a canonical v2 SessionEvent into the legacy v1 wire shape."""
579
+ runtime_event = content.get("runtime_event")
580
+ if not isinstance(runtime_event, Mapping):
581
+ return event
582
+ event_type = str(runtime_event.get("event_type") or "")
583
+ item_kind = str(runtime_event.get("item_kind") or "")
584
+ raw_source = runtime_event.get("source") or {}
585
+ source = raw_source if isinstance(raw_source, Mapping) else {}
586
+ normalized = dict(event)
587
+ normalized_metadata = dict(metadata)
588
+
589
+ if event_type == "run.started":
590
+ source_metadata = source.get("metadata") if isinstance(source, Mapping) else None
591
+ if isinstance(source_metadata, Mapping) and source_metadata.get("source") == "ag-ui":
592
+ normalized["EventType"] = "user_message"
593
+ normalized["Content"] = {"text": _input_text(source_metadata.get("input"))}
594
+ normalized["Author"] = "user"
595
+ normalized["Metadata"] = normalized_metadata
596
+ return normalized
597
+ normalized["EventType"] = "run.started"
598
+ normalized["Content"] = {"status": runtime_event.get("status", "running")}
599
+ elif event_type == "run.completed":
600
+ normalized["EventType"] = "run.completed"
601
+ normalized["Content"] = {"status": "completed"}
602
+ elif event_type == "run.failed":
603
+ normalized["EventType"] = "run.failed"
604
+ error = runtime_event.get("error") or {}
605
+ normalized["Content"] = {"status": "failed", "error": error.get("message", "")}
606
+ elif event_type == "run.canceled":
607
+ normalized["EventType"] = "run.canceled"
608
+ normalized["Content"] = {"status": "canceled"}
609
+ elif event_type == "run.interrupted":
610
+ normalized["EventType"] = "run.interrupted"
611
+ normalized["Content"] = {"status": "interrupted"}
612
+ elif event_type == "item.started":
613
+ if item_kind == "tool_call":
614
+ initial = runtime_event.get("initial") or {}
615
+ parts = initial.get("parts") if isinstance(initial, Mapping) else None
616
+ part = parts[0] if isinstance(parts, list) and parts else {}
617
+ call_id = part.get("call_id", "")
618
+ name = part.get("name", "")
619
+ args = part.get("arguments", {})
620
+ normalized["EventType"] = "tool_call"
621
+ normalized["Content"] = {"call_id": call_id, "name": name, "args": args}
622
+ normalized_metadata.update({"call_id": call_id, "tool_name": name, "tool_args": args})
623
+ elif item_kind == "data" and source.get("protocol") == "a2ui":
624
+ surface_id = str(source.get("metadata", {}).get("surface_id") or "")
625
+ source_metadata = source.get("metadata")
626
+ initial = runtime_event.get("initial") or {}
627
+ parts = initial.get("parts") if isinstance(initial, Mapping) else []
628
+ data: Any = {}
629
+ for part in (parts or []):
630
+ if isinstance(part, Mapping) and part.get("content_type") == "data":
631
+ data = part.get("data")
632
+ break
633
+ if (
634
+ isinstance(data, list)
635
+ and isinstance(source_metadata, Mapping)
636
+ and source_metadata.get("operation_batch") is True
637
+ ):
638
+ normalized["Content"] = {
639
+ "surface_id": surface_id,
640
+ "a2ui_operations": data,
641
+ }
642
+ elif isinstance(data, list):
643
+ normalized["Content"] = {"surface_id": surface_id, "components": data}
644
+ elif isinstance(data, Mapping):
645
+ normalized["Content"] = data
646
+ else:
647
+ normalized["Content"] = {"surface_id": surface_id}
648
+ normalized["EventType"] = "a2ui.surface.begin"
649
+ else:
650
+ return event
651
+ elif event_type == "item.completed":
652
+ if item_kind == "message":
653
+ snapshot = runtime_event.get("snapshot") or {}
654
+ parts = snapshot.get("parts") if isinstance(snapshot, Mapping) else None
655
+ text = ""
656
+ if isinstance(parts, list):
657
+ for part in parts:
658
+ if isinstance(part, Mapping) and part.get("content_type") == "text":
659
+ text = part.get("text", "")
660
+ break
661
+ if not text:
662
+ return event
663
+ normalized["EventType"] = "assistant_message"
664
+ normalized["Content"] = {"role": "model", "parts": [{"text": text}]}
665
+ normalized["Author"] = "assistant"
666
+ elif item_kind == "tool_call":
667
+ return event
668
+ elif item_kind == "tool_result":
669
+ snapshot = runtime_event.get("snapshot") or {}
670
+ parts = snapshot.get("parts") if isinstance(snapshot, Mapping) else None
671
+ part = parts[0] if isinstance(parts, list) and parts else {}
672
+ call_id = part.get("call_id", "")
673
+ result = part.get("result", "")
674
+ normalized["EventType"] = "tool_result"
675
+ normalized["Content"] = {"call_id": call_id, "name": "", "result": result}
676
+ normalized_metadata.update({"call_id": call_id, "tool_output": result})
677
+ elif item_kind == "data" and source.get("protocol") == "a2ui":
678
+ source_metadata = source.get("metadata")
679
+ if (
680
+ isinstance(source_metadata, Mapping)
681
+ and source_metadata.get("operation_batch") is True
682
+ ):
683
+ return event
684
+ surface_id = str(source.get("metadata", {}).get("surface_id") or "")
685
+ normalized["EventType"] = "a2ui.surface.end"
686
+ normalized["Content"] = {"surface_id": surface_id}
687
+ else:
688
+ return event
689
+ elif event_type == "item.updated":
690
+ if item_kind == "message":
691
+ update = runtime_event.get("update") or {}
692
+ text = update.get("text", "") if isinstance(update, Mapping) else ""
693
+ normalized["EventType"] = "assistant_stream_delta"
694
+ normalized["Content"] = {"role": "model", "parts": [{"text": text}]}
695
+ elif item_kind == "reasoning":
696
+ update = runtime_event.get("update") or {}
697
+ text = update.get("text", "") if isinstance(update, Mapping) else ""
698
+ normalized["EventType"] = "reasoning"
699
+ normalized["Content"] = {"role": "model", "parts": [{"text": text}]}
700
+ elif item_kind == "data" and source.get("protocol") == "a2ui":
701
+ surface_id = str(source.get("metadata", {}).get("surface_id") or "")
702
+ update = runtime_event.get("update") or {}
703
+ update_data = update.get("data") if isinstance(update, Mapping) else None
704
+ if isinstance(update_data, list):
705
+ normalized["Content"] = {"surface_id": surface_id, "components": update_data}
706
+ elif isinstance(update_data, Mapping):
707
+ normalized["Content"] = update_data
708
+ else:
709
+ normalized["Content"] = {"surface_id": surface_id}
710
+ normalized["EventType"] = "a2ui.surface.update"
711
+ else:
712
+ return event
713
+ elif event_type == "interaction.requested":
714
+ interaction_kind = str(runtime_event.get("interaction_kind") or "approval")
715
+ request = runtime_event.get("request") or {}
716
+ if not isinstance(request, Mapping):
717
+ request = {}
718
+ if interaction_kind == "approval":
719
+ interaction_id = str(runtime_event.get("interaction_id") or "")
720
+ call_id = str(request.get("call_id") or "")
721
+ kind = str(request.get("kind") or "approval")
722
+ detail = request.get("detail")
723
+ if not isinstance(detail, Mapping):
724
+ detail = {}
725
+ normalized["EventType"] = "approval_request"
726
+ normalized["Content"] = {"detail": detail}
727
+ normalized_metadata["interrupt_info"] = {
728
+ "approval_request_id": interaction_id or call_id,
729
+ "id": interaction_id or call_id,
730
+ "tool_name": detail.get("tool_name") or kind,
731
+ "arguments": detail.get("arguments") or detail.get("args"),
732
+ "approval_level": detail.get("approval_level"),
733
+ "approval_message": detail.get("message"),
734
+ }
735
+ # Preserve ag-ui protocol tag from source metadata.
736
+ source = runtime_event.get("source") or {}
737
+ source_metadata = source.get("metadata") if isinstance(source, Mapping) else None
738
+ if isinstance(source_metadata, Mapping) and source_metadata.get("protocol") == "ag-ui":
739
+ normalized_metadata["protocol"] = "ag-ui"
740
+ else:
741
+ # structured_input: project as approval_request but with
742
+ # structured input schema in detail.
743
+ interaction_id = str(runtime_event.get("interaction_id") or "")
744
+ normalized["EventType"] = "approval_request"
745
+ normalized["Content"] = {"detail": request}
746
+ normalized_metadata["interrupt_info"] = {
747
+ "approval_request_id": interaction_id,
748
+ "id": interaction_id,
749
+ "tool_name": "structured_input",
750
+ "arguments": None,
751
+ }
752
+ elif event_type == "interaction.resolved":
753
+ interaction_kind = str(runtime_event.get("interaction_kind") or "")
754
+ response = runtime_event.get("response") or {}
755
+ if not isinstance(response, Mapping):
756
+ response = {}
757
+ response_type = str(response.get("response_type") or "")
758
+ interaction_id = str(runtime_event.get("interaction_id") or "")
759
+ if response_type == "approval":
760
+ decision = str(response.get("decision") or "")
761
+ normalized["EventType"] = "approval_response"
762
+ normalized["Content"] = {"detail": response}
763
+ normalized_metadata["resume_input"] = {
764
+ "approval_request_id": interaction_id,
765
+ "approve": decision in ("approved", "approve", True),
766
+ "decision": decision,
767
+ }
768
+ source = runtime_event.get("source") or {}
769
+ source_metadata = source.get("metadata") if isinstance(source, Mapping) else None
770
+ if isinstance(source_metadata, Mapping) and source_metadata.get("protocol") == "ag-ui":
771
+ normalized_metadata["protocol"] = "ag-ui"
772
+ else:
773
+ normalized["EventType"] = "approval_response"
774
+ normalized["Content"] = {"detail": response}
775
+ normalized_metadata["resume_input"] = {
776
+ "approval_request_id": interaction_id,
777
+ "approve": True,
778
+ "decision": "approved",
779
+ }
780
+ else:
781
+ return event
782
+
783
+ normalized["Metadata"] = normalized_metadata
784
+ return normalized
785
+
786
+
508
787
  def _normalize_runtime_event(
509
788
  event: Mapping[str, Any],
510
789
  *,
511
790
  agui_invocations: set[str],
512
791
  ) -> Mapping[str, Any]:
513
792
  metadata = _event_metadata(event)
514
- if not metadata.get("ksadk_runtime_event"):
793
+ is_canonical = metadata.get("ksadk_canonical_runtime_event")
794
+ if not metadata.get("ksadk_runtime_event") and not is_canonical:
515
795
  return event
516
796
  raw_content = event.get("Content")
517
797
  content = raw_content if isinstance(raw_content, Mapping) else {}
798
+ if is_canonical:
799
+ return _normalize_canonical_event(event, content, metadata)
518
800
  payload = content.get("payload")
519
801
  payload = payload if isinstance(payload, Mapping) else {}
520
802
  event_type = str(event.get("EventType") or "")
@@ -522,17 +804,17 @@ def _normalize_runtime_event(
522
804
  normalized["Content"] = dict(payload)
523
805
  normalized_metadata = dict(metadata)
524
806
 
525
- if event_type == EventType.RUN_STARTED and payload.get("source") == "ag-ui":
807
+ if event_type == "run.started" and payload.get("source") == "ag-ui":
526
808
  normalized["EventType"] = "user_message"
527
809
  normalized["Content"] = {"text": _input_text(payload.get("input"))}
528
810
  normalized["Author"] = "user"
529
- elif event_type == EventType.TEXT_COMPLETED:
811
+ elif event_type == "text.completed":
530
812
  normalized["EventType"] = "assistant_message"
531
- elif event_type == EventType.TEXT_DELTA:
813
+ elif event_type == "text.delta":
532
814
  normalized["EventType"] = "assistant_stream_delta"
533
- elif event_type in {EventType.REASONING_DELTA, EventType.REASONING_COMPLETED}:
815
+ elif event_type in {"reasoning.delta", "reasoning.completed"}:
534
816
  normalized["EventType"] = "reasoning"
535
- elif event_type == EventType.TOOL_CALL_BEGIN:
817
+ elif event_type == "tool.call.begin":
536
818
  normalized["EventType"] = "tool_call"
537
819
  normalized_metadata.update(
538
820
  {
@@ -541,7 +823,7 @@ def _normalize_runtime_event(
541
823
  "tool_args": payload.get("args"),
542
824
  }
543
825
  )
544
- elif event_type == EventType.TOOL_CALL_END:
826
+ elif event_type == "tool.call.end":
545
827
  normalized["EventType"] = "tool_result"
546
828
  normalized_metadata.update(
547
829
  {
@@ -550,7 +832,7 @@ def _normalize_runtime_event(
550
832
  "tool_output": payload.get("result", payload.get("error")),
551
833
  }
552
834
  )
553
- elif event_type == EventType.APPROVAL_REQUESTED:
835
+ elif event_type == "approval.requested":
554
836
  detail = payload.get("detail")
555
837
  detail = detail if isinstance(detail, Mapping) else {}
556
838
  approval_request = detail.get("approval_requests")
@@ -593,7 +875,7 @@ def _normalize_runtime_event(
593
875
  )
594
876
  if is_agui_approval:
595
877
  normalized_metadata["protocol"] = "ag-ui"
596
- elif event_type == EventType.APPROVAL_RESOLVED:
878
+ elif event_type == "approval.resolved":
597
879
  decision = payload.get("decision")
598
880
  normalized["EventType"] = "approval_response"
599
881
  normalized_metadata["resume_input"] = {
@@ -156,7 +156,7 @@ def estimate_text_tokens(text: str) -> int:
156
156
  """轻量 token 估算。
157
157
 
158
158
  当前先做一层比 `len/4` 更稳的启发式:
159
- - CJK 字符按 1 token 估算,避免中文场景长期卡在 0% / 1%
159
+ - CJK 字符按约 1.5 token 估算,降低中文场景的系统性低估
160
160
  - 其他字符继续按 4 chars ~= 1 token 估算
161
161
 
162
162
  这仍然不是真实 tokenizer,但比纯英文口径更接近本地中文使用体验。
@@ -176,10 +176,10 @@ def estimate_text_tokens(text: str) -> int:
176
176
  or 0x4E00 <= codepoint <= 0x9FFF
177
177
  or 0xF900 <= codepoint <= 0xFAFF
178
178
  ):
179
- cjk_tokens += 1
179
+ cjk_tokens += 1.5 # tiktoken cl100k_base: CJK ~1.5 tokens/char
180
180
  else:
181
181
  ascii_chars += 1
182
- return max(1, cjk_tokens + math.ceil(ascii_chars / 4))
182
+ return max(1, int(cjk_tokens) + math.ceil(ascii_chars / 4))
183
183
 
184
184
 
185
185
  def get_context_window_tokens(model_metadata: Mapping[str, Any] | None = None) -> int:
@@ -226,6 +226,52 @@ def get_auto_compact_threshold_percentage(model_metadata: Mapping[str, Any] | No
226
226
  return max(0, min(100, int(round((threshold_tokens / context_window) * 100))))
227
227
 
228
228
 
229
+ # --- PR D1:双阈值(仅 ksadk_hosted 路径使用) ---
230
+ # soft_limit:proactive 整理触发线(默认 50% effective window)。
231
+ # hard_limit:proactive 强制压缩触发线(≈ 现单阈值,默认 ~84%),尽量在 PTL 之前止血。
232
+ # 非 ksadk_hosted 路径仍用 get_auto_compact_threshold_tokens 单阈值,行为不变。
233
+ KSADK_COMPACT_SOFT_LIMIT_PCT_DEFAULT = 50
234
+ KSADK_COMPACT_HARD_LIMIT_PCT_DEFAULT = 85
235
+
236
+
237
+ def _compact_limit_pct_env(name: str, default: int) -> int:
238
+ import os
239
+
240
+ raw = os.environ.get(name)
241
+ if raw is None or str(raw).strip() == "":
242
+ return default
243
+ try:
244
+ return max(1, min(100, int(raw)))
245
+ except ValueError:
246
+ return default
247
+
248
+
249
+ def get_auto_compact_soft_limit_tokens(model_metadata: Mapping[str, Any] | None = None) -> int:
250
+ """soft_limit:proactive 整理触发线(默认 effective window 的 50%)。
251
+
252
+ 百分比可由 env ``KSADK_COMPACT_SOFT_LIMIT_PCT`` 覆盖(1..100)。
253
+ """
254
+ pct = _compact_limit_pct_env(
255
+ "KSADK_COMPACT_SOFT_LIMIT_PCT", KSADK_COMPACT_SOFT_LIMIT_PCT_DEFAULT
256
+ )
257
+ effective = get_effective_context_window_tokens(model_metadata)
258
+ return max(1, math.floor(effective * pct / 100))
259
+
260
+
261
+ def get_auto_compact_hard_limit_tokens(model_metadata: Mapping[str, Any] | None = None) -> int:
262
+ """hard_limit:proactive 强制压缩触发线(≈ 现单阈值算法,reserve+buffer)。
263
+
264
+ 默认复用 ``get_auto_compact_threshold_tokens``(~84%)。可由 env
265
+ ``KSADK_COMPACT_HARD_LIMIT_PCT`` 覆盖为按百分比计算(1..100);未设则用现阈值算法,
266
+ 保证与 PTL/非门控路径的既有 hard 边界一致。
267
+ """
268
+ pct_env = _compact_limit_pct_env("KSADK_COMPACT_HARD_LIMIT_PCT", 0) # 0 = 未设,走现算法
269
+ if pct_env:
270
+ effective = get_effective_context_window_tokens(model_metadata)
271
+ return max(1, math.floor(effective * pct_env / 100))
272
+ return get_auto_compact_threshold_tokens(model_metadata)
273
+
274
+
229
275
  def normalize_model_metadata(raw_model: Mapping[str, Any] | str | None) -> dict[str, Any]:
230
276
  """把模型目录统一规范成稳定 shape。
231
277