agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/METADATA +52 -20
  2. agentengine_sdk_python-0.8.1.dist-info/RECORD +644 -0
  3. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/WHEEL +1 -1
  4. ksadk/a2a/__init__.py +180 -11
  5. ksadk/a2a/bootstrap.py +332 -0
  6. ksadk/a2a/card.py +15 -0
  7. ksadk/a2a/context_store.py +203 -0
  8. ksadk/a2a/control_plane.py +1056 -0
  9. ksadk/a2a/credential.py +99 -0
  10. ksadk/a2a/event_adapter.py +149 -0
  11. ksadk/a2a/executor.py +361 -137
  12. ksadk/a2a/external_transport.py +516 -0
  13. ksadk/a2a/identity.py +304 -0
  14. ksadk/a2a/ids.py +22 -0
  15. ksadk/a2a/langgraph.py +285 -0
  16. ksadk/a2a/resume_store.py +201 -0
  17. ksadk/a2a/routes.py +112 -0
  18. ksadk/a2a/server.py +102 -62
  19. ksadk/a2a/service_env.py +33 -0
  20. ksadk/a2a/space_client.py +1122 -0
  21. ksadk/a2a/task_adapter.py +423 -0
  22. ksadk/a2a/task_event_dispatcher.py +167 -0
  23. ksadk/a2a/task_event_outbox.py +326 -0
  24. ksadk/a2a/task_store.py +206 -0
  25. ksadk/a2a_card.py +101 -0
  26. ksadk/a2ui/__init__.py +27 -0
  27. ksadk/a2ui/core.py +186 -0
  28. ksadk/a2ui/models.py +166 -0
  29. ksadk/a2ui/renderer.py +198 -0
  30. ksadk/agui/__init__.py +9 -0
  31. ksadk/agui/a2ui_projection.py +92 -0
  32. ksadk/agui/agent.py +872 -0
  33. ksadk/agui/config.py +92 -0
  34. ksadk/agui/routes.py +47 -0
  35. ksadk/api/client.py +238 -204
  36. ksadk/api/environment.py +27 -0
  37. ksadk/builders/__init__.py +2 -0
  38. ksadk/builders/base.py +16 -14
  39. ksadk/builders/code_builder.py +375 -270
  40. ksadk/builders/container_builder.py +240 -200
  41. ksadk/builders/framework_requirements.py +31 -12
  42. ksadk/builders/ks3_uploader.py +60 -29
  43. ksadk/builders/managed_runtime_builder.py +173 -0
  44. ksadk/builders/mcp_builder.py +91 -92
  45. ksadk/builders/requirements_utils.py +1 -5
  46. ksadk/cli/__init__.py +97 -171
  47. ksadk/cli/cmd_a2a.py +255 -84
  48. ksadk/cli/cmd_agent.py +19 -5
  49. ksadk/cli/cmd_build.py +158 -29
  50. ksadk/cli/cmd_completion.py +47 -35
  51. ksadk/cli/cmd_config.py +267 -198
  52. ksadk/cli/cmd_create.py +507 -740
  53. ksadk/cli/cmd_dashboard.py +120 -45
  54. ksadk/cli/cmd_deploy.py +135 -59
  55. ksadk/cli/cmd_destroy.py +44 -14
  56. ksadk/cli/cmd_eval.py +386 -0
  57. ksadk/cli/cmd_files.py +63 -24
  58. ksadk/cli/cmd_hermes.py +313 -135
  59. ksadk/cli/cmd_invoke.py +184 -122
  60. ksadk/cli/cmd_launch.py +76 -28
  61. ksadk/cli/cmd_mcp.py +98 -64
  62. ksadk/cli/cmd_model.py +14 -5
  63. ksadk/cli/cmd_openclaw.py +564 -268
  64. ksadk/cli/cmd_replay.py +71 -0
  65. ksadk/cli/cmd_run.py +58 -73
  66. ksadk/cli/cmd_status.py +80 -31
  67. ksadk/cli/cmd_studio.py +110 -0
  68. ksadk/cli/cmd_version.py +20 -13
  69. ksadk/cli/cmd_web.py +95 -18
  70. ksadk/cli/deploy_utils.py +20 -20
  71. ksadk/cli/dry_run.py +7 -4
  72. ksadk/cli/env_options.py +83 -0
  73. ksadk/cli/error_utils.py +37 -12
  74. ksadk/cli/global_options.py +4 -3
  75. ksadk/cli/local_runtime.py +1 -2
  76. ksadk/cli/model_catalog.py +6 -2
  77. ksadk/cli/network_options.py +41 -19
  78. ksadk/cli/resource_common.py +6 -2
  79. ksadk/cli/runtime_bootstrap.py +51 -0
  80. ksadk/cli/storage.py +0 -1
  81. ksadk/cli/ui.py +11 -3
  82. ksadk/cli/workflow_common.py +52 -18
  83. ksadk/codex/__init__.py +12 -0
  84. ksadk/codex/client.py +1042 -0
  85. ksadk/codex/phase.py +143 -0
  86. ksadk/codex/runtime.py +940 -0
  87. ksadk/common/aicp_env.py +0 -1
  88. ksadk/common/auth.py +2 -2
  89. ksadk/common/constants.py +1 -3
  90. ksadk/common/kop_client.py +232 -0
  91. ksadk/common/llm_utils.py +17 -13
  92. ksadk/compat/__init__.py +5 -0
  93. ksadk/compat/adk_compat.py +200 -0
  94. ksadk/compat/copilotkit_a2ui.py +330 -0
  95. ksadk/configs/__init__.py +12 -14
  96. ksadk/configs/env_registry.py +661 -116
  97. ksadk/configs/global_config.py +3 -2
  98. ksadk/configs/settings.py +133 -209
  99. ksadk/conversations/__init__.py +85 -92
  100. ksadk/conversations/attachment_storage.py +16 -11
  101. ksadk/conversations/attachments.py +44 -36
  102. ksadk/conversations/compaction_pipeline.py +12 -12
  103. ksadk/conversations/compaction_prompt.py +9 -5
  104. ksadk/conversations/context.py +221 -6
  105. ksadk/conversations/message_projection.py +438 -51
  106. ksadk/conversations/model_context.py +12 -6
  107. ksadk/conversations/model_options.py +0 -1
  108. ksadk/conversations/normalize.py +20 -16
  109. ksadk/conversations/reasoning_markup.py +1 -1
  110. ksadk/conversations/runtime.py +339 -5255
  111. ksadk/conversations/runtime_compaction.py +333 -0
  112. ksadk/conversations/runtime_constants.py +27 -0
  113. ksadk/conversations/runtime_governance.py +185 -0
  114. ksadk/conversations/runtime_input.py +660 -0
  115. ksadk/conversations/runtime_invocation.py +395 -0
  116. ksadk/conversations/runtime_metadata.py +475 -0
  117. ksadk/conversations/runtime_observability.py +367 -0
  118. ksadk/conversations/runtime_payloads.py +272 -0
  119. ksadk/conversations/runtime_persistence.py +440 -0
  120. ksadk/conversations/runtime_preparation.py +426 -0
  121. ksadk/conversations/runtime_resume.py +836 -0
  122. ksadk/conversations/runtime_stream_events.py +902 -0
  123. ksadk/conversations/runtime_streaming.py +700 -0
  124. ksadk/conversations/semantic_summary.py +17 -5
  125. ksadk/conversations/session_title.py +6 -3
  126. ksadk/deployment/__init__.py +15 -16
  127. ksadk/deployment/agent_access.py +12 -23
  128. ksadk/deployment/base.py +51 -38
  129. ksadk/deployment/managed_runtime.py +33 -0
  130. ksadk/deployment/manager.py +85 -71
  131. ksadk/deployment/providers/serverless.py +379 -210
  132. ksadk/deployment/registry.py +38 -32
  133. ksadk/deployment/state.py +11 -11
  134. ksadk/deployment/ui_config.py +1 -1
  135. ksadk/detection/__init__.py +1 -1
  136. ksadk/detection/detector.py +146 -83
  137. ksadk/detection/mcp_detector.py +9 -6
  138. ksadk/evaluation/__init__.py +84 -0
  139. ksadk/evaluation/a2a_adapter.py +444 -0
  140. ksadk/evaluation/adapters.py +54 -0
  141. ksadk/evaluation/contracts.py +409 -0
  142. ksadk/evaluation/evalset.py +351 -0
  143. ksadk/evaluation/evaluators.py +461 -0
  144. ksadk/evaluation/executor.py +118 -0
  145. ksadk/evaluation/storage.py +68 -0
  146. ksadk/evaluation/target.py +73 -0
  147. ksadk/events/__init__.py +25 -0
  148. ksadk/events/parser.py +191 -0
  149. ksadk/events/replay.py +37 -0
  150. ksadk/events/runtime_event.py +273 -0
  151. ksadk/events/store.py +317 -0
  152. ksadk/harness/__init__.py +35 -0
  153. ksadk/harness/app.py +269 -0
  154. ksadk/harness/config.py +181 -0
  155. ksadk/harness/reasoner.py +105 -0
  156. ksadk/harness/runtime.py +364 -0
  157. ksadk/harness/sandbox.py +141 -0
  158. ksadk/harness/tools.py +222 -0
  159. ksadk/hermes_terminal.py +28 -12
  160. ksadk/identity/resolver.py +15 -9
  161. ksadk/ids.py +32 -0
  162. ksadk/knowledge_base/adk_tool.py +1 -1
  163. ksadk/knowledge_base/client.py +38 -33
  164. ksadk/managed_a2a_card.py +160 -0
  165. ksadk/managed_runtime.py +195 -0
  166. ksadk/markdown.py +5 -2
  167. ksadk/mcp_runtime/__init__.py +9 -6
  168. ksadk/memory/__init__.py +1 -1
  169. ksadk/memory/adk/__init__.py +2 -0
  170. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  171. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  172. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  173. ksadk/memory/adk/backends/sdk_ltm_backend.py +36 -36
  174. ksadk/memory/adk/long_term_memory.py +34 -37
  175. ksadk/memory/adk/resilient_session_service.py +4 -5
  176. ksadk/memory/adk/short_term_memory.py +12 -21
  177. ksadk/memory/adk_tool.py +3 -2
  178. ksadk/memory/backends/base.py +19 -19
  179. ksadk/memory/backends/memory.py +24 -25
  180. ksadk/memory/backends/redis.py +31 -30
  181. ksadk/memory/langchain_tool.py +2 -1
  182. ksadk/memory/manager.py +52 -47
  183. ksadk/memory/service.py +16 -6
  184. ksadk/memory/tool.py +4 -0
  185. ksadk/model_policy.py +15 -7
  186. ksadk/model_proxy/__init__.py +51 -0
  187. ksadk/model_proxy/bootstrap.py +80 -0
  188. ksadk/model_proxy/cache.py +165 -0
  189. ksadk/model_proxy/config.py +66 -0
  190. ksadk/model_proxy/demo_webui.py +115 -0
  191. ksadk/model_proxy/detect.py +145 -0
  192. ksadk/model_proxy/gate.py +68 -0
  193. ksadk/model_proxy/namespace.py +201 -0
  194. ksadk/model_proxy/protocol_proxy.py +22 -0
  195. ksadk/model_proxy/server.py +443 -0
  196. ksadk/model_proxy/transform.py +735 -0
  197. ksadk/openclaw_gateway.py +29 -14
  198. ksadk/runners/adk_runner.py +354 -146
  199. ksadk/runners/base_runner.py +71 -29
  200. ksadk/runners/deepagents_runner.py +0 -1
  201. ksadk/runners/factory.py +18 -5
  202. ksadk/runners/langchain_runner.py +29 -742
  203. ksadk/runners/langgraph_runner.py +417 -97
  204. ksadk/runners/patch_langchain.py +16 -16
  205. ksadk/runners/remote_runner.py +134 -33
  206. ksadk/runners/usage_accumulator.py +1 -0
  207. ksadk/runners/utils/__init__.py +0 -10
  208. ksadk/runners/utils/loader.py +23 -7
  209. ksadk/runtime/__init__.py +67 -0
  210. ksadk/runtime/adapter.py +412 -0
  211. ksadk/runtime/conversation_execution.py +553 -0
  212. ksadk/runtime/executor.py +251 -0
  213. ksadk/runtime/factory.py +156 -0
  214. ksadk/runtime/framework_adapters.py +118 -0
  215. ksadk/runtime/launch.py +48 -0
  216. ksadk/runtime/preprocessing.py +131 -0
  217. ksadk/runtime/runner_adapter.py +1032 -0
  218. ksadk/runtime/runner_loading.py +36 -0
  219. ksadk/runtime_context.py +18 -3
  220. ksadk/runtime_state.py +0 -1
  221. ksadk/sandbox/__init__.py +4 -1
  222. ksadk/sandbox/backends/__init__.py +4 -1
  223. ksadk/sandbox/backends/e2b.py +13 -5
  224. ksadk/sandbox/backends/local_process.py +11 -3
  225. ksadk/sandbox/base.py +10 -15
  226. ksadk/sandbox/factory.py +14 -4
  227. ksadk/sandbox/registry.py +57 -6
  228. ksadk/server/__init__.py +39 -4
  229. ksadk/server/api_models.py +15 -5
  230. ksadk/server/app.py +24 -3928
  231. ksadk/server/composition.py +47 -0
  232. ksadk/server/factory.py +622 -0
  233. ksadk/server/routes/__init__.py +1 -0
  234. ksadk/server/routes/checkpoint_resolution.py +116 -0
  235. ksadk/server/routes/common.py +682 -0
  236. ksadk/server/routes/control.py +331 -0
  237. ksadk/server/routes/dependencies.py +98 -0
  238. ksadk/server/routes/misc.py +425 -0
  239. ksadk/server/routes/models.py +451 -0
  240. ksadk/server/routes/openai_compat.py +229 -0
  241. ksadk/server/routes/projection.py +848 -0
  242. ksadk/server/routes/routers.py +52 -0
  243. ksadk/server/routes/run.py +519 -0
  244. ksadk/server/routes/sessions.py +644 -0
  245. ksadk/server/routes/streaming.py +265 -0
  246. ksadk/server/routes/workspace.py +414 -0
  247. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-CakCqxEN.js} +1 -1
  248. ksadk/server/static/assets/CodeBlock-CynLknyO.js +9 -0
  249. ksadk/server/static/assets/MathMessageMarkdown-3sQdOysS.js +8 -0
  250. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +303 -0
  251. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +1 -0
  252. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-DrgjcKhl.js} +1 -1
  253. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +1 -0
  254. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-BXoVRbQ6.js} +1 -1
  255. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-BnaB3Ywv.js} +1 -1
  256. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-Dw4weZcp.js} +1 -1
  257. ksadk/server/static/assets/channel-Dt3rQTFI.js +1 -0
  258. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-ChjpLK7j.js} +1 -1
  259. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-B9drTgOW.js} +1 -1
  260. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-CK4ROATy.js} +1 -1
  261. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B9KtTTgw.js} +1 -1
  262. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-1O1mki3m.js} +1 -1
  263. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-B_fH2YuH.js} +1 -1
  264. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D6rFLaVV.js} +1 -1
  265. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +1 -0
  266. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +1 -0
  267. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +1 -0
  268. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-ChNs_Mdk.js} +1 -1
  269. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-D0QXg_MQ.js} +1 -1
  270. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-DBDDKwBQ.js} +1 -1
  271. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-BkwDOxmO.js} +1 -1
  272. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Bv8waYvY.js} +1 -1
  273. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-e1VECDdu.js} +1 -1
  274. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-Ds9adfRl.js} +1 -1
  275. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-4N2NMVYg.js} +1 -1
  276. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-B-jNR6Vn.js} +1 -1
  277. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-B5J2uhNk.js} +1 -1
  278. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-B5oS1zcj.js} +1 -1
  279. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BB3-OwTQ.js} +1 -1
  280. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-BIlKoW0k.js} +1 -1
  281. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-BjOdlDjj.js} +1 -1
  282. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-C1sz5Eo3.js} +1 -1
  283. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-CWV4lDr1.js} +1 -1
  284. ksadk/server/static/assets/{dist-D-xOD048.js → dist-CmZHzlwZ.js} +1 -1
  285. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-D6MpCZtz.js} +1 -1
  286. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-DJN_6Y39.js} +1 -1
  287. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-DQU9EWw-.js} +1 -1
  288. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-DWKByxWV.js} +1 -1
  289. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-Dli7qW-B.js} +1 -1
  290. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-DsHPdk3W.js} +1 -1
  291. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-X4TnqwOK.js} +1 -1
  292. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-_pHPTyZ-.js} +1 -1
  293. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-fhOuWds5.js} +1 -1
  294. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-gLnrGsoU.js} +1 -1
  295. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-j6Dxmf_j.js} +1 -1
  296. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-o2OVmKvt.js} +1 -1
  297. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-BPItFKH6.js} +1 -1
  298. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +1 -0
  299. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-BbYB9w5Y.js} +1 -1
  300. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-TQXa0KXv.js} +1 -1
  301. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +1 -0
  302. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-bKblCnpa.js} +1 -1
  303. ksadk/server/static/assets/index-R52pJJvg.js +177 -0
  304. ksadk/server/static/assets/index-jJr3_955.css +2 -0
  305. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +1 -0
  306. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-BGVT7J_i.js} +1 -1
  307. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-K0OOfVna.js} +1 -1
  308. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-8LeOJaZp.js} +1 -1
  309. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-C6uCgZrW.js} +1 -1
  310. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-CYWseY5E.js} +1 -1
  311. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-hdBcYzM8.js} +1 -1
  312. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-BWrDjSZM.js} +2 -2
  313. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-Bjy_2v4_.js} +1 -1
  314. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +1 -0
  315. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +1 -0
  316. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-GmmqNiVH.js} +1 -1
  317. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-BmkRbwCg.js} +1 -1
  318. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +1 -0
  319. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DSWFqL7c.js} +1 -1
  320. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-l6iXmU65.js} +1 -1
  321. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-Cq6UBeQB.js} +1 -1
  322. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-qzTQpg3Y.js} +1 -1
  323. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +1 -0
  324. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-DEz24vV0.js} +1 -1
  325. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +1 -0
  326. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +1 -0
  327. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-CMCixki2.js} +1 -1
  328. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +1 -0
  329. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-CVzB8F9K.js} +1 -1
  330. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-BFBqBLc1.js} +1 -1
  331. ksadk/server/static/index.html +2 -2
  332. ksadk/server/terminal_sessions.py +111 -58
  333. ksadk/sessions/__init__.py +69 -19
  334. ksadk/sessions/base.py +31 -11
  335. ksadk/sessions/continuity.py +2 -3
  336. ksadk/sessions/in_memory.py +46 -2
  337. ksadk/sessions/local_service.py +148 -17
  338. ksadk/sessions/postgres_service.py +143 -25
  339. ksadk/sessions/resilient.py +36 -8
  340. ksadk/skills/models.py +17 -5
  341. ksadk/skills/package_store.py +5 -2
  342. ksadk/skills/runtime/agent.py +20 -5
  343. ksadk/skills/runtime/artifacts.py +1 -5
  344. ksadk/skills/runtime/backends/e2b.py +10 -4
  345. ksadk/skills/runtime/backends/local.py +15 -3
  346. ksadk/skills/runtime/base.py +1 -2
  347. ksadk/skills/runtime/executor.py +10 -3
  348. ksadk/skills/runtime/factory.py +4 -2
  349. ksadk/skills/runtime/loader.py +1 -2
  350. ksadk/skills/runtime/registry.py +15 -10
  351. ksadk/skills/runtime/request.py +3 -1
  352. ksadk/skills/service_client.py +47 -16
  353. ksadk/skills/tool_defs.py +15 -10
  354. ksadk/studio/__init__.py +5 -0
  355. ksadk/studio/agent_avatar_assets.py +120 -0
  356. ksadk/studio/agent_lifecycle.py +51 -0
  357. ksadk/studio/api.py +1046 -0
  358. ksadk/studio/api_catalog_routes.py +324 -0
  359. ksadk/studio/api_contracts.py +177 -0
  360. ksadk/studio/api_helpers.py +132 -0
  361. ksadk/studio/authoring.py +524 -0
  362. ksadk/studio/authoring_coordinator.py +285 -0
  363. ksadk/studio/builder.py +320 -0
  364. ksadk/studio/capabilities.py +351 -0
  365. ksadk/studio/cloud.py +278 -0
  366. ksadk/studio/codex_agent_service.py +583 -0
  367. ksadk/studio/codex_builder.py +324 -0
  368. ksadk/studio/codex_manifest.py +278 -0
  369. ksadk/studio/codex_run.py +352 -0
  370. ksadk/studio/compiler.py +189 -0
  371. ksadk/studio/contracts.py +644 -0
  372. ksadk/studio/errors.py +47 -0
  373. ksadk/studio/evaluation.py +192 -0
  374. ksadk/studio/event_store.py +284 -0
  375. ksadk/studio/framework_run.py +114 -0
  376. ksadk/studio/identifiers.py +33 -0
  377. ksadk/studio/mcp_runtime.py +229 -0
  378. ksadk/studio/model_client.py +543 -0
  379. ksadk/studio/model_profile_service.py +214 -0
  380. ksadk/studio/operations.py +243 -0
  381. ksadk/studio/otel_trace.py +754 -0
  382. ksadk/studio/pagination.py +182 -0
  383. ksadk/studio/python_tool_inspection.py +183 -0
  384. ksadk/studio/repository.py +306 -0
  385. ksadk/studio/resource_catalog.py +1217 -0
  386. ksadk/studio/run_service.py +707 -0
  387. ksadk/studio/runtime_catalog.py +74 -0
  388. ksadk/studio/runtime_source.py +339 -0
  389. ksadk/studio/service.py +1141 -0
  390. ksadk/studio/shared_web.py +994 -0
  391. ksadk/studio/skill_discovery.py +628 -0
  392. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
  393. ksadk/studio/static/assets/index-CaEN0eTR.css +1 -0
  394. ksadk/studio/static/assets/index-DI2eY_NH.js +252 -0
  395. ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
  396. ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
  397. ksadk/studio/static/index.html +15 -0
  398. ksadk/studio/templates.py +630 -0
  399. ksadk/studio/validator.py +246 -0
  400. ksadk/studio/workspace.py +137 -0
  401. ksadk/terminal_exec_policy.py +3 -4
  402. ksadk/tools/gateway.py +101 -15
  403. ksadk/tools/result_budget.py +12 -4
  404. ksadk/toolsets/__init__.py +161 -37
  405. ksadk/toolsets/a2a.py +426 -0
  406. ksadk/toolsets/platform.py +21 -5
  407. ksadk/toolsets/sandbox.py +82 -16
  408. ksadk/toolsets/skills.py +200 -39
  409. ksadk/toolsets/web.py +123 -26
  410. ksadk/toolsets/workspace.py +212 -101
  411. ksadk/tracing/__init__.py +19 -21
  412. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  413. ksadk/tracing/setup.py +135 -506
  414. ksadk/tracing/span_utils.py +0 -41
  415. ksadk/tui/loop.py +78 -30
  416. ksadk/tui/stream_render.py +1 -0
  417. ksadk/ui_config.py +5 -3
  418. ksadk/version.py +1 -1
  419. ksadk_runtime_common/memory_backend/registry.py +56 -56
  420. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  421. ksadk_runtime_common/workspace_files/router.py +8 -2
  422. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  423. ksadk/a2a/card_builder.py +0 -64
  424. ksadk/a2a/client.py +0 -309
  425. ksadk/runners/utils/langfuse.py +0 -230
  426. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  427. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  428. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  429. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  430. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  431. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  432. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  433. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  434. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  435. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  436. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  437. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  438. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  439. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  440. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  441. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  442. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  443. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  444. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  445. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  446. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  447. ksadk/tracing/exporters/langfuse_exporter.py +0 -445
  448. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/entry_points.txt +0 -0
  449. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/licenses/LICENSE +0 -0
  450. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,367 @@
