agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.0__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 (371) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
  2. agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
  3. ksadk/a2a/__init__.py +178 -11
  4. ksadk/a2a/bootstrap.py +334 -0
  5. ksadk/a2a/card.py +120 -0
  6. ksadk/a2a/context_store.py +203 -0
  7. ksadk/a2a/control_plane.py +818 -0
  8. ksadk/a2a/credential.py +99 -0
  9. ksadk/a2a/event_adapter.py +149 -0
  10. ksadk/a2a/executor.py +406 -89
  11. ksadk/a2a/external_transport.py +516 -0
  12. ksadk/a2a/identity.py +304 -0
  13. ksadk/a2a/ids.py +22 -0
  14. ksadk/a2a/langgraph.py +285 -0
  15. ksadk/a2a/resume_store.py +201 -0
  16. ksadk/a2a/routes.py +105 -0
  17. ksadk/a2a/server.py +107 -60
  18. ksadk/a2a/space_client.py +1101 -0
  19. ksadk/a2a/task_adapter.py +423 -0
  20. ksadk/a2a/task_event_dispatcher.py +167 -0
  21. ksadk/a2a/task_event_outbox.py +326 -0
  22. ksadk/a2a/task_store.py +206 -0
  23. ksadk/a2ui/__init__.py +27 -0
  24. ksadk/a2ui/core.py +186 -0
  25. ksadk/a2ui/models.py +166 -0
  26. ksadk/a2ui/renderer.py +198 -0
  27. ksadk/agui/__init__.py +9 -0
  28. ksadk/agui/a2ui_projection.py +92 -0
  29. ksadk/agui/agent.py +857 -0
  30. ksadk/agui/config.py +86 -0
  31. ksadk/agui/routes.py +55 -0
  32. ksadk/api/client.py +233 -191
  33. ksadk/builders/__init__.py +2 -0
  34. ksadk/builders/base.py +16 -14
  35. ksadk/builders/code_builder.py +318 -236
  36. ksadk/builders/container_builder.py +187 -167
  37. ksadk/builders/framework_requirements.py +29 -11
  38. ksadk/builders/ks3_uploader.py +58 -27
  39. ksadk/builders/managed_runtime_builder.py +145 -0
  40. ksadk/builders/mcp_builder.py +91 -92
  41. ksadk/builders/requirements_utils.py +1 -5
  42. ksadk/cli/__init__.py +89 -171
  43. ksadk/cli/cmd_a2a.py +254 -70
  44. ksadk/cli/cmd_agent.py +19 -5
  45. ksadk/cli/cmd_build.py +158 -29
  46. ksadk/cli/cmd_completion.py +47 -35
  47. ksadk/cli/cmd_config.py +267 -198
  48. ksadk/cli/cmd_create.py +500 -720
  49. ksadk/cli/cmd_dashboard.py +120 -45
  50. ksadk/cli/cmd_deploy.py +117 -58
  51. ksadk/cli/cmd_destroy.py +44 -14
  52. ksadk/cli/cmd_files.py +63 -24
  53. ksadk/cli/cmd_hermes.py +168 -89
  54. ksadk/cli/cmd_invoke.py +184 -122
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +98 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +483 -227
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +33 -10
  61. ksadk/cli/cmd_status.py +80 -31
  62. ksadk/cli/cmd_version.py +20 -13
  63. ksadk/cli/cmd_web.py +89 -13
  64. ksadk/cli/deploy_utils.py +20 -20
  65. ksadk/cli/dry_run.py +5 -3
  66. ksadk/cli/error_utils.py +37 -12
  67. ksadk/cli/global_options.py +1 -2
  68. ksadk/cli/local_runtime.py +1 -2
  69. ksadk/cli/model_catalog.py +6 -2
  70. ksadk/cli/network_options.py +34 -14
  71. ksadk/cli/resource_common.py +6 -2
  72. ksadk/cli/storage.py +0 -1
  73. ksadk/cli/ui.py +5 -3
  74. ksadk/cli/workflow_common.py +51 -17
  75. ksadk/codex/__init__.py +12 -0
  76. ksadk/codex/client.py +408 -0
  77. ksadk/codex/phase.py +143 -0
  78. ksadk/codex/runtime.py +449 -0
  79. ksadk/common/aicp_env.py +0 -1
  80. ksadk/common/auth.py +2 -2
  81. ksadk/common/constants.py +1 -3
  82. ksadk/common/llm_utils.py +17 -13
  83. ksadk/compat/__init__.py +5 -0
  84. ksadk/compat/adk_compat.py +200 -0
  85. ksadk/compat/copilotkit_a2ui.py +330 -0
  86. ksadk/configs/__init__.py +12 -12
  87. ksadk/configs/env_registry.py +500 -100
  88. ksadk/configs/global_config.py +2 -1
  89. ksadk/configs/settings.py +151 -124
  90. ksadk/conversations/__init__.py +7 -5
  91. ksadk/conversations/attachment_storage.py +16 -11
  92. ksadk/conversations/attachments.py +44 -36
  93. ksadk/conversations/compaction_pipeline.py +12 -12
  94. ksadk/conversations/compaction_prompt.py +9 -5
  95. ksadk/conversations/context.py +221 -6
  96. ksadk/conversations/message_projection.py +438 -51
  97. ksadk/conversations/model_context.py +12 -6
  98. ksadk/conversations/model_options.py +0 -1
  99. ksadk/conversations/normalize.py +20 -16
  100. ksadk/conversations/reasoning_markup.py +1 -1
  101. ksadk/conversations/runtime.py +339 -5255
  102. ksadk/conversations/runtime_compaction.py +333 -0
  103. ksadk/conversations/runtime_constants.py +27 -0
  104. ksadk/conversations/runtime_governance.py +185 -0
  105. ksadk/conversations/runtime_input.py +652 -0
  106. ksadk/conversations/runtime_invocation.py +395 -0
  107. ksadk/conversations/runtime_metadata.py +475 -0
  108. ksadk/conversations/runtime_observability.py +355 -0
  109. ksadk/conversations/runtime_payloads.py +272 -0
  110. ksadk/conversations/runtime_persistence.py +440 -0
  111. ksadk/conversations/runtime_preparation.py +418 -0
  112. ksadk/conversations/runtime_resume.py +816 -0
  113. ksadk/conversations/runtime_stream_events.py +902 -0
  114. ksadk/conversations/runtime_streaming.py +547 -0
  115. ksadk/conversations/semantic_summary.py +17 -5
  116. ksadk/conversations/session_title.py +6 -3
  117. ksadk/deployment/__init__.py +15 -16
  118. ksadk/deployment/agent_access.py +12 -23
  119. ksadk/deployment/base.py +51 -38
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +309 -202
  122. ksadk/deployment/registry.py +38 -32
  123. ksadk/deployment/state.py +11 -11
  124. ksadk/deployment/ui_config.py +1 -1
  125. ksadk/detection/__init__.py +1 -1
  126. ksadk/detection/detector.py +146 -83
  127. ksadk/detection/mcp_detector.py +9 -6
  128. ksadk/events/__init__.py +25 -0
  129. ksadk/events/parser.py +191 -0
  130. ksadk/events/replay.py +37 -0
  131. ksadk/events/runtime_event.py +264 -0
  132. ksadk/events/store.py +317 -0
  133. ksadk/harness/__init__.py +34 -0
  134. ksadk/harness/app.py +278 -0
  135. ksadk/harness/config.py +181 -0
  136. ksadk/harness/reasoner.py +105 -0
  137. ksadk/harness/runner.py +211 -0
  138. ksadk/harness/sandbox.py +141 -0
  139. ksadk/harness/tools.py +222 -0
  140. ksadk/hermes_terminal.py +23 -12
  141. ksadk/identity/resolver.py +15 -9
  142. ksadk/ids.py +32 -0
  143. ksadk/knowledge_base/adk_tool.py +1 -1
  144. ksadk/knowledge_base/client.py +23 -29
  145. ksadk/managed_runtime.py +188 -0
  146. ksadk/markdown.py +5 -2
  147. ksadk/mcp_runtime/__init__.py +9 -6
  148. ksadk/memory/__init__.py +1 -1
  149. ksadk/memory/adk/__init__.py +2 -0
  150. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  151. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  152. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  153. ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
  154. ksadk/memory/adk/long_term_memory.py +31 -35
  155. ksadk/memory/adk/resilient_session_service.py +4 -5
  156. ksadk/memory/adk/short_term_memory.py +12 -21
  157. ksadk/memory/adk_tool.py +3 -2
  158. ksadk/memory/backends/base.py +19 -19
  159. ksadk/memory/backends/memory.py +24 -25
  160. ksadk/memory/backends/redis.py +31 -30
  161. ksadk/memory/langchain_tool.py +2 -1
  162. ksadk/memory/manager.py +52 -47
  163. ksadk/memory/service.py +10 -8
  164. ksadk/model_policy.py +15 -7
  165. ksadk/model_proxy/__init__.py +51 -0
  166. ksadk/model_proxy/bootstrap.py +80 -0
  167. ksadk/model_proxy/cache.py +165 -0
  168. ksadk/model_proxy/config.py +45 -0
  169. ksadk/model_proxy/demo_webui.py +115 -0
  170. ksadk/model_proxy/detect.py +145 -0
  171. ksadk/model_proxy/gate.py +68 -0
  172. ksadk/model_proxy/namespace.py +173 -0
  173. ksadk/model_proxy/protocol_proxy.py +22 -0
  174. ksadk/model_proxy/server.py +300 -0
  175. ksadk/model_proxy/transform.py +691 -0
  176. ksadk/openclaw_gateway.py +29 -14
  177. ksadk/runners/adk_runner.py +345 -120
  178. ksadk/runners/base_runner.py +46 -29
  179. ksadk/runners/codex_runner.py +132 -0
  180. ksadk/runners/deepagents_runner.py +0 -1
  181. ksadk/runners/factory.py +17 -5
  182. ksadk/runners/langchain_runner.py +29 -742
  183. ksadk/runners/langgraph_runner.py +352 -90
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +134 -33
  186. ksadk/runners/usage_accumulator.py +1 -0
  187. ksadk/runners/utils/langfuse.py +3 -3
  188. ksadk/runners/utils/loader.py +7 -7
  189. ksadk/runtime/__init__.py +41 -0
  190. ksadk/runtime/adapter.py +345 -0
  191. ksadk/runtime/framework_adapters.py +124 -0
  192. ksadk/runtime/preprocessing.py +118 -0
  193. ksadk/runtime/runner_adapter.py +873 -0
  194. ksadk/runtime_context.py +18 -3
  195. ksadk/runtime_state.py +0 -1
  196. ksadk/sandbox/__init__.py +4 -1
  197. ksadk/sandbox/backends/__init__.py +4 -1
  198. ksadk/sandbox/backends/e2b.py +13 -5
  199. ksadk/sandbox/backends/local_process.py +11 -3
  200. ksadk/sandbox/base.py +10 -15
  201. ksadk/sandbox/factory.py +14 -4
  202. ksadk/sandbox/registry.py +57 -6
  203. ksadk/server/api_models.py +15 -5
  204. ksadk/server/app.py +455 -3885
  205. ksadk/server/composition.py +21 -0
  206. ksadk/server/factory.py +624 -0
  207. ksadk/server/routes/__init__.py +1 -0
  208. ksadk/server/routes/checkpoint_resolution.py +116 -0
  209. ksadk/server/routes/common.py +713 -0
  210. ksadk/server/routes/control.py +327 -0
  211. ksadk/server/routes/dependencies.py +98 -0
  212. ksadk/server/routes/misc.py +448 -0
  213. ksadk/server/routes/models.py +443 -0
  214. ksadk/server/routes/openai_compat.py +207 -0
  215. ksadk/server/routes/projection.py +795 -0
  216. ksadk/server/routes/routers.py +52 -0
  217. ksadk/server/routes/run.py +726 -0
  218. ksadk/server/routes/sessions.py +649 -0
  219. ksadk/server/routes/streaming.py +223 -0
  220. ksadk/server/routes/workspace.py +381 -0
  221. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
  222. ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
  224. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
  226. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-CFKwSk_B.js} +1 -1
  227. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
  228. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
  239. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
  240. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
  241. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
  242. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
  272. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
  273. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
  275. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
  276. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
  277. ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
  278. ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
  279. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
  280. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
  288. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
  289. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
  290. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
  292. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
  293. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
  297. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
  298. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
  299. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
  300. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
  301. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
  302. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
  303. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
  305. ksadk/server/static/index.html +2 -2
  306. ksadk/server/terminal_sessions.py +111 -58
  307. ksadk/sessions/__init__.py +69 -19
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +2 -3
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +143 -25
  313. ksadk/sessions/resilient.py +36 -8
  314. ksadk/skills/models.py +17 -5
  315. ksadk/skills/package_store.py +5 -2
  316. ksadk/skills/runtime/agent.py +20 -5
  317. ksadk/skills/runtime/artifacts.py +1 -5
  318. ksadk/skills/runtime/backends/e2b.py +10 -4
  319. ksadk/skills/runtime/backends/local.py +15 -3
  320. ksadk/skills/runtime/base.py +1 -2
  321. ksadk/skills/runtime/executor.py +10 -3
  322. ksadk/skills/runtime/factory.py +4 -2
  323. ksadk/skills/runtime/loader.py +1 -2
  324. ksadk/skills/runtime/registry.py +15 -10
  325. ksadk/skills/runtime/request.py +3 -1
  326. ksadk/skills/service_client.py +38 -17
  327. ksadk/skills/tool_defs.py +15 -10
  328. ksadk/terminal_exec_policy.py +3 -4
  329. ksadk/tools/gateway.py +92 -15
  330. ksadk/tools/result_budget.py +12 -4
  331. ksadk/toolsets/__init__.py +134 -36
  332. ksadk/toolsets/platform.py +21 -5
  333. ksadk/toolsets/sandbox.py +82 -16
  334. ksadk/toolsets/skills.py +200 -39
  335. ksadk/toolsets/web.py +123 -26
  336. ksadk/toolsets/workspace.py +212 -101
  337. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  338. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  339. ksadk/tracing/setup.py +69 -53
  340. ksadk/tracing/span_utils.py +5 -2
  341. ksadk/tui/loop.py +78 -30
  342. ksadk/tui/stream_render.py +1 -0
  343. ksadk/ui_config.py +5 -3
  344. ksadk/version.py +1 -1
  345. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  346. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  347. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  348. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  349. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  350. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  351. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  352. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  353. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  354. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  355. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  356. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  357. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  358. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  359. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  360. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  361. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  362. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  364. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  365. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  366. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  367. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  368. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  369. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  370. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  371. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,333 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+ from typing import Any, Callable, Dict, Mapping, Optional, Sequence
