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
@@ -2,8 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from dataclasses import dataclass, replace
6
5
  import json
6
+ from dataclasses import dataclass, replace
7
7
  from pathlib import Path
8
8
  from typing import Any, Sequence
9
9
 
@@ -16,9 +16,9 @@ from ksadk.cli.ui import (
16
16
  print_info,
17
17
  print_kv,
18
18
  print_next_steps,
19
+ print_rule,
19
20
  print_title,
20
21
  print_warn,
21
- print_rule,
22
22
  )
23
23
 
24
24
 
@@ -55,9 +55,19 @@ def build_workflow_local_plan(
55
55
  normalized_artifact_type = (artifact_type or "").strip().lower()
56
56
  normalized_reference = str(artifact_reference or artifact_plan.reference or "")
57
57
  source = artifact_plan.source or ("built" if artifact_plan.should_build else "external")
58
- will_build = artifact_plan.will_build if artifact_plan.will_build is not None else artifact_plan.should_build
59
- should_publish = artifact_plan.should_publish if artifact_plan.should_publish is not None else artifact_plan.should_build
60
- will_publish = artifact_plan.will_publish if artifact_plan.will_publish is not None else will_build
58
+ will_build = (
59
+ artifact_plan.will_build
60
+ if artifact_plan.will_build is not None
61
+ else artifact_plan.should_build
62
+ )
63
+ should_publish = (
64
+ artifact_plan.should_publish
65
+ if artifact_plan.should_publish is not None
66
+ else artifact_plan.should_build
67
+ )
68
+ will_publish = (
69
+ artifact_plan.will_publish if artifact_plan.will_publish is not None else will_build
70
+ )
61
71
  build_reason = _plan_step_reason(
62
72
  source=source,
63
73
  explicit_ref_option=artifact_plan.explicit_ref_option,
@@ -114,13 +124,20 @@ def build_workflow_local_plan(
114
124
  }
115
125
 
116
126
 
117
- def should_build_artifact(*, target: str, artifact_type: str | None, ks3_path: str | None, image: str | None) -> bool:
127
+ def should_build_artifact(
128
+ *, target: str, artifact_type: str | None, ks3_path: str | None, image: str | None
129
+ ) -> bool:
118
130
  """Whether deploy/launch should build artifacts locally."""
119
131
  if target != "serverless":
120
132
  return False
121
133
  mode = (artifact_type or "Code").strip().lower()
122
134
  if mode == "code":
123
135
  return not bool(ks3_path)
136
+ # ManagedRuntime is a declarative server-side manifest. ``ksadk build``
137
+ # remains available for inspection/offline locking, but ``deploy`` neither
138
+ # uploads nor needs a local artifact.
139
+ if mode == "managedruntime":
140
+ return False
124
141
  if mode == "container":
125
142
  return not bool(image)
126
143
  return False
@@ -136,6 +153,7 @@ def plan_artifact_build(
136
153
  repackage: bool = False,
137
154
  ) -> ArtifactBuildPlan:
138
155
  """Plan artifact build behavior and metadata cleanup under cache options."""
156
+ mode = (artifact_type or "Code").strip().lower()
139
157
  should_build = should_build_artifact(
140
158
  target=target,
141
159
  artifact_type=artifact_type,
@@ -144,7 +162,6 @@ def plan_artifact_build(
144
162
  )
145
163
  explicit_ref_option = None
146
164
  if target == "serverless" and not should_build:
147
- mode = (artifact_type or "Code").strip().lower()
148
165
  if mode == "code" and ks3_path:
149
166
  explicit_ref_option = "--ks3-path"
150
167
  elif mode == "container" and image:
@@ -154,8 +171,8 @@ def plan_artifact_build(
154
171
  should_clear_metadata=bool((no_cache or repackage) and should_build),
155
172
  explicit_ref_option=explicit_ref_option,
156
173
  will_build=should_build,
157
- should_publish=bool(target == "serverless" and should_build),
158
- will_publish=bool(target == "serverless" and should_build),
174
+ should_publish=bool(target == "serverless" and should_build and mode != "managedruntime"),
175
+ will_publish=bool(target == "serverless" and should_build and mode != "managedruntime"),
159
176
  source="external" if explicit_ref_option else ("built" if should_build else None),
160
177
  )
161
178
 
@@ -176,7 +193,9 @@ def _predict_artifact_reference(
176
193
 
177
194
  normalized_artifact_type = (artifact_type or "Code").strip().lower()
178
195
  normalized_deploy_name = (deploy_name or "agent").strip() or "agent"
179
- normalized_region = "cn-beijing-6" if str(region or "").strip() == "pre-online" else str(region or "").strip()
196
+ normalized_region = (
197
+ "cn-beijing-6" if str(region or "").strip() == "pre-online" else str(region or "").strip()
198
+ )
180
199
 
181
200
  if normalized_artifact_type == "code":
182
201
  bucket = (ks3_bucket or "").strip()
@@ -184,7 +203,11 @@ def _predict_artifact_reference(
184
203
  bucket = f"agentengine-{account_id}-{normalized_region}"
185
204
  if not bucket:
186
205
  bucket = "<ks3-bucket>"
187
- return f"ks3://{bucket}/agents/{normalized_deploy_name}/code_<dry-run>.zip"
206
+ artifact_label = "runtime" if normalized_artifact_type == "managedruntime" else "code"
207
+ return f"ks3://{bucket}/agents/{normalized_deploy_name}/{artifact_label}_<dry-run>.zip"
208
+
209
+ if normalized_artifact_type == "managedruntime":
210
+ return "inline:managed-runtime"
188
211
 
189
212
  if normalized_artifact_type == "container":
190
213
  normalized_registry = (registry or "").strip().rstrip("/")
@@ -212,6 +235,7 @@ def resolve_artifact_build_plan(
212
235
  """Resolve workflow artifact behavior after package metadata is available."""
213
236
  normalized_explicit = str(explicit_reference or "").strip()
214
237
  normalized_cached = str(cached_reference or "").strip()
238
+ is_managed_runtime = (artifact_type or "").strip().lower() == "managedruntime"
215
239
 
216
240
  if normalized_explicit:
217
241
  return replace(
@@ -241,7 +265,7 @@ def resolve_artifact_build_plan(
241
265
  return replace(
242
266
  plan,
243
267
  will_build=False,
244
- should_publish=bool(target == "serverless"),
268
+ should_publish=bool(target == "serverless" and not is_managed_runtime),
245
269
  will_publish=False,
246
270
  source="planned_build",
247
271
  reference=_predict_artifact_reference(
@@ -260,8 +284,8 @@ def resolve_artifact_build_plan(
260
284
  return replace(
261
285
  plan,
262
286
  will_build=True,
263
- should_publish=bool(target == "serverless"),
264
- will_publish=bool(target == "serverless"),
287
+ should_publish=bool(target == "serverless" and not is_managed_runtime),
288
+ will_publish=bool(target == "serverless" and not is_managed_runtime),
265
289
  source="built",
266
290
  reference=plan.reference,
267
291
  reference_is_predicted=False,
@@ -339,7 +363,11 @@ def _request_header_summary(headers: Any) -> str:
339
363
  def _summarize_plan_steps(steps: Sequence[dict[str, Any]]) -> tuple[str, str, str]:
340
364
  executed = [str(step.get("name") or "-") for step in steps if step.get("will_run")]
341
365
  planned = [str(step.get("name") or "-") for step in steps if step.get("planned")]
342
- skipped = [str(step.get("name") or "-") for step in steps if not step.get("will_run") and not step.get("planned")]
366
+ skipped = [
367
+ str(step.get("name") or "-")
368
+ for step in steps
369
+ if not step.get("will_run") and not step.get("planned")
370
+ ]
343
371
  return (
344
372
  ", ".join(executed) or "-",
345
373
  ", ".join(planned) or "-",
@@ -516,8 +544,14 @@ def render_workflow_dry_run(
516
544
 
517
545
  print_rule("本地计划")
518
546
  print_kv("制品类型", str(plan.get("artifact_type") or "-"))
519
- print_kv("需要本地构建", "是" if artifact.get("should_local_build", artifact.get("should_build")) else "否")
520
- print_kv("会执行本地构建", "是" if artifact.get("will_local_build", artifact.get("will_build")) else "否")
547
+ print_kv(
548
+ "需要本地构建",
549
+ "是" if artifact.get("should_local_build", artifact.get("should_build")) else "否",
550
+ )
551
+ print_kv(
552
+ "会执行本地构建",
553
+ "是" if artifact.get("will_local_build", artifact.get("will_build")) else "否",
554
+ )
521
555
  print_kv("需要发布制品", "是" if artifact.get("should_publish") else "否")
522
556
  print_kv("会执行制品发布", "是" if artifact.get("will_publish") else "否")
523
557
  if artifact.get("source"):
@@ -0,0 +1,12 @@
1
+ """CodexRuntime — 非 ADK 体系 runtime (goal-09)。"""
2
+
3
+ from ksadk.codex.client import AsyncCodexClient, CodexClient
4
+ from ksadk.codex.phase import CodexPhaseTracker
5
+ from ksadk.codex.runtime import CodexRuntime
6
+
7
+ __all__ = [
8
+ "AsyncCodexClient",
9
+ "CodexClient",
10
+ "CodexPhaseTracker",
11
+ "CodexRuntime",
12
+ ]
ksadk/codex/client.py ADDED
@@ -0,0 +1,408 @@
1
+ """CodexRuntime 的 codex 后端接口 (goal-09)。
2
+
3
+ 重托管模式:CodexRuntime 对执行生命周期负责,不把 cancel/进程管理薄委托给上层。
4
+ ``CodexClient`` 是 codex 后端(thread/turn 生命周期)的最小接口,方法集对齐 OpenAI
5
+ 官方 ``openai-codex`` SDK 的**真实**线程模型(``thread_start`` / ``thread.turn`` /
6
+ ``handle.stream`` / ``handle.interrupt`` / ``thread_resume``):
7
+
8
+ - 生产实现 ``AsyncCodexClient``:基于 ``AsyncCodex``。**lazy import**,缺依赖时显式
9
+ 报"请安装 ksadk[codex]",不静默失败;构造时对真实 SDK 方法做 ``hasattr`` 校验,
10
+ 版本漂移时 fail-fast,而非运行期 AttributeError。
11
+ - 测试实现:用 fake(见 tests/runners/test_codex_runtime.py / test_adapter_contract.py),
12
+ 不需要真 CLI 二进制。
13
+
14
+ 诚实边界:本模块的 SDK **方法面**已对安装的 ``openai-codex==0.144.4`` 实证(方法存在性 +
15
+ 协程/asyncgen 形态);Notification → RuntimeEvent 的**字段级** phase 映射需在接真实 codex
16
+ 后端时按实况对齐(结构已按生成的 payload 类型映射,见 ``_notification_to_event_dict``)。
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import os
22
+ import secrets
23
+ from abc import ABC, abstractmethod
24
+ from importlib.metadata import PackageNotFoundError, version
25
+ from typing import Any, AsyncIterator, Optional
26
+
27
+ from ksadk.model_proxy import ProxyConfig, ProxyServer
28
+ from ksadk.model_proxy.cache import CapabilityCache, credential_scope
29
+ from ksadk.model_proxy.detect import probe_responses_capability
30
+
31
+ # 探测缓存单例:能力判定跨 client 共享,按 (model, base, credential_scope) 长缓存
32
+ _CAPABILITY_CACHE = CapabilityCache(ttl=3600)
33
+
34
+
35
+ def _is_openai_official(base: str) -> bool:
36
+ """OpenAI 官方 base_url(直连,不探测不代理)。"""
37
+ from urllib.parse import urlsplit
38
+
39
+ host = (urlsplit(base).hostname or "").lower()
40
+ return host == "api.openai.com" or host.endswith(".openai.com")
41
+
42
+
43
+ def _upgrade_http_to_https(upstream: str) -> str:
44
+ """http 非回环自动升级 https(凭证安全 + 兼容历史 http .env;星流等支持 https)。
45
+
46
+ ProxyConfig 强制非回环 https(凭证不裸奔);历史 .env 常写 http://kspmas,
47
+ 这里 upgrade 让 codex 代理对它可用,不改通用模板(ADK 等用 http 本就 OK)。
48
+ """
49
+ from urllib.parse import urlsplit, urlunsplit
50
+
51
+ parts = urlsplit(upstream)
52
+ scheme = parts.scheme.lower()
53
+ host = (parts.hostname or "").lower()
54
+ if scheme == "http" and host not in ("localhost", "127.0.0.1", "::1"):
55
+ return urlunsplit(("https", parts.netloc, parts.path, parts.query, parts.fragment))
56
+ return upstream
57
+
58
+
59
+ def _probe_requires_proxy(model: str, base: str, key: str) -> bool:
60
+ """探测上游:只有**确凿不支持 responses** 才返回 True(走代理)。
61
+
62
+ supported/unknown 都返回 False(直连)。unknown(故障)保守直连——故障 ≠ 模型
63
+ 不支持 responses,不 silent 改变接入方式。结果经 CapabilityCache 缓存(singleflight)。
64
+ """
65
+
66
+ def probe(m: str, b: str):
67
+ import httpx
68
+
69
+ with httpx.Client() as client:
70
+ return probe_responses_capability(client, b, key, m, timeout=15.0)
71
+
72
+ caps = _CAPABILITY_CACHE.get_or_probe(model, base, credential_scope(key), probe)
73
+ return caps.verdict == "unsupported"
74
+
75
+
76
+ class CodexClient(ABC):
77
+ """codex 后端(thread/turn 生命周期)的最小接口(对齐真实 SDK 线程模型)。"""
78
+
79
+ @abstractmethod
80
+ async def start_thread(self, config: Optional[dict[str, Any]] = None) -> str:
81
+ """新建 thread(真实 SDK ``thread_start``),返回 thread_id。"""
82
+ raise NotImplementedError
83
+
84
+ @abstractmethod
85
+ def run_turn(
86
+ self,
87
+ thread_id: str,
88
+ prompt: Any,
89
+ *,
90
+ config: Optional[dict[str, Any]] = None,
91
+ ) -> AsyncIterator[dict[str, Any]]:
92
+ """在 thread 上跑一个 turn(``thread.turn`` + ``handle.stream``),
93
+ 产出规范化事件 dict(``{"method": ..., "params": ...}``)。"""
94
+ raise NotImplementedError
95
+
96
+ @abstractmethod
97
+ async def interrupt_active_turn(self, thread_id: str) -> bool:
98
+ """interrupt 该 thread 当前活跃 turn(真实 SDK ``handle.interrupt``);
99
+ 无活跃 turn 返回 False。"""
100
+ raise NotImplementedError
101
+
102
+ @abstractmethod
103
+ async def resume_thread(self, thread_id: str, config: Optional[dict[str, Any]] = None) -> str:
104
+ """恢复 thread(真实 SDK ``thread_resume``),返回 thread_id。"""
105
+ raise NotImplementedError
106
+
107
+ @abstractmethod
108
+ async def close(self) -> None:
109
+ """释放后端资源(真实 SDK ``close``)。"""
110
+ raise NotImplementedError
111
+
112
+
113
+ def _missing_codex_error() -> RuntimeError:
114
+ return RuntimeError(
115
+ "CodexRuntime 需要 openai-codex SDK;请安装 ksadk[codex]:"
116
+ " pip install 'ksadk[codex]'(openai-codex 为可选 extra,不进默认依赖)"
117
+ )
118
+
119
+
120
+ class AsyncCodexClient(CodexClient):
121
+ """基于 OpenAI 官方 ``openai-codex`` SDK(``AsyncCodex``)的生产后端。
122
+
123
+ **lazy import** ``openai_codex``:仅在实际使用时导入,缺依赖时显式报错
124
+ (``pip install 'ksadk[codex]'``),不让所有 ksadk 用户默认背几十 MB CLI 二进制。
125
+ 构造时校验真实 SDK 方法存在(``thread_start``/``thread_resume``/``close`` 及
126
+ ``AsyncThread.turn`` / ``AsyncTurnHandle.stream``/``interrupt``),版本漂移 fail-fast。
127
+ """
128
+
129
+ def __init__(self, config: Any = None) -> None:
130
+ try:
131
+ from openai_codex import ( # type: ignore[import-not-found]
132
+ AsyncCodex,
133
+ AsyncThread,
134
+ AsyncTurnHandle,
135
+ )
136
+ except ImportError as exc:
137
+ raise _missing_codex_error() from exc
138
+
139
+ try:
140
+ sdk_version = version("openai-codex")
141
+ except PackageNotFoundError:
142
+ sdk_version = "unknown"
143
+ required = (
144
+ (AsyncCodex, "thread_start"),
145
+ (AsyncCodex, "thread_resume"),
146
+ (AsyncCodex, "close"),
147
+ (AsyncThread, "turn"),
148
+ (AsyncTurnHandle, "stream"),
149
+ (AsyncTurnHandle, "interrupt"),
150
+ )
151
+ for owner, method_name in required:
152
+ if not hasattr(owner, method_name):
153
+ raise RuntimeError(
154
+ f"openai-codex {sdk_version} SDK 缺少 "
155
+ f"{owner.__name__}.{method_name}(版本不兼容)"
156
+ )
157
+
158
+ # AsyncCodex 0.144.4 only accepts one CodexConfig positional/keyword.
159
+ config, self._proxy = self._maybe_apply_proxy(config)
160
+ self._codex = AsyncCodex(config=config)
161
+ self.sdk_version = sdk_version
162
+ self._threads: dict[str, Any] = {} # thread_id -> AsyncThread
163
+ self._active_handles: dict[str, Any] = {} # thread_id -> 活跃 AsyncTurnHandle
164
+
165
+ @staticmethod
166
+ def _maybe_apply_proxy(config: Any) -> tuple[Any, Any]:
167
+ """codex 代理启用:**智能探测 fallback(带显式覆盖)**。
168
+
169
+ - ``KSADK_CODEX_USE_PROXY=1`` → 强制开代理;``=0`` → 强制直连(可人工覆盖误判)。
170
+ - **未设 env 时智能探测**:OpenAI 官方 base_url 直连(不探测);自定义上游
171
+ (星流等)探测 responses 能力(detect.py + CapabilityCache 缓存,一次探测长缓存):
172
+ - ``supported`` → 直连(原生 responses 可用)
173
+ - ``unsupported`` → 自动启用代理(chat 模型,经转换层)
174
+ - ``unknown``(故障/超时)→ **保守直连**,不 silent 改变接入方式
175
+ - 凭证闭合:codex 子进程只拿随机 KSADK_PROXY_TOKEN;上游 key 留父进程。
176
+ - 互斥:launch_args_override 已设时 raise(override 整体覆盖命令行)。
177
+
178
+ 返回 (新 config, ProxyServer | None)。staticmethod 便于单测。
179
+ """
180
+ env_val = os.environ.get("KSADK_CODEX_USE_PROXY")
181
+ if env_val == "0":
182
+ return config, None
183
+ if env_val == "1":
184
+ return AsyncCodexClient._start_proxy_and_inject(config)
185
+ # 未设:智能探测
186
+ base = (
187
+ os.environ.get("KSADK_PROXY_UPSTREAM_BASE")
188
+ or os.environ.get("OPENAI_BASE_URL")
189
+ or os.environ.get("OPENAI_API_BASE")
190
+ or ""
191
+ )
192
+ if not base or _is_openai_official(base):
193
+ return config, None # OpenAI 官方:直连,不探测
194
+ model = os.environ.get("OPENAI_MODEL_NAME") or os.environ.get("MODEL_NAME") or ""
195
+ key = os.environ.get("KSADK_PROXY_UPSTREAM_KEY") or os.environ.get("OPENAI_API_KEY") or ""
196
+ if _probe_requires_proxy(model, base, key):
197
+ return AsyncCodexClient._start_proxy_and_inject(config)
198
+ return config, None
199
+
200
+ @staticmethod
201
+ def _start_proxy_and_inject(config: Any) -> tuple[Any, Any]:
202
+ """起进程内 ProxyServer + 注入 codex provider(opt-in/探测判定走代理时)。"""
203
+ import dataclasses
204
+
205
+ from openai_codex import CodexConfig # type: ignore[import-not-found]
206
+
207
+ cfg = config if isinstance(config, CodexConfig) else CodexConfig()
208
+ if cfg.launch_args_override is not None:
209
+ raise RuntimeError(
210
+ "KSADK_CODEX_USE_PROXY 与 CodexConfig.launch_args_override 互斥:"
211
+ "代理注入靠 config_overrides,而 launch_args_override 会整体覆盖命令行"
212
+ )
213
+ upstream = (
214
+ os.environ.get("KSADK_PROXY_UPSTREAM_BASE")
215
+ or os.environ.get("OPENAI_BASE_URL")
216
+ or os.environ.get("OPENAI_API_BASE")
217
+ or "https://kspmas.ksyun.com/v1"
218
+ )
219
+ upstream = _upgrade_http_to_https(upstream)
220
+ api_key = (
221
+ os.environ.get("KSADK_PROXY_UPSTREAM_KEY") or os.environ.get("OPENAI_API_KEY") or ""
222
+ )
223
+ token = secrets.token_hex(16)
224
+ proxy = ProxyServer(ProxyConfig(upstream_base=upstream, api_key=api_key, local_token=token))
225
+ proxy.start()
226
+ overrides = list(cfg.config_overrides or ())
227
+ overrides += [
228
+ "model_provider=ksadk_proxy",
229
+ "model_providers.ksadk_proxy.name=ksadk_proxy",
230
+ f"model_providers.ksadk_proxy.base_url={proxy.base_url}",
231
+ "model_providers.ksadk_proxy.env_key=KSADK_PROXY_TOKEN",
232
+ "model_providers.ksadk_proxy.wire_api=responses",
233
+ "model_providers.ksadk_proxy.supports_websockets=false",
234
+ "web_search=disabled",
235
+ "features.multi_agent=false",
236
+ "features.multi_agent_v2=false",
237
+ ]
238
+ env = dict(cfg.env or {})
239
+ env["KSADK_PROXY_TOKEN"] = token
240
+ return dataclasses.replace(cfg, config_overrides=tuple(overrides), env=env), proxy
241
+
242
+
243
+ async def start_thread(self, config: Optional[dict[str, Any]] = None) -> str:
244
+ thread = await self._codex.thread_start(**self._thread_kwargs(config))
245
+ self._threads[thread.id] = thread
246
+ return str(thread.id)
247
+
248
+ async def resume_thread(self, thread_id: str, config: Optional[dict[str, Any]] = None) -> str:
249
+ # An ephemeral thread has no rollout on disk, so SDK thread_resume would
250
+ # fail with -32600. Reuse its live AsyncThread for same-process resume.
251
+ cached = self._threads.get(thread_id)
252
+ if cached is not None:
253
+ return str(cached.id)
254
+ kwargs = self._thread_kwargs(config)
255
+ # AsyncCodex.thread_resume 0.144.4 has no ephemeral parameter.
256
+ kwargs.pop("ephemeral", None)
257
+ thread = await self._codex.thread_resume(thread_id, **kwargs)
258
+ self._threads[thread.id] = thread
259
+ return str(thread.id)
260
+
261
+ def run_turn(
262
+ self,
263
+ thread_id: str,
264
+ prompt: Any,
265
+ *,
266
+ config: Optional[dict[str, Any]] = None,
267
+ ) -> AsyncIterator[dict[str, Any]]:
268
+ return self._run_turn_gen(thread_id, prompt, config)
269
+
270
+ async def _run_turn_gen(
271
+ self, thread_id: str, prompt: Any, config: Optional[dict[str, Any]]
272
+ ) -> AsyncIterator[dict[str, Any]]:
273
+ thread = self._threads.get(thread_id)
274
+ if thread is None:
275
+ # 未显式 start/resume 的 thread_id:按 resume 语义接入真实后端。
276
+ await self.resume_thread(thread_id, config)
277
+ thread = self._threads[thread_id]
278
+ handle = await thread.turn(self._coerce_input(prompt), **self._turn_kwargs(config))
279
+ self._active_handles[thread_id] = handle
280
+ try:
281
+ async for notification in handle.stream():
282
+ event = self._notification_to_event_dict(notification)
283
+ if event is not None:
284
+ yield event
285
+ finally:
286
+ self._active_handles.pop(thread_id, None)
287
+
288
+ async def interrupt_active_turn(self, thread_id: str) -> bool:
289
+ handle = self._active_handles.get(thread_id)
290
+ if handle is None:
291
+ return False
292
+ await handle.interrupt()
293
+ return True
294
+
295
+ async def close(self) -> None:
296
+ try:
297
+ await self._codex.close()
298
+ finally:
299
+ self._active_handles.clear()
300
+ self._threads.clear()
301
+ if self._proxy is not None:
302
+ self._proxy.stop()
303
+ self._proxy = None
304
+
305
+ # ---- 内部:config / input / 事件映射 ----
306
+
307
+ @staticmethod
308
+ def _thread_kwargs(config: Optional[dict[str, Any]]) -> dict[str, Any]:
309
+ """Map runtime config to the exact 0.144.4 thread API surface."""
310
+ from openai_codex import ApprovalMode, Sandbox # type: ignore[import-not-found]
311
+
312
+ config = config or {}
313
+ known = {
314
+ "approval_mode",
315
+ "model",
316
+ "model_provider",
317
+ "cwd",
318
+ "sandbox",
319
+ "service_tier",
320
+ "base_instructions",
321
+ "developer_instructions",
322
+ "ephemeral",
323
+ }
324
+ result = {k: v for k, v in config.items() if k in known}
325
+ # KSADK sessions are ephemeral so an interrupted/half-written turn cannot
326
+ # later be revived from Codex's on-disk session store.
327
+ result.setdefault("ephemeral", True)
328
+ if config.get("sandbox_read_only", False):
329
+ result["sandbox"] = Sandbox.read_only
330
+ result.setdefault("approval_mode", ApprovalMode.deny_all)
331
+ else:
332
+ result["sandbox"] = _coerce_enum(Sandbox, result.get("sandbox"))
333
+ result["approval_mode"] = _coerce_enum(ApprovalMode, result.get("approval_mode"))
334
+ return {key: value for key, value in result.items() if value is not None}
335
+
336
+ @staticmethod
337
+ def _turn_kwargs(config: Optional[dict[str, Any]]) -> dict[str, Any]:
338
+ """Map runtime config to the exact 0.144.4 AsyncThread.turn surface."""
339
+ from openai_codex import ApprovalMode, Sandbox # type: ignore[import-not-found]
340
+
341
+ config = config or {}
342
+ known = {
343
+ "approval_mode",
344
+ "cwd",
345
+ "effort",
346
+ "model",
347
+ "output_schema",
348
+ "personality",
349
+ "sandbox",
350
+ "service_tier",
351
+ "summary",
352
+ }
353
+ result = {key: value for key, value in config.items() if key in known}
354
+ if config.get("sandbox_read_only", False):
355
+ result["sandbox"] = Sandbox.read_only
356
+ result.setdefault("approval_mode", ApprovalMode.deny_all)
357
+ else:
358
+ result["sandbox"] = _coerce_enum(Sandbox, result.get("sandbox"))
359
+ result["approval_mode"] = _coerce_enum(ApprovalMode, result.get("approval_mode"))
360
+ return {key: value for key, value in result.items() if value is not None}
361
+
362
+ @staticmethod
363
+ def _coerce_input(prompt: Any) -> Any:
364
+ # RunInput 接受 str 或 [TextInput|...];str 直接透传。
365
+ return prompt if isinstance(prompt, str) else prompt
366
+
367
+ @staticmethod
368
+ def _notification_to_event_dict(notification: Any) -> Optional[dict[str, Any]]:
369
+ """把真实 ``Notification``(method + 类型化 payload)映射为运行时消费的规范化 dict。
370
+
371
+ 按 payload 类型路由(结构已对生成的 payload 类型实证);字段级 phase 细节在接
372
+ 真实后端时对齐。
373
+ """
374
+ payload = notification.payload
375
+ if hasattr(payload, "model_dump"):
376
+ params = payload.model_dump(mode="json")
377
+ else:
378
+ params = getattr(payload, "params", None)
379
+ if not isinstance(params, dict):
380
+ params = {}
381
+
382
+ method = str(getattr(notification, "method", ""))
383
+ supported_methods = {
384
+ "item/started",
385
+ "item/completed",
386
+ "item/agentMessage/delta",
387
+ "item/autoApprovalReview/started",
388
+ "item/autoApprovalReview/completed",
389
+ "error",
390
+ }
391
+ if method in supported_methods:
392
+ return {"method": method, "params": params}
393
+ return None
394
+
395
+
396
+ def _coerce_enum(enum_type: Any, value: Any) -> Any:
397
+ if value is None or isinstance(value, enum_type):
398
+ return value
399
+ try:
400
+ return enum_type(value)
401
+ except (TypeError, ValueError) as exc:
402
+ supported = ", ".join(member.value for member in enum_type)
403
+ raise ValueError(
404
+ f"unsupported {enum_type.__name__} {value!r}; expected {supported}"
405
+ ) from exc
406
+
407
+
408
+ __all__ = ["AsyncCodexClient", "CodexClient"]