1
+ from __future__ import annotations
2
+
3
+ from contextlib import asynccontextmanager, nullcontext
4
+ from typing import Any, Mapping, Sequence
5
+
6
+ from ksadk.sessions import SessionEvent
7
+
8
+
9
+ def _extract_deferred_tool_names(output: Any) -> list[str]:
10
+ if not isinstance(output, Mapping):
11
+ return []
12
+ raw_names = output.get("deferred_tool_names")
13
+ if not isinstance(raw_names, Sequence) or isinstance(raw_names, (str, bytes, bytearray)):
14
+ return []
15
+ names: list[str] = []
16
+ seen: set[str] = set()
17
+ for item in raw_names:
18
+ name = str(item or "").strip()
19
+ if not name or name in seen:
20
+ continue
21
+ seen.add(name)
22
+ names.append(name)
23
+ return names
24
+
25
+
26
+ def _latest_deferred_tool_names(events: Sequence[SessionEvent]) -> list[str]:
27
+ for event in reversed(events):
28
+ if event.event_type != "run_status":
29
+ continue
30
+ metadata = event.metadata or {}
31
+ if metadata.get("detail") != "deferred_tools_selected":
32
+ continue
33
+ return _extract_deferred_tool_names(metadata)
34
+ return []
35
+
36
+
37
+ def _normalize_usage_payload(usage: Mapping[str, Any] | None) -> dict[str, Any]:
38
+ if not isinstance(usage, Mapping):
39
+ return {}
40
+ normalized: dict[str, Any] = {}
41
+ for key in (
42
+ "input_tokens",
43
+ "output_tokens",
44
+ "total_tokens",
45
+ "prompt_tokens",
46
+ "completion_tokens",
47
+ ):
48
+ value = usage.get(key)
49
+ if value is None:
50
+ continue
51
+ try:
52
+ normalized[key] = int(value)
53
+ except (TypeError, ValueError):
54
+ continue
55
+ for key in ("input_token_details", "output_token_details"):
56
+ value = usage.get(key)
57
+ if isinstance(value, Mapping):
58
+ normalized[key] = dict(value)
59
+ prompt_details = usage.get("prompt_tokens_details")
60
+ if isinstance(prompt_details, Mapping):
61
+ normalized["prompt_tokens_details"] = dict(prompt_details)
62
+ cached_tokens = prompt_details.get("cached_tokens")
63
+ if cached_tokens is not None:
64
+ try:
65
+ normalized.setdefault("input_token_details", {})["cached"] = int(cached_tokens)
66
+ except (TypeError, ValueError):
67
+ pass
68
+ completion_details = usage.get("completion_tokens_details")
69
+ if isinstance(completion_details, Mapping):
70
+ normalized["completion_tokens_details"] = dict(completion_details)
71
+ reasoning_tokens = completion_details.get("reasoning_tokens")
72
+ if reasoning_tokens is not None:
73
+ try:
74
+ normalized.setdefault("output_token_details", {})["reasoning"] = int(
75
+ reasoning_tokens
76
+ )
77
+ except (TypeError, ValueError):
78
+ pass
79
+ return normalized
80
+
81
+
82
+ def _usage_from_metadata(metadata: Mapping[str, Any] | None) -> dict[str, Any]:
83
+ if not isinstance(metadata, Mapping):
84
+ return {}
85
+ return _normalize_usage_payload(metadata.get("usage"))
86
+
87
+
88
+ def _responses_usage_payload(usage: Mapping[str, Any] | None) -> dict[str, Any] | None:
89
+ normalized = _normalize_usage_payload(usage)
90
+ if not normalized:
91
+ return None
92
+ input_tokens = normalized.get("input_tokens", normalized.get("prompt_tokens", 0))
93
+ output_tokens = normalized.get("output_tokens", normalized.get("completion_tokens", 0))
94
+ total_tokens = normalized.get("total_tokens", input_tokens + output_tokens)
95
+ payload = {
96
+ "input_tokens": input_tokens,
97
+ "input_tokens_details": {"cached_tokens": 0},
98
+ "output_tokens": output_tokens,
99
+ "output_tokens_details": {"reasoning_tokens": 0},
100
+ "total_tokens": total_tokens,
101
+ }
102
+ input_details = normalized.get("input_token_details")
103
+ if isinstance(input_details, Mapping):
104
+ cached_tokens = input_details.get(
105
+ "cached_tokens",
106
+ input_details.get("cached", input_details.get("cache_read", 0)),
107
+ )
108
+ payload["input_tokens_details"]["cached_tokens"] = int(cached_tokens or 0)
109
+ output_details = normalized.get("output_token_details")
110
+ if isinstance(output_details, Mapping):
111
+ reasoning_tokens = output_details.get(
112
+ "reasoning_tokens",
113
+ output_details.get("reasoning", 0),
114
+ )
115
+ payload["output_tokens_details"]["reasoning_tokens"] = int(reasoning_tokens or 0)
116
+ return payload
117
+
118
+
119
+ def _chat_usage_payload(usage: Mapping[str, Any] | None) -> dict[str, Any] | None:
120
+ normalized = _normalize_usage_payload(usage)
121
+ if not normalized:
122
+ return None
123
+ prompt_tokens = normalized.get("prompt_tokens", normalized.get("input_tokens", 0))
124
+ completion_tokens = normalized.get("completion_tokens", normalized.get("output_tokens", 0))
125
+ total_tokens = normalized.get("total_tokens", prompt_tokens + completion_tokens)
126
+ payload = {
127
+ "prompt_tokens": prompt_tokens,
128
+ "completion_tokens": completion_tokens,
129
+ "total_tokens": total_tokens,
130
+ }
131
+ prompt_details = normalized.get("prompt_tokens_details")
132
+ if isinstance(prompt_details, Mapping):
133
+ payload["prompt_tokens_details"] = dict(prompt_details)
134
+ input_token_details = normalized.get("input_token_details")
135
+ if isinstance(input_token_details, Mapping) and input_token_details:
136
+ prompt_details = dict(payload.get("prompt_tokens_details") or {})
137
+ cached_tokens = input_token_details.get("cached")
138
+ if cached_tokens is not None:
139
+ try:
140
+ prompt_details["cached_tokens"] = int(cached_tokens)
141
+ except (TypeError, ValueError):
142
+ pass
143
+ if prompt_details:
144
+ payload["prompt_tokens_details"] = prompt_details
145
+ completion_details = normalized.get("completion_tokens_details")
146
+ if isinstance(completion_details, Mapping):
147
+ payload["completion_tokens_details"] = dict(completion_details)
148
+ output_token_details = normalized.get("output_token_details")
149
+ if isinstance(output_token_details, Mapping) and output_token_details:
150
+ completion_details = dict(payload.get("completion_tokens_details") or {})
151
+ reasoning_tokens = output_token_details.get("reasoning")
152
+ if reasoning_tokens is not None:
153
+ try:
154
+ completion_details["reasoning_tokens"] = int(reasoning_tokens)
155
+ except (TypeError, ValueError):
156
+ pass
157
+ if completion_details:
158
+ payload["completion_tokens_details"] = completion_details
159
+ return payload
160
+
161
+
162
+ def _get_conversation_tracer() -> Any | None:
163
+ try:
164
+ from opentelemetry import trace
165
+
166
+ return trace.get_tracer("ksadk.conversations")
167
+ except Exception:
168
+ return None
169
+
170
+
171
+ def _current_span_feedback_metadata() -> dict[str, str]:
172
+ try:
173
+ from opentelemetry import trace
174
+
175
+ span = trace.get_current_span()
176
+ except Exception:
177
+ return {}
178
+ return _span_feedback_metadata(span)
179
+
180
+
181
+ def _span_feedback_metadata(span: Any | None) -> dict[str, str]:
182
+ if span is None:
183
+ return {}
184
+ try:
185
+ context = span.get_span_context()
186
+ except Exception:
187
+ return {}
188
+ if not getattr(context, "is_valid", False):
189
+ return {}
190
+ return {
191
+ "trace_id": format(context.trace_id, "032x"),
192
+ "root_span_id": format(context.span_id, "016x"),
193
+ }
194
+
195
+
196
+ def _get_current_span() -> Any | None:
197
+ try:
198
+ from opentelemetry import trace
199
+
200
+ return trace.get_current_span()
201
+ except Exception:
202
+ return None
203
+
204
+
205
+ def _span_current_context(span: Any | None):
206
+ if span is None:
207
+ return nullcontext()
208
+ try:
209
+ from opentelemetry.trace import use_span
210
+
211
+ return use_span(
212
+ span, end_on_exit=False, record_exception=False, set_status_on_exception=False
213
+ )
214
+ except Exception:
215
+ return nullcontext()
216
+
217
+
218
+ @asynccontextmanager
219
+ async def _conversation_span_scope(name: str, *, manual_end: bool = False):
220
+ tracer = _get_conversation_tracer()
221
+ if tracer is None:
222
+ yield None
223
+ return
224
+ if manual_end:
225
+ span = tracer.start_span(name)
226
+ try:
227
+ yield span
228
+ finally:
229
+ try:
230
+ span.end()
231
+ except Exception:
232
+ pass
233
+ return
234
+ span = tracer.start_span(name)
235
+ try:
236
+ yield span
237
+ finally:
238
+ try:
239
+ span.end()
240
+ except Exception:
241
+ pass
242
+
243
+
244
+ def _set_span_attribute(span: Any | None, key: str, value: Any) -> None:
245
+ if span is None:
246
+ return
247
+ if value is None:
248
+ return
249
+ if isinstance(value, str):
250
+ value = value.strip()
251
+ if not value:
252
+ return
253
+ try:
254
+ span.set_attribute(key, value)
255
+ except Exception:
256
+ return
257
+
258
+
259
+ def _set_conversation_input_attributes(span: Any | None, input_text: str | None) -> None:
260
+ text = " ".join(str(input_text or "").split())
261
+ if not text:
262
+ return
263
+ for key in (
264
+ "langfuse.trace.input",
265
+ "langfuse.observation.input",
266
+ "input.value",
267
+ "gen_ai.prompt",
268
+ ):
269
+ _set_span_attribute(span, key, text)
270
+
271
+
272
+ def _set_conversation_output_attributes(span: Any | None, output_text: str | None) -> None:
273
+ text = " ".join(str(output_text or "").split())
274
+ if not text:
275
+ return
276
+ for key in (
277
+ "langfuse.trace.output",
278
+ "langfuse.observation.output",
279
+ "output.value",
280
+ "gen_ai.completion",
281
+ ):
282
+ _set_span_attribute(span, key, text)
283
+
284
+
285
+ def _set_conversation_usage_attributes(
286
+ span: Any | None,
287
+ usage: Mapping[str, Any] | None,
288
+ ) -> None:
289
+ normalized = _normalize_usage_payload(usage)
290
+ if not normalized:
291
+ return
292
+
293
+ def _usage_int(value: Any) -> int:
294
+ try:
295
+ return int(value or 0)
296
+ except (TypeError, ValueError):
297
+ return 0
298
+
299
+ input_tokens = _usage_int(normalized.get("input_tokens"))
300
+ output_tokens = _usage_int(normalized.get("output_tokens"))
301
+ total_tokens = _usage_int(normalized.get("total_tokens") or (input_tokens + output_tokens))
302
+ input_details = normalized.get("input_token_details")
303
+ output_details = normalized.get("output_token_details")
304
+ cache_read_tokens = 0
305
+ reasoning_tokens = 0
306
+ if isinstance(input_details, Mapping):
307
+ cache_read_tokens = _usage_int(
308
+ input_details.get("cache_read")
309
+ or input_details.get("cached")
310
+ or input_details.get("cached_tokens")
311
+ )
312
+ if isinstance(output_details, Mapping):
313
+ reasoning_tokens = _usage_int(
314
+ output_details.get("reasoning") or output_details.get("reasoning_tokens")
315
+ )
316
+
317
+ attributes = {
318
+ "gen_ai.usage.input_tokens": input_tokens,
319
+ "gen_ai.usage.output_tokens": output_tokens,
320
+ "gen_ai.usage.total_tokens": total_tokens,
321
+ "llm.usage.prompt_tokens": input_tokens,
322
+ "llm.usage.completion_tokens": output_tokens,
323
+ "llm.usage.total_tokens": total_tokens,
324
+ }
325
+ if cache_read_tokens:
326
+ attributes["gen_ai.usage.cache_read.input_tokens"] = cache_read_tokens
327
+ attributes["llm.usage.cache_read.input_tokens"] = cache_read_tokens
328
+ if reasoning_tokens:
329
+ attributes["gen_ai.usage.reasoning.output_tokens"] = reasoning_tokens
330
+ attributes["llm.usage.reasoning_tokens"] = reasoning_tokens
331
+
332
+ for key, value in attributes.items():
333
+ if value:
334
+ _set_span_attribute(span, key, value)
335
+
336
+
337
+ def _set_conversation_span_attributes(
338
+ span: Any,
339
+ *,
340
+ agent_id: str,
341
+ user_id: str,
342
+ session_id: str,
343
+ invocation_id: str,
344
+ runner_name: str,
345
+ model: str | None,
346
+ response_id: str | None = None,
347
+ ) -> None:
348
+ if span is None:
349
+ return
350
+ try:
351
+ span.set_attribute("ksadk.agent_id", agent_id)
352
+ span.set_attribute("ksadk.user_id", user_id)
353
+ span.set_attribute("ksadk.session_id", session_id)
354
+ span.set_attribute("ksadk.invocation_id", invocation_id)
355
+ span.set_attribute("ksadk.runner", runner_name)
356
+ span.set_attribute("langfuse.trace.name", runner_name)
357
+ span.set_attribute("langfuse.session.id", session_id)
358
+ span.set_attribute("session.id", session_id)
359
+ span.set_attribute("langfuse.user.id", user_id)
360
+ span.set_attribute("user.id", user_id)
361
+ if model:
362
+ span.set_attribute("llm.model_name", model)
363
+ span.set_attribute("gen_ai.request.model", model)
364
+ if response_id:
365
+ span.set_attribute("ksadk.response_id", response_id)
366
+ except Exception:
367
+ return
@@ -0,0 +1,272 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import time
5
+ import uuid
6
+ from dataclasses import dataclass, field
7
+ from typing import Any, Mapping, Optional, Sequence
8
+
9
+ from ksadk.conversations.run_kinds import (
10
+ RUN_MODE_FOREGROUND,
11
+ RUN_TRIGGER_NEW_RUN,
12
+ )
13
+ from ksadk.conversations.runtime_observability import (
14
+ _chat_usage_payload,
15
+ _responses_usage_payload,
16
+ _usage_from_metadata,
17
+ )
18
+ from ksadk.sessions import SessionEvent
19
+
20
+
21
+ @dataclass
22
+ class PreparedConversationTurn:
23
+ """一次 turn 编排后的标准输入。
24
+
25
+ 这个对象把“会话归属”“用户最新输入”“投影后的上下文 history”
26
+ 和“附件/parts”等运行时所需信息收拢到一起,避免不同 endpoint
27
+ 各自重新拼装。
28
+ """
29
+
30
+ session_id: str
31
+ invocation_id: str
32
+ user_input: str
33
+ user_display_input: str
34
+ history: list[dict[str, str]]
35
+ input_content: list[dict[str, Any]]
36
+ input_messages: list[dict[str, Any]]
37
+ user_parts: list[dict[str, Any]]
38
+ attachments: list[dict[str, Any]]
39
+ attachment_results: list[dict[str, Any]]
40
+ current_attachments: list[dict[str, Any]]
41
+ current_attachment_results: list[dict[str, Any]]
42
+ has_current_files: bool
43
+ model_metadata: dict[str, Any] = field(default_factory=dict)
44
+ model_options: dict[str, Any] = field(default_factory=dict)
45
+ instructions: str = ""
46
+ request_metadata: dict[str, Any] = field(default_factory=dict)
47
+ compaction_triggered: bool = False
48
+ compaction_trigger: str | None = None
49
+ compacted_until_seq_id: int | None = None
50
+ resume_input: dict[str, Any] | None = None
51
+ # 双维度 run 标识:run_mode=怎么跑(background/foreground),
52
+ # run_trigger=怎么开始(new_run/checkpoint_resume/approval_resume)
53
+ run_mode: str = RUN_MODE_FOREGROUND
54
+ run_trigger: str = RUN_TRIGGER_NEW_RUN
55
+ request_history: list[dict[str, str]] = field(default_factory=list)
56
+ request_responses_history: list[dict[str, Any]] = field(default_factory=list)
57
+ responses_history: list[dict[str, Any]] = field(default_factory=list)
58
+
59
+
60
+ @dataclass
61
+ class CompactionPlan:
62
+ """一次 compaction 规划结果。
63
+
64
+ 预览阶段和真正落 checkpoint 阶段都复用这份规划,避免 `/run_sse`
65
+ 与 conversation runtime 各自写一套“是否需要压缩”的条件判断。
66
+ """
67
+
68
+ should_compact: bool
69
+ groups_to_compact: list[list[SessionEvent]]
70
+ total_chars: int
71
+ total_estimated_tokens: int
72
+ group_count: int
73
+ tail_groups: int
74
+ auto_compact_threshold_tokens: int | None = None
75
+ auto_compact_threshold_percentage: int | None = None
76
+ compacted_until_seq_id: int | None = None
77
+ pinned_group_indexes: list[int] = field(default_factory=list)
78
+ pinned_state: dict[str, Any] = field(default_factory=dict)
79
+
80
+
81
+ def build_responses_payload(
82
+ *,
83
+ output_text: str,
84
+ model: Optional[str],
85
+ session_id: str,
86
+ response_id: str | None = None,
87
+ created_at: int | None = None,
88
+ status: str = "completed",
89
+ metadata: Mapping[str, Any] | None = None,
90
+ usage: Mapping[str, Any] | None = None,
91
+ incomplete_details: Mapping[str, Any] | None = None,
92
+ error: Mapping[str, Any] | None = None,
93
+ output_items: Sequence[Mapping[str, Any]] | None = None,
94
+ ) -> dict[str, Any]:
95
+ response_id = response_id or f"resp_{uuid.uuid4().hex}"
96
+ created_at = created_at or int(time.time())
97
+ message_id = f"msg_{uuid.uuid4().hex[:12]}"
98
+ output_item_status = "completed" if status == "completed" else status
99
+ message_item = {
100
+ "id": message_id,
101
+ "type": "message",
102
+ "status": output_item_status,
103
+ "role": "assistant",
104
+ "content": [{"type": "output_text", "text": output_text}],
105
+ }
106
+ normalized_output_items = [
107
+ dict(item) for item in list(output_items or []) if isinstance(item, Mapping)
108
+ ]
109
+ if normalized_output_items:
110
+ output = normalized_output_items
111
+ if not any(str(item.get("type") or "") == "message" for item in output):
112
+ output = [message_item, *output]
113
+ else:
114
+ output = [message_item]
115
+ usage_payload = _responses_usage_payload(usage or _usage_from_metadata(metadata))
116
+ return {
117
+ "id": response_id,
118
+ "object": "response",
119
+ "created_at": created_at,
120
+ "status": status,
121
+ "error": dict(error) if isinstance(error, Mapping) else None,
122
+ "incomplete_details": (
123
+ dict(incomplete_details) if isinstance(incomplete_details, Mapping) else None
124
+ ),
125
+ "instructions": None,
126
+ "metadata": dict(metadata or {}),
127
+ "model": model or "agent",
128
+ "parallel_tool_calls": True,
129
+ "temperature": None,
130
+ "top_p": None,
131
+ "tools": [],
132
+ "output": output,
133
+ "output_text": output_text,
134
+ "usage": usage_payload,
135
+ "session_id": session_id,
136
+ }
137
+
138
+
139
+ def extract_responses_resume_input(input_payload: Any) -> dict[str, Any] | None:
140
+ """Extract OpenAI Responses approval resume input without exposing runner details."""
141
+ if isinstance(input_payload, Mapping):
142
+ candidates = [input_payload]
143
+ elif isinstance(input_payload, Sequence) and not isinstance(
144
+ input_payload, (str, bytes, bytearray)
145
+ ):
146
+ candidates = [item for item in input_payload if isinstance(item, Mapping)]
147
+ else:
148
+ return None
149
+
150
+ for item in candidates:
151
+ item_type = str(item.get("type") or "").strip()
152
+ if item_type == "agentengine.resume_checkpoint":
153
+ checkpoint_resume: dict[str, Any] = {"type": "agentengine.resume_checkpoint"}
154
+ for key in (
155
+ "run_id",
156
+ "checkpoint_id",
157
+ "resume_attempt_id",
158
+ "framework",
159
+ "framework_ref",
160
+ ):
161
+ if key in item:
162
+ checkpoint_resume[key] = item.get(key)
163
+ return checkpoint_resume
164
+
165
+ if item_type == "mcp_approval_response":
166
+ approval_resume: dict[str, Any] = {"type": "mcp_approval_response"}
167
+ if item.get("id"):
168
+ approval_resume["id"] = str(item.get("id"))
169
+ approval_request_id = item.get("approval_request_id")
170
+ if approval_request_id:
171
+ approval_resume["approval_request_id"] = str(approval_request_id)
172
+ if "approve" in item:
173
+ approval_resume["approve"] = item.get("approve")
174
+ elif "approved" in item:
175
+ approval_resume["approve"] = item.get("approved")
176
+ if item.get("reason") is not None:
177
+ approval_resume["reason"] = str(item.get("reason") or "")
178
+ return approval_resume
179
+
180
+ if item_type == "function_call_output":
181
+ call_id = item.get("call_id")
182
+ if not call_id:
183
+ continue
184
+ function_resume: dict[str, Any] = {
185
+ "type": "function_call_output",
186
+ "call_id": str(call_id),
187
+ "output": item.get("output", ""),
188
+ }
189
+ if item.get("id"):
190
+ function_resume["id"] = str(item.get("id"))
191
+ return function_resume
192
+
193
+ if item_type in {"ksadk_resume", "ksadk.approval_response"}:
194
+ ksadk_resume: dict[str, Any] = {"type": "ksadk_resume"}
195
+ interrupt_id = (
196
+ item.get("interrupt_id") or item.get("approval_request_id") or item.get("id")
197
+ )
198
+ if interrupt_id:
199
+ ksadk_resume["interrupt_id"] = str(interrupt_id)
200
+ if "value" in item:
201
+ ksadk_resume["value"] = item.get("value")
202
+ elif "resume" in item:
203
+ ksadk_resume["value"] = item.get("resume")
204
+ else:
205
+ ksadk_resume["value"] = {
206
+ key: value
207
+ for key, value in item.items()
208
+ if key not in {"type", "interrupt_id", "approval_request_id", "id"}
209
+ }
210
+ return ksadk_resume
211
+
212
+ return None
213
+
214
+
215
+ def build_chat_completions_payload(
216
+ *,
217
+ output_text: str,
218
+ model: Optional[str],
219
+ session_id: str,
220
+ metadata: Mapping[str, Any] | None = None,
221
+ ) -> dict[str, Any]:
222
+ usage = _chat_usage_payload(_usage_from_metadata(metadata))
223
+ payload = {
224
+ "id": f"chatcmpl-{uuid.uuid4()}",
225
+ "object": "chat.completion",
226
+ "created": int(time.time()),
227
+ "model": model or "agent",
228
+ "choices": [
229
+ {
230
+ "index": 0,
231
+ "message": {"role": "assistant", "content": output_text},
232
+ "finish_reason": "stop",
233
+ }
234
+ ],
235
+ "usage": usage,
236
+ "session_id": session_id,
237
+ }
238
+ if isinstance(metadata, Mapping) and metadata:
239
+ payload["metadata"] = dict(metadata)
240
+ return payload
241
+
242
+
243
+ def build_compaction_sse_event(
244
+ *,
245
+ phase: str,
246
+ trigger: str,
247
+ compacted_until_seq_id: int | None = None,
248
+ total_chars: int | None = None,
249
+ total_estimated_tokens: int | None = None,
250
+ group_count: int | None = None,
251
+ threshold_percentage: int | None = None,
252
+ ) -> str:
253
+ """统一生成 compaction 相关 SSE,方便不同入口保持同一语义。"""
254
+
255
+ payload: dict[str, Any] = {
256
+ "phase": phase,
257
+ "trigger": trigger,
258
+ "timestamp": int(time.time() * 1000),
259
+ }
260
+ if compacted_until_seq_id is not None:
261
+ payload["compacted_until_seq_id"] = compacted_until_seq_id
262
+ if total_chars is not None:
263
+ payload["total_chars"] = total_chars
264
+ if total_estimated_tokens is not None:
265
+ payload["total_estimated_tokens"] = total_estimated_tokens
266
+ if group_count is not None:
267
+ payload["group_count"] = group_count
268
+ if threshold_percentage is not None:
269
+ payload["threshold_percentage"] = threshold_percentage
270
+ return (
271
+ f"event: response.compaction.{phase}\ndata: {json.dumps(payload, ensure_ascii=False)}\n\n"
272
+ )