5
+
6
+ from ksadk.conversations.compaction_pipeline import build_working_set_metadata, run_pipeline
7
+ from ksadk.conversations.context import (
8
+ TRANSCRIPT_EVENT_TYPES,
9
+ canonical_event_type,
10
+ compacted_until_seq_id,
11
+ extract_event_text,
12
+ group_events_by_api_round,
13
+ )
14
+ from ksadk.conversations.model_context import (
15
+ estimate_text_tokens,
16
+ get_auto_compact_threshold_percentage,
17
+ get_auto_compact_threshold_tokens,
18
+ )
19
+ from ksadk.conversations.runtime_constants import (
20
+ AUTOCOMPACT_KEEP_TAIL_GROUPS,
21
+ PTL_RETRY_KEEP_TAIL_GROUPS,
22
+ )
23
+ from ksadk.conversations.runtime_metadata import (
24
+ _build_pending_user_event,
25
+ _latest_user_turn,
26
+ _normalized_conversation_messages,
27
+ _resolve_effective_attachment_context,
28
+ _resolve_model_metadata,
29
+ _resolve_runtime_model_metadata,
30
+ _transcript_event_type,
31
+ )
32
+ from ksadk.conversations.runtime_payloads import CompactionPlan
33
+ from ksadk.conversations.runtime_persistence import append_context_checkpoint_event
34
+ from ksadk.conversations.semantic_summary import (
35
+ extract_pinned_state,
36
+ find_pinned_group_indexes,
37
+ summarize_compaction,
38
+ )
39
+ from ksadk.sessions import SessionEvent, resolve_session_service
40
+
41
+
42
+ def _plan_compaction(
43
+ events: Sequence[SessionEvent],
44
+ *,
45
+ model: Optional[str] = None,
46
+ model_metadata: Mapping[str, Any] | None = None,
47
+ pending_events: Sequence[SessionEvent] | None = None,
48
+ force: bool = False,
49
+ keep_tail_groups: int | None = None,
50
+ ) -> CompactionPlan:
51
+ """根据当前 transcript 计算是否需要做 checkpoint compaction。"""
52
+
53
+ compacted_until = compacted_until_seq_id(list(events))
54
+ transcript_events = [
55
+ event
56
+ for event in events
57
+ if event.seq_id > compacted_until
58
+ and _transcript_event_type(event) in TRANSCRIPT_EVENT_TYPES
59
+ and _transcript_event_type(event) != "context_checkpoint"
60
+ ]
61
+ pending_transcript_events = [
62
+ event
63
+ for event in (pending_events or [])
64
+ if _transcript_event_type(event) in TRANSCRIPT_EVENT_TYPES
65
+ and _transcript_event_type(event) != "context_checkpoint"
66
+ ]
67
+ combined_events = [*transcript_events, *pending_transcript_events]
68
+ groups = group_events_by_api_round(combined_events)
69
+ pinned_group_indexes = sorted(find_pinned_group_indexes(groups))
70
+ pinned_state = extract_pinned_state(groups)
71
+ tail_groups = (
72
+ keep_tail_groups
73
+ if keep_tail_groups is not None
74
+ else (PTL_RETRY_KEEP_TAIL_GROUPS if force else AUTOCOMPACT_KEEP_TAIL_GROUPS)
75
+ )
76
+ resolved_model_metadata = _resolve_model_metadata(model, model_metadata=model_metadata)
77
+ auto_compact_threshold_tokens = get_auto_compact_threshold_tokens(resolved_model_metadata)
78
+ auto_compact_threshold_percentage = get_auto_compact_threshold_percentage(
79
+ resolved_model_metadata
80
+ )
81
+ total_chars = sum(len(extract_event_text(event)) for event in combined_events)
82
+ total_estimated_tokens = sum(
83
+ estimate_text_tokens(extract_event_text(event)) for event in combined_events
84
+ )
85
+ if not force and (
86
+ len(groups) <= tail_groups or total_estimated_tokens <= auto_compact_threshold_tokens
87
+ ):
88
+ return CompactionPlan(
89
+ should_compact=False,
90
+ groups_to_compact=[],
91
+ total_chars=total_chars,
92
+ total_estimated_tokens=total_estimated_tokens,
93
+ group_count=len(groups),
94
+ tail_groups=tail_groups,
95
+ auto_compact_threshold_tokens=auto_compact_threshold_tokens,
96
+ auto_compact_threshold_percentage=auto_compact_threshold_percentage,
97
+ pinned_group_indexes=pinned_group_indexes,
98
+ pinned_state=pinned_state,
99
+ )
100
+
101
+ compactable_indexes = [
102
+ index for index in range(len(groups)) if index not in pinned_group_indexes
103
+ ]
104
+ retained_tail_indexes = set(compactable_indexes[-tail_groups:]) if tail_groups > 0 else set()
105
+ preserved_indexes = set(pinned_group_indexes) | retained_tail_indexes
106
+ first_preserved_index = min(preserved_indexes) if preserved_indexes else len(groups)
107
+ groups_to_compact = [
108
+ group
109
+ for index, group in enumerate(groups[:first_preserved_index])
110
+ if index not in pinned_group_indexes
111
+ ]
112
+ if not groups_to_compact:
113
+ return CompactionPlan(
114
+ should_compact=False,
115
+ groups_to_compact=[],
116
+ total_chars=total_chars,
117
+ total_estimated_tokens=total_estimated_tokens,
118
+ group_count=len(groups),
119
+ tail_groups=tail_groups,
120
+ auto_compact_threshold_tokens=auto_compact_threshold_tokens,
121
+ auto_compact_threshold_percentage=auto_compact_threshold_percentage,
122
+ pinned_group_indexes=pinned_group_indexes,
123
+ pinned_state=pinned_state,
124
+ )
125
+
126
+ compacted_until_seq_id_value = groups_to_compact[-1][-1].seq_id or None
127
+ return CompactionPlan(
128
+ should_compact=True,
129
+ groups_to_compact=groups_to_compact,
130
+ total_chars=total_chars,
131
+ total_estimated_tokens=total_estimated_tokens,
132
+ group_count=len(groups),
133
+ tail_groups=tail_groups,
134
+ auto_compact_threshold_tokens=auto_compact_threshold_tokens,
135
+ auto_compact_threshold_percentage=auto_compact_threshold_percentage,
136
+ compacted_until_seq_id=compacted_until_seq_id_value,
137
+ pinned_group_indexes=pinned_group_indexes,
138
+ pinned_state=pinned_state,
139
+ )
140
+
141
+
142
+ async def preview_auto_compaction(
143
+ *,
144
+ agent_id: str,
145
+ user_id: str,
146
+ session_id: Optional[str],
147
+ messages: Sequence[Dict[str, Any]],
148
+ model: Optional[str] = None,
149
+ model_metadata: Mapping[str, Any] | None = None,
150
+ session_service_provider: Callable[[], Any] | None = None,
151
+ ) -> CompactionPlan:
152
+ """在真正写入 turn 之前预估是否会触发自动压缩。
153
+
154
+ 这个预览只用于给 UI 提前打一条“正在压缩上下文”的流式提示,不会修改会话。
155
+ """
156
+
157
+ if not session_id:
158
+ return CompactionPlan(
159
+ should_compact=False,
160
+ groups_to_compact=[],
161
+ total_chars=0,
162
+ total_estimated_tokens=0,
163
+ group_count=0,
164
+ tail_groups=AUTOCOMPACT_KEEP_TAIL_GROUPS,
165
+ )
166
+
167
+ provider = session_service_provider or resolve_session_service
168
+ service = provider()
169
+ existing_session = await service.get_session(session_id)
170
+ if not existing_session:
171
+ return CompactionPlan(
172
+ should_compact=False,
173
+ groups_to_compact=[],
174
+ total_chars=0,
175
+ total_estimated_tokens=0,
176
+ group_count=0,
177
+ tail_groups=AUTOCOMPACT_KEEP_TAIL_GROUPS,
178
+ )
179
+
180
+ resolved_user_id = existing_session.user_id or user_id
181
+ if existing_session.agent_id != agent_id or resolved_user_id != user_id:
182
+ return CompactionPlan(
183
+ should_compact=False,
184
+ groups_to_compact=[],
185
+ total_chars=0,
186
+ total_estimated_tokens=0,
187
+ group_count=0,
188
+ tail_groups=AUTOCOMPACT_KEEP_TAIL_GROUPS,
189
+ )
190
+
191
+ normalized_messages = _normalized_conversation_messages(messages)
192
+ resolved_model_metadata = await _resolve_runtime_model_metadata(
193
+ model,
194
+ model_metadata=model_metadata,
195
+ )
196
+ user_input, user_display_input, _, _, attachments, attachment_results = _latest_user_turn(
197
+ normalized_messages
198
+ )
199
+ effective_attachments, effective_attachment_results = _resolve_effective_attachment_context(
200
+ normalized_messages=normalized_messages,
201
+ session=existing_session,
202
+ )
203
+ pending_event = _build_pending_user_event(
204
+ session_id=session_id,
205
+ invocation_id=f"preview-{uuid.uuid4()}",
206
+ user_input=user_input,
207
+ user_display_input=user_display_input or user_input,
208
+ attachments=effective_attachments,
209
+ attachment_results=effective_attachment_results,
210
+ )
211
+ events = await service.get_events(session_id)
212
+ return _plan_compaction(
213
+ events,
214
+ model=model,
215
+ model_metadata=resolved_model_metadata,
216
+ pending_events=[pending_event],
217
+ )
218
+
219
+
220
+ async def compact_conversation_history(
221
+ *,
222
+ session_id: str,
223
+ author: str,
224
+ invocation_id: Optional[str] = None,
225
+ model: Optional[str] = None,
226
+ model_metadata: Mapping[str, Any] | None = None,
227
+ force: bool = False,
228
+ trigger: str = "auto",
229
+ keep_tail_groups: Optional[int] = None,
230
+ session_service_provider: Callable[[], Any] | None = None,
231
+ ) -> SessionEvent | None:
232
+ """把旧轮次折叠为 checkpoint。
233
+
234
+ 这是本地版的 compaction:先按 API round 分组,再保留尾部若干轮,把更早
235
+ 的部分压成 append-only summary 事件。force=True 时用于 PTL 恢复。
236
+ """
237
+ provider = session_service_provider or resolve_session_service
238
+ service = provider()
239
+ events = await service.get_events(session_id)
240
+ plan = _plan_compaction(
241
+ events,
242
+ model=model,
243
+ model_metadata=model_metadata,
244
+ force=force,
245
+ keep_tail_groups=keep_tail_groups,
246
+ )
247
+ if not plan.should_compact:
248
+ return None
249
+
250
+ previous_summary = ""
251
+ latest_checkpoint = next(
252
+ (
253
+ event
254
+ for event in reversed(events)
255
+ if canonical_event_type(event.event_type) == "context_checkpoint"
256
+ ),
257
+ None,
258
+ )
259
+ if latest_checkpoint:
260
+ previous_summary = extract_event_text(latest_checkpoint)
261
+
262
+ compacted_until_seq_id_value = int(plan.compacted_until_seq_id or 0)
263
+ resolved_model_metadata = _resolve_model_metadata(model, model_metadata=model_metadata)
264
+ threshold_tokens = get_auto_compact_threshold_tokens(resolved_model_metadata)
265
+
266
+ # P0.5 分层 compaction pipeline:L2 Snip + L3 Microcompact(零 LLM 成本确定性裁剪),
267
+ # 只作用于送 summarizer 的 candidate 投影,绝不删 append-only transcript。
268
+ # 详见 ksadk/conversations/compaction_pipeline.py。
269
+ pipeline_result = run_pipeline(
270
+ plan.groups_to_compact,
271
+ threshold_tokens=threshold_tokens,
272
+ pinned_state=plan.pinned_state,
273
+ previous_summary=previous_summary,
274
+ )
275
+ candidate_groups = pipeline_result["candidate_groups"]
276
+
277
+ summary_result = await summarize_compaction(
278
+ groups_to_compact=candidate_groups,
279
+ previous_summary=previous_summary,
280
+ pinned_state=plan.pinned_state,
281
+ model_metadata=resolved_model_metadata,
282
+ model=model,
283
+ )
284
+
285
+ # L5 working set 恢复(保守版):只记 metadata,不读文件内容。
286
+ working_set = build_working_set_metadata(pinned_state=plan.pinned_state)
287
+
288
+ return await append_context_checkpoint_event(
289
+ session_id=session_id,
290
+ author=author,
291
+ compacted_until_seq_id=compacted_until_seq_id_value,
292
+ summary_text=summary_result.summary_text,
293
+ trigger=trigger,
294
+ invocation_id=invocation_id,
295
+ metadata={
296
+ "head_seq_id": plan.groups_to_compact[0][0].seq_id,
297
+ "tail_seq_id": plan.groups_to_compact[-1][-1].seq_id,
298
+ "invocation_ids": [
299
+ event.invocation_id
300
+ for group in plan.groups_to_compact
301
+ for event in group
302
+ if event.invocation_id
303
+ ],
304
+ "summary_strategy": summary_result.summary_strategy,
305
+ "summary_version": summary_result.summary_version,
306
+ "summary_model": summary_result.summary_model,
307
+ "summary_usage": summary_result.summary_usage,
308
+ "fallback_reason": summary_result.fallback_reason,
309
+ # P0.5 pipeline 审计字段(原始 transcript 未改,这里只记投影统计)。
310
+ "pipeline_stages": pipeline_result["pipeline_stages"],
311
+ "tokens_before": pipeline_result["tokens_before"],
312
+ "tokens_after": pipeline_result["tokens_after"],
313
+ "snip_stats": {
314
+ "removed_redundant_tool_results": pipeline_result[
315
+ "snip_stats"
316
+ ].removed_redundant_tool_results,
317
+ "snip_released_tokens": pipeline_result["snip_released_tokens"],
318
+ "covered_seq_range": list(pipeline_result["snip_stats"].covered_seq_range or []),
319
+ },
320
+ "microcompact_stats": (
321
+ {
322
+ "compacted_groups": pipeline_result["microcompact_stats"].compacted_groups,
323
+ "tokens_before": pipeline_result["microcompact_stats"].tokens_before,
324
+ "tokens_after": pipeline_result["microcompact_stats"].tokens_after,
325
+ "preserved_receipts": pipeline_result["microcompact_stats"].preserved_receipts,
326
+ }
327
+ if pipeline_result["microcompact_stats"] is not None
328
+ else None
329
+ ),
330
+ "working_set": working_set,
331
+ },
332
+ session_service_provider=provider,
333
+ )
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from typing import Any
5
+
6
+ AUTOCOMPACT_KEEP_TAIL_GROUPS = 4
7
+ PTL_RETRY_KEEP_TAIL_GROUPS = 2
8
+ PROMPT_TOO_LONG_MARKERS = (
9
+ "prompt-too-long",
10
+ "prompt too long",
11
+ "maximum context length",
12
+ "context length",
13
+ "context_length_exceeded",
14
+ "413",
15
+ )
16
+ SESSION_SUMMARY_MAX_CHARS = 160
17
+ ATTACHMENT_CONTEXT_STATE_KEY = "__ksadk_attachment_context__"
18
+ EVENT_SCAN_PAGE_SIZE = 500
19
+ # Durable stream snapshots make a detached run recoverable after a browser refresh.
20
+ # Keep them bounded: the first text delta is persisted immediately, then at most one
21
+ # update per interval unless a substantial amount of text has arrived.
22
+ ASSISTANT_STREAM_SNAPSHOT_INTERVAL_SECONDS = 0.5
23
+ ASSISTANT_STREAM_SNAPSHOT_MIN_NEW_CHARS = 256
24
+
25
+ logger = logging.getLogger("ksadk.conversations.runtime")
26
+ _MODEL_CATALOG_CACHE_TTL_SECONDS = 60.0
27
+ _MODEL_CATALOG_CACHE: dict[tuple[str, str], tuple[float, list[dict[str, Any]]]] = {}
@@ -0,0 +1,185 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from dataclasses import dataclass
6
+ from typing import Any, Mapping
7
+
8
+ from ksadk.sessions import SessionEvent
9
+
10
+
11
+ @dataclass
12
+ class RuntimeGovernanceState:
13
+ max_turns: int = 0
14
+ max_tool_calls: int = 0
15
+ max_consecutive_tool_failures: int = 0
16
+ max_consecutive_approval_denials: int = 0
17
+ max_consecutive_compact_failures: int = 0
18
+ turn_count: int = 0
19
+ tool_calls: int = 0
20
+ consecutive_tool_failures: int = 0
21
+ consecutive_approval_denials: int = 0
22
+ consecutive_compact_failures: int = 0
23
+
24
+
25
+ class RuntimeCircuitOpen(RuntimeError):
26
+ def __init__(self, reason: str, message: str, *, metadata: Mapping[str, Any] | None = None):
27
+ super().__init__(message)
28
+ self.reason = reason
29
+ self.metadata = dict(metadata or {})
30
+
31
+
32
+ def _int_env(name: str, default: int = 0) -> int:
33
+ raw = os.environ.get(name)
34
+ if raw is None:
35
+ return int(default)
36
+ try:
37
+ return max(0, int(raw))
38
+ except ValueError:
39
+ return int(default)
40
+
41
+
42
+ def _runtime_governance_from_env() -> RuntimeGovernanceState:
43
+ return RuntimeGovernanceState(
44
+ max_turns=_int_env("KSADK_MAX_TURNS", 0),
45
+ max_tool_calls=_int_env("KSADK_MAX_TOOL_CALLS", 0),
46
+ max_consecutive_tool_failures=_int_env("KSADK_MAX_CONSECUTIVE_TOOL_FAILURES", 0),
47
+ max_consecutive_approval_denials=_int_env("KSADK_MAX_CONSECUTIVE_APPROVAL_DENIALS", 0),
48
+ max_consecutive_compact_failures=_int_env("KSADK_MAX_CONSECUTIVE_COMPACT_FAILURES", 0),
49
+ )
50
+
51
+
52
+ def _governance_error(
53
+ reason: str, message: str, state: RuntimeGovernanceState
54
+ ) -> RuntimeCircuitOpen:
55
+ return RuntimeCircuitOpen(
56
+ reason,
57
+ message,
58
+ metadata={
59
+ "reason": reason,
60
+ "max_turns": state.max_turns,
61
+ "max_tool_calls": state.max_tool_calls,
62
+ "max_consecutive_tool_failures": state.max_consecutive_tool_failures,
63
+ "max_consecutive_approval_denials": state.max_consecutive_approval_denials,
64
+ "max_consecutive_compact_failures": state.max_consecutive_compact_failures,
65
+ "turn_count": state.turn_count,
66
+ "tool_calls": state.tool_calls,
67
+ "consecutive_tool_failures": state.consecutive_tool_failures,
68
+ "consecutive_approval_denials": state.consecutive_approval_denials,
69
+ "consecutive_compact_failures": state.consecutive_compact_failures,
70
+ },
71
+ )
72
+
73
+
74
+ def _governance_record_turn_start(state: RuntimeGovernanceState) -> None:
75
+ state.turn_count += 1
76
+ if state.max_turns and state.turn_count > state.max_turns:
77
+ raise _governance_error("max_turns_exceeded", "runtime max_turns limit exceeded", state)
78
+
79
+
80
+ def _governance_record_tool_call(state: RuntimeGovernanceState) -> None:
81
+ state.tool_calls += 1
82
+ if state.max_tool_calls and state.tool_calls > state.max_tool_calls:
83
+ raise _governance_error(
84
+ "max_tool_calls_exceeded", "runtime max_tool_calls limit exceeded", state
85
+ )
86
+
87
+
88
+ def _governance_record_tool_result(state: RuntimeGovernanceState, output: Any) -> None:
89
+ failed = isinstance(output, Mapping) and output.get("ok") is False
90
+ state.consecutive_tool_failures = state.consecutive_tool_failures + 1 if failed else 0
91
+ if (
92
+ state.max_consecutive_tool_failures
93
+ and state.consecutive_tool_failures >= state.max_consecutive_tool_failures
94
+ ):
95
+ raise _governance_error(
96
+ "consecutive_tool_failures", "runtime consecutive tool failure limit exceeded", state
97
+ )
98
+
99
+
100
+ def _governance_record_approval_response(
101
+ state: RuntimeGovernanceState, approval: Mapping[str, Any]
102
+ ) -> None:
103
+ approved = bool(approval.get("approved") or approval.get("approve"))
104
+ state.consecutive_approval_denials = 0 if approved else state.consecutive_approval_denials + 1
105
+ if (
106
+ state.max_consecutive_approval_denials
107
+ and state.consecutive_approval_denials >= state.max_consecutive_approval_denials
108
+ ):
109
+ raise _governance_error(
110
+ "consecutive_approval_denials",
111
+ "runtime consecutive approval denial limit exceeded",
112
+ state,
113
+ )
114
+
115
+
116
+ def _governance_record_compact_failure(state: RuntimeGovernanceState) -> None:
117
+ state.consecutive_compact_failures += 1
118
+ if (
119
+ state.max_consecutive_compact_failures
120
+ and state.consecutive_compact_failures >= state.max_consecutive_compact_failures
121
+ ):
122
+ raise _governance_error(
123
+ "consecutive_compact_failures",
124
+ "runtime consecutive compact failure limit exceeded",
125
+ state,
126
+ )
127
+
128
+
129
+ def _governance_record_compact_success(state: RuntimeGovernanceState) -> None:
130
+ state.consecutive_compact_failures = 0
131
+
132
+
133
+ async def _compact_conversation_history_with_governance(
134
+ governance: RuntimeGovernanceState | None,
135
+ **kwargs: Any,
136
+ ) -> SessionEvent | None:
137
+ from ksadk.conversations.runtime_compaction import compact_conversation_history
138
+
139
+ try:
140
+ checkpoint = await compact_conversation_history(**kwargs)
141
+ except Exception:
142
+ if governance is not None:
143
+ _governance_record_compact_failure(governance)
144
+ raise
145
+ if checkpoint is not None and governance is not None:
146
+ _governance_record_compact_success(governance)
147
+ return checkpoint
148
+
149
+
150
+ def _tool_observability_metadata(
151
+ tool_name: str, output: Any, *, duration_ms: int | None = None
152
+ ) -> dict[str, Any]:
153
+ output_text = (
154
+ json.dumps(output, ensure_ascii=False, sort_keys=True)
155
+ if isinstance(output, Mapping)
156
+ else str(output)
157
+ )
158
+ metadata: dict[str, Any] = {
159
+ "tool_name": tool_name,
160
+ "duration_ms": int(duration_ms or 0),
161
+ "output_chars": len(output_text),
162
+ "truncated": False,
163
+ "persisted": False,
164
+ "exit_code": None,
165
+ "error_type": "",
166
+ }
167
+ if isinstance(output, Mapping):
168
+ persisted = output.get("persisted") or output.get("persisted_outputs")
169
+ metadata.update(
170
+ {
171
+ "truncated": any(
172
+ bool(output.get(key))
173
+ for key in (
174
+ "truncated",
175
+ "stdout_truncated",
176
+ "stderr_truncated",
177
+ "results_truncated",
178
+ )
179
+ ),
180
+ "persisted": bool(persisted),
181
+ "exit_code": output.get("exit_code"),
182
+ "error_type": str(output.get("error_type") or ""),
183
+ }
184
+ )
185
+ return metadata