agentengine-sdk-python 0.6.4__py3-none-any.whl → 0.7.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 (486) hide show
  1. agentengine_sdk_python-0.7.0.dist-info/METADATA +181 -0
  2. agentengine_sdk_python-0.7.0.dist-info/RECORD +482 -0
  3. {agentengine_sdk_python-0.6.4.dist-info → agentengine_sdk_python-0.7.0.dist-info}/WHEEL +1 -1
  4. agentengine_sdk_python-0.7.0.dist-info/entry_points.txt +3 -0
  5. agentengine_sdk_python-0.7.0.dist-info/licenses/LICENSE +175 -0
  6. agentengine_sdk_python-0.7.0.dist-info/top_level.txt +2 -0
  7. ksadk/__init__.py +13 -0
  8. ksadk/__main__.py +4 -0
  9. ksadk/a2a/__init__.py +15 -0
  10. ksadk/a2a/card_builder.py +64 -0
  11. ksadk/a2a/client.py +309 -0
  12. ksadk/a2a/executor.py +201 -0
  13. ksadk/a2a/server.py +79 -0
  14. ksadk/agents/__init__.py +20 -0
  15. ksadk/agents/base.py +370 -0
  16. ksadk/agents/context.py +38 -0
  17. ksadk/agents/event.py +35 -0
  18. ksadk/agents/loop_agent.py +71 -0
  19. ksadk/agents/parallel_agent.py +109 -0
  20. ksadk/agents/runner_adapter.py +24 -0
  21. ksadk/agents/sequential_agent.py +34 -0
  22. ksadk/api/__init__.py +3 -0
  23. ksadk/api/client.py +2246 -0
  24. ksadk/builders/__init__.py +20 -0
  25. ksadk/builders/base.py +66 -0
  26. ksadk/builders/code_builder.py +1990 -0
  27. ksadk/builders/container_builder.py +786 -0
  28. ksadk/builders/framework_requirements.py +59 -0
  29. ksadk/builders/ks3_uploader.py +389 -0
  30. ksadk/builders/mcp_builder.py +476 -0
  31. ksadk/builders/requirements_utils.py +75 -0
  32. ksadk/cli/__init__.py +531 -0
  33. ksadk/cli/__main__.py +4 -0
  34. ksadk/cli/agent_ref.py +204 -0
  35. ksadk/cli/cmd_a2a.py +167 -0
  36. ksadk/cli/cmd_agent.py +201 -0
  37. ksadk/cli/cmd_build.py +270 -0
  38. ksadk/cli/cmd_completion.py +304 -0
  39. ksadk/cli/cmd_config.py +758 -0
  40. ksadk/cli/cmd_create.py +2304 -0
  41. ksadk/cli/cmd_dashboard.py +900 -0
  42. ksadk/cli/cmd_deploy.py +704 -0
  43. ksadk/cli/cmd_destroy.py +345 -0
  44. ksadk/cli/cmd_files.py +1227 -0
  45. ksadk/cli/cmd_hermes.py +1263 -0
  46. ksadk/cli/cmd_invoke.py +1503 -0
  47. ksadk/cli/cmd_launch.py +564 -0
  48. ksadk/cli/cmd_mcp.py +1179 -0
  49. ksadk/cli/cmd_model.py +302 -0
  50. ksadk/cli/cmd_openclaw.py +3922 -0
  51. ksadk/cli/cmd_run.py +239 -0
  52. ksadk/cli/cmd_status.py +588 -0
  53. ksadk/cli/cmd_version.py +522 -0
  54. ksadk/cli/cmd_web.py +288 -0
  55. ksadk/cli/deploy_utils.py +87 -0
  56. ksadk/cli/dry_run.py +214 -0
  57. ksadk/cli/env_options.py +82 -0
  58. ksadk/cli/error_utils.py +525 -0
  59. ksadk/cli/global_options.py +31 -0
  60. ksadk/cli/local_runtime.py +97 -0
  61. ksadk/cli/model_catalog.py +136 -0
  62. ksadk/cli/network_options.py +412 -0
  63. ksadk/cli/resource_common.py +621 -0
  64. ksadk/cli/storage.py +84 -0
  65. ksadk/cli/ui.py +431 -0
  66. ksadk/cli/workflow_common.py +552 -0
  67. ksadk/common/__init__.py +14 -0
  68. ksadk/common/aicp_env.py +128 -0
  69. ksadk/common/auth.py +190 -0
  70. ksadk/common/constants.py +84 -0
  71. ksadk/common/llm_utils.py +61 -0
  72. ksadk/configs/__init__.py +61 -0
  73. ksadk/configs/env_registry.py +343 -0
  74. ksadk/configs/global_config.py +200 -0
  75. ksadk/configs/settings.py +706 -0
  76. ksadk/conversations/__init__.py +95 -0
  77. ksadk/conversations/attachment_storage.py +379 -0
  78. ksadk/conversations/attachments.py +774 -0
  79. ksadk/conversations/compaction_pipeline.py +387 -0
  80. ksadk/conversations/compaction_prompt.py +128 -0
  81. ksadk/conversations/context.py +303 -0
  82. ksadk/conversations/message_projection.py +269 -0
  83. ksadk/conversations/model_context.py +370 -0
  84. ksadk/conversations/model_options.py +136 -0
  85. ksadk/conversations/normalize.py +446 -0
  86. ksadk/conversations/reasoning_markup.py +91 -0
  87. ksadk/conversations/run_kinds.py +61 -0
  88. ksadk/conversations/run_status.py +53 -0
  89. ksadk/conversations/runtime.py +5276 -0
  90. ksadk/conversations/semantic_summary.py +359 -0
  91. ksadk/conversations/session_title.py +254 -0
  92. ksadk/deployment/__init__.py +83 -0
  93. ksadk/deployment/agent_access.py +226 -0
  94. ksadk/deployment/base.py +229 -0
  95. ksadk/deployment/manager.py +332 -0
  96. ksadk/deployment/providers/__init__.py +10 -0
  97. ksadk/deployment/providers/serverless.py +1115 -0
  98. ksadk/deployment/registry.py +120 -0
  99. ksadk/deployment/state.py +78 -0
  100. ksadk/deployment/ui_config.py +21 -0
  101. ksadk/detection/__init__.py +7 -0
  102. ksadk/detection/detector.py +431 -0
  103. ksadk/detection/mcp_detector.py +250 -0
  104. ksadk/hermes_terminal.py +467 -0
  105. ksadk/identity/__init__.py +17 -0
  106. ksadk/identity/resolver.py +385 -0
  107. ksadk/knowledge_base/__init__.py +62 -0
  108. ksadk/knowledge_base/adk_tool.py +47 -0
  109. ksadk/knowledge_base/client.py +297 -0
  110. ksadk/knowledge_base/langchain_tool.py +55 -0
  111. ksadk/knowledge_base/service.py +66 -0
  112. ksadk/knowledge_base/tool.py +50 -0
  113. ksadk/markdown.py +169 -0
  114. ksadk/mcp_runtime/__init__.py +231 -0
  115. ksadk/memory/__init__.py +57 -0
  116. ksadk/memory/adk/__init__.py +51 -0
  117. ksadk/memory/adk/backends/__init__.py +5 -0
  118. ksadk/memory/adk/backends/base_ltm_backend.py +52 -0
  119. ksadk/memory/adk/backends/http_ltm_backend.py +183 -0
  120. ksadk/memory/adk/backends/inmemory_ltm_backend.py +96 -0
  121. ksadk/memory/adk/backends/sdk_ltm_backend.py +456 -0
  122. ksadk/memory/adk/long_term_memory.py +273 -0
  123. ksadk/memory/adk/resilient_session_service.py +268 -0
  124. ksadk/memory/adk/short_term_memory.py +304 -0
  125. ksadk/memory/adk_tool.py +31 -0
  126. ksadk/memory/backends/__init__.py +6 -0
  127. ksadk/memory/backends/base.py +103 -0
  128. ksadk/memory/backends/memory.py +112 -0
  129. ksadk/memory/backends/redis.py +146 -0
  130. ksadk/memory/langchain_tool.py +39 -0
  131. ksadk/memory/ltm_backend_factory.py +24 -0
  132. ksadk/memory/manager.py +215 -0
  133. ksadk/memory/service.py +172 -0
  134. ksadk/memory/tool.py +96 -0
  135. ksadk/model_policy.py +223 -0
  136. ksadk/openclaw_gateway.py +378 -0
  137. ksadk/runners/__init__.py +8 -0
  138. ksadk/runners/adk_runner.py +1994 -0
  139. ksadk/runners/base_runner.py +305 -0
  140. ksadk/runners/deepagents_runner.py +13 -0
  141. ksadk/runners/factory.py +73 -0
  142. ksadk/runners/langchain_runner.py +751 -0
  143. ksadk/runners/langgraph_runner.py +985 -0
  144. ksadk/runners/patch_langchain.py +187 -0
  145. ksadk/runners/remote_runner.py +792 -0
  146. ksadk/runners/usage_accumulator.py +38 -0
  147. ksadk/runners/utils/__init__.py +19 -0
  148. ksadk/runners/utils/langfuse.py +230 -0
  149. ksadk/runners/utils/loader.py +62 -0
  150. ksadk/runtime_context.py +166 -0
  151. ksadk/runtime_state.py +25 -0
  152. ksadk/sandbox/__init__.py +28 -0
  153. ksadk/sandbox/backends/__init__.py +9 -0
  154. ksadk/sandbox/backends/e2b.py +154 -0
  155. ksadk/sandbox/backends/local_process.py +131 -0
  156. ksadk/sandbox/base.py +101 -0
  157. ksadk/sandbox/factory.py +53 -0
  158. ksadk/sandbox/registry.py +187 -0
  159. ksadk/server/__init__.py +7 -0
  160. ksadk/server/api_models.py +73 -0
  161. ksadk/server/app.py +3931 -0
  162. ksadk/server/static/assets/ArtifactsPanel-D-SSn2ee.js +1 -0
  163. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +9 -0
  164. ksadk/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  165. ksadk/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  166. ksadk/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  167. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  168. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  169. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  170. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  171. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  172. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  173. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  174. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  175. ksadk/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  176. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  177. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  178. ksadk/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  179. ksadk/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  180. ksadk/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  181. ksadk/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  182. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  183. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  184. ksadk/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  185. ksadk/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  186. ksadk/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  187. ksadk/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  188. ksadk/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  189. ksadk/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  190. ksadk/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  191. ksadk/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  192. ksadk/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  193. ksadk/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  194. ksadk/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  195. ksadk/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  196. ksadk/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  197. ksadk/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  198. ksadk/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  199. ksadk/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  200. ksadk/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  201. ksadk/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  202. ksadk/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  203. ksadk/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  204. ksadk/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  205. ksadk/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  206. ksadk/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  207. ksadk/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  208. ksadk/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  209. ksadk/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  210. ksadk/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  211. ksadk/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  212. ksadk/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  213. ksadk/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  214. ksadk/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  215. ksadk/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  216. ksadk/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  217. ksadk/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  218. ksadk/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  219. ksadk/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  220. ksadk/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  221. ksadk/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  222. ksadk/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +8 -0
  224. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +1 -0
  225. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +303 -0
  226. ksadk/server/static/assets/NativeTerminalPanel-CHOd7Rch.css +1 -0
  227. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +1 -0
  228. ksadk/server/static/assets/addon-fit-DthTIhi3.js +1 -0
  229. ksadk/server/static/assets/apl-CnwPGSsG.js +1 -0
  230. ksadk/server/static/assets/arc-BA13sHc9.js +1 -0
  231. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +1 -0
  232. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-DzJzgVoL.js +36 -0
  233. ksadk/server/static/assets/asciiarmor-qTkVPQu6.js +1 -0
  234. ksadk/server/static/assets/asn1-Dr8qZg38.js +1 -0
  235. ksadk/server/static/assets/asterisk-Bja0s6e1.js +1 -0
  236. ksadk/server/static/assets/blockDiagram-GPEHLZMM-UTdVcZhn.js +132 -0
  237. ksadk/server/static/assets/brainfuck-D5EjA2JK.js +1 -0
  238. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dix0GD4m.js +10 -0
  239. ksadk/server/static/assets/channel-CTuydARX.js +1 -0
  240. ksadk/server/static/assets/chunk-2J33WTMH-C2JxuZ42.js +1 -0
  241. ksadk/server/static/assets/chunk-4BX2VUAB-Be57QPgD.js +1 -0
  242. ksadk/server/static/assets/chunk-55IACEB6-WjSuy4nv.js +1 -0
  243. ksadk/server/static/assets/chunk-727SXJPM-BOovP-b5.js +206 -0
  244. ksadk/server/static/assets/chunk-AQP2D5EJ-DOmZNmWj.js +231 -0
  245. ksadk/server/static/assets/chunk-FMBD7UC4-DzwlodkU.js +15 -0
  246. ksadk/server/static/assets/chunk-ND2GUHAM-DMqAikEU.js +1 -0
  247. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +1 -0
  248. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +1 -0
  249. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +1 -0
  250. ksadk/server/static/assets/clike-DHH8Ad3s.js +1 -0
  251. ksadk/server/static/assets/clojure-BflJGmDX.js +1 -0
  252. ksadk/server/static/assets/cmake-CyVbuzPu.js +1 -0
  253. ksadk/server/static/assets/cobol-B_OZ4V-R.js +1 -0
  254. ksadk/server/static/assets/coffeescript-B2pKbFk8.js +1 -0
  255. ksadk/server/static/assets/commonlisp-CcllspGY.js +1 -0
  256. ksadk/server/static/assets/cose-bilkent-S5V4N54A-Zhy2GBnP.js +1 -0
  257. ksadk/server/static/assets/crystal-M5-qzICs.js +1 -0
  258. ksadk/server/static/assets/css-CYpP4FRV.js +1 -0
  259. ksadk/server/static/assets/cypher-p9eYesGn.js +1 -0
  260. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +321 -0
  261. ksadk/server/static/assets/d-BhMjBjQP.js +1 -0
  262. ksadk/server/static/assets/dagre-BM42HDAG-CbKrtIUz.js +4 -0
  263. ksadk/server/static/assets/dagre-Bx709z4p.js +1 -0
  264. ksadk/server/static/assets/defaultLocale-C8Fc0cco.js +1 -0
  265. ksadk/server/static/assets/diagram-2AECGRRQ-BRApgQRK.js +43 -0
  266. ksadk/server/static/assets/diagram-5GNKFQAL-D0xbnDiK.js +10 -0
  267. ksadk/server/static/assets/diagram-KO2AKTUF-CVugVI9L.js +3 -0
  268. ksadk/server/static/assets/diagram-LMA3HP47-DozUGgee.js +24 -0
  269. ksadk/server/static/assets/diagram-OG6HWLK6-ZOYsKlru.js +24 -0
  270. ksadk/server/static/assets/diff-ChtP43wD.js +1 -0
  271. ksadk/server/static/assets/dist-2hInLS_J.js +9 -0
  272. ksadk/server/static/assets/dist-8EEyGgDx.js +1 -0
  273. ksadk/server/static/assets/dist-8_SfK1IP.js +1 -0
  274. ksadk/server/static/assets/dist-B0NP_Z0z.js +23 -0
  275. ksadk/server/static/assets/dist-BIJVDMuB.js +1 -0
  276. ksadk/server/static/assets/dist-BmlMPsCc.js +2 -0
  277. ksadk/server/static/assets/dist-BrCcQ47T.js +1 -0
  278. ksadk/server/static/assets/dist-BssVmjIo.js +6 -0
  279. ksadk/server/static/assets/dist-C3HIIaN5.js +1 -0
  280. ksadk/server/static/assets/dist-CPBtqRTW.js +1 -0
  281. ksadk/server/static/assets/dist-CkEKJFtk.js +1 -0
  282. ksadk/server/static/assets/dist-D-JMdWPQ.js +1 -0
  283. ksadk/server/static/assets/dist-D-xOD048.js +1 -0
  284. ksadk/server/static/assets/dist-D57wnGWd.js +1 -0
  285. ksadk/server/static/assets/dist-DL_NKc_z.js +1 -0
  286. ksadk/server/static/assets/dist-DMezvBGJ.js +1 -0
  287. ksadk/server/static/assets/dist-DmFaq_Iy.js +1 -0
  288. ksadk/server/static/assets/dist-Dp0k7bWI.js +1 -0
  289. ksadk/server/static/assets/dist-DpKtt4Bo.js +1 -0
  290. ksadk/server/static/assets/dist-DyOkZmze.js +11 -0
  291. ksadk/server/static/assets/dist-DyWsb78Q.js +1 -0
  292. ksadk/server/static/assets/dist-gX6GOLKq.js +1 -0
  293. ksadk/server/static/assets/dockerfile-BLkNEvjs.js +1 -0
  294. ksadk/server/static/assets/dtd-DTF72YNO.js +1 -0
  295. ksadk/server/static/assets/dylan-C6jEEEk-.js +1 -0
  296. ksadk/server/static/assets/ebnf-D4c0_ac3.js +1 -0
  297. ksadk/server/static/assets/ecl-BSZaIHnp.js +1 -0
  298. ksadk/server/static/assets/eiffel-BEjRio4Q.js +1 -0
  299. ksadk/server/static/assets/elm-Cshzl8qu.js +1 -0
  300. ksadk/server/static/assets/erDiagram-TEJ5UH35-Bk-9bgE5.js +85 -0
  301. ksadk/server/static/assets/erlang-DaB2Rkuy.js +1 -0
  302. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +1 -0
  303. ksadk/server/static/assets/factor-D7LVTn2l.js +1 -0
  304. ksadk/server/static/assets/fcl-ClOhbFR7.js +1 -0
  305. ksadk/server/static/assets/flowDiagram-I6XJVG4X-Dn9kZVuZ.js +162 -0
  306. ksadk/server/static/assets/forth-Cezjo90N.js +1 -0
  307. ksadk/server/static/assets/fortran-Bt6PBEDR.js +1 -0
  308. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-BGxXlJqm.js +292 -0
  309. ksadk/server/static/assets/gas-BHEdbvp9.js +1 -0
  310. ksadk/server/static/assets/gherkin-oBAE_ms0.js +1 -0
  311. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +1 -0
  312. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-C7Q0X-wi.js +106 -0
  313. ksadk/server/static/assets/graphlib-B8gBHxth.js +1 -0
  314. ksadk/server/static/assets/groovy-BC3IOsC8.js +1 -0
  315. ksadk/server/static/assets/haskell-BRsoo5mP.js +1 -0
  316. ksadk/server/static/assets/haxe-DIz0ZZqd.js +1 -0
  317. ksadk/server/static/assets/http-CLVgA2GD.js +1 -0
  318. ksadk/server/static/assets/idl-BUZw3wgd.js +1 -0
  319. ksadk/server/static/assets/index-C00Lwg3L.js +165 -0
  320. ksadk/server/static/assets/index-DAURbCsP.css +1 -0
  321. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +1 -0
  322. ksadk/server/static/assets/infoDiagram-5YYISTIA-BO_CSqq5.js +2 -0
  323. ksadk/server/static/assets/init-D6jRqBbL.js +1 -0
  324. ksadk/server/static/assets/ishikawaDiagram-YF4QCWOH-eYLPLd46.js +70 -0
  325. ksadk/server/static/assets/javascript-9Tg8ixDm.js +1 -0
  326. ksadk/server/static/assets/journeyDiagram-JHISSGLW-De9geSb0.js +139 -0
  327. ksadk/server/static/assets/julia-CQfgDRfP.js +1 -0
  328. ksadk/server/static/assets/kanban-definition-UN3LZRKU-Cs80kQto.js +89 -0
  329. ksadk/server/static/assets/katex-DSrCFD8n.js +265 -0
  330. ksadk/server/static/assets/linear-CN9sbKTF.js +1 -0
  331. ksadk/server/static/assets/livescript-BXxG0Yva.js +1 -0
  332. ksadk/server/static/assets/lua-CiA1ziua.js +1 -0
  333. ksadk/server/static/assets/mathematica-u8YMmbU0.js +1 -0
  334. ksadk/server/static/assets/mbox-BEMVcqjs.js +1 -0
  335. ksadk/server/static/assets/mermaid-parser.core-DlgSBU8l.js +161 -0
  336. ksadk/server/static/assets/mindmap-definition-RKZ34NQL-9afz7Oug.js +96 -0
  337. ksadk/server/static/assets/mirc-C9zpzAZU.js +1 -0
  338. ksadk/server/static/assets/mllike-B45xgp2S.js +1 -0
  339. ksadk/server/static/assets/modelica-CqHI_q-D.js +1 -0
  340. ksadk/server/static/assets/mscgen-qgSLujhx.js +1 -0
  341. ksadk/server/static/assets/mumps-CW_TBmxz.js +1 -0
  342. ksadk/server/static/assets/nginx-BMaDbqW3.js +1 -0
  343. ksadk/server/static/assets/nsis-AQ_alPln.js +1 -0
  344. ksadk/server/static/assets/ntriples-d28e9m0E.js +1 -0
  345. ksadk/server/static/assets/octave-D2Q8cUp1.js +1 -0
  346. ksadk/server/static/assets/ordinal-hYBb2elL.js +1 -0
  347. ksadk/server/static/assets/oz-BwTct_5T.js +1 -0
  348. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +1 -0
  349. ksadk/server/static/assets/pascal-Dp_KdFgX.js +1 -0
  350. ksadk/server/static/assets/perl-CdEHsPfU.js +1 -0
  351. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +1 -0
  352. ksadk/server/static/assets/pieDiagram-4H26LBE5-DPv_VstN.js +30 -0
  353. ksadk/server/static/assets/pig-AF4Hwhju.js +1 -0
  354. ksadk/server/static/assets/powershell-CzG71I4L.js +1 -0
  355. ksadk/server/static/assets/properties-C357ku5U.js +1 -0
  356. ksadk/server/static/assets/protobuf-D1ij_kNL.js +1 -0
  357. ksadk/server/static/assets/pug-Bugr-47h.js +1 -0
  358. ksadk/server/static/assets/puppet-B4hC2X4m.js +1 -0
  359. ksadk/server/static/assets/python-BqYw9LYJ.js +1 -0
  360. ksadk/server/static/assets/q-B9NhS7L_.js +1 -0
  361. ksadk/server/static/assets/quadrantDiagram-W4KKPZXB-o77wZ1XK.js +7 -0
  362. ksadk/server/static/assets/r-DADKenSm.js +1 -0
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +1 -0
  364. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-BYVw81VC.js +84 -0
  365. ksadk/server/static/assets/rpm-gpDK5sbt.js +1 -0
  366. ksadk/server/static/assets/ruby-DsYpTuWg.js +1 -0
  367. ksadk/server/static/assets/sankeyDiagram-5OEKKPKP-B7nZFMKT.js +40 -0
  368. ksadk/server/static/assets/sas-C2OyD2Y6.js +1 -0
  369. ksadk/server/static/assets/scheme-CyDdOh7e.js +1 -0
  370. ksadk/server/static/assets/sequenceDiagram-3UESZ5HK-BGRRrFw5.js +162 -0
  371. ksadk/server/static/assets/shell-Du5Qg9im.js +1 -0
  372. ksadk/server/static/assets/sieve-BAxa3IjF.js +1 -0
  373. ksadk/server/static/assets/simple-mode-DRpGK0lJ.js +1 -0
  374. ksadk/server/static/assets/smalltalk-BLp5-jwC.js +1 -0
  375. ksadk/server/static/assets/solr-BBopId9w.js +1 -0
  376. ksadk/server/static/assets/sparql-Dz-mlCAC.js +1 -0
  377. ksadk/server/static/assets/spreadsheet-CTIncYxj.js +1 -0
  378. ksadk/server/static/assets/sql-DcCJ9jop.js +1 -0
  379. ksadk/server/static/assets/stateDiagram-AJRCARHV-BUfHCoPs.js +1 -0
  380. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +1 -0
  381. ksadk/server/static/assets/stex-sDrdk2BW.js +1 -0
  382. ksadk/server/static/assets/stylus-DLLZ8dgm.js +1 -0
  383. ksadk/server/static/assets/swift-DKB6_1j6.js +1 -0
  384. ksadk/server/static/assets/tcl-BGfruO1u.js +1 -0
  385. ksadk/server/static/assets/textile-DWBqthVk.js +1 -0
  386. ksadk/server/static/assets/tiddlywiki-VlUiK86J.js +1 -0
  387. ksadk/server/static/assets/tiki-CxVlf5KZ.js +1 -0
  388. ksadk/server/static/assets/timeline-definition-PNZ67QCA-FbCTGrf9.js +120 -0
  389. ksadk/server/static/assets/toml-LvoKBwCs.js +1 -0
  390. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +1 -0
  391. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +1 -0
  392. ksadk/server/static/assets/troff-C2dAgh7P.js +1 -0
  393. ksadk/server/static/assets/ttcn-BePYh-hG.js +1 -0
  394. ksadk/server/static/assets/ttcn-cfg-CY0aot7Q.js +1 -0
  395. ksadk/server/static/assets/turtle-BDLWE2cD.js +1 -0
  396. ksadk/server/static/assets/vb-BthdM_4N.js +1 -0
  397. ksadk/server/static/assets/vbscript-D9f6rSsU.js +1 -0
  398. ksadk/server/static/assets/velocity-CqftRsjg.js +1 -0
  399. ksadk/server/static/assets/vennDiagram-CIIHVFJN-DWgwtPsJ.js +34 -0
  400. ksadk/server/static/assets/verilog-D-x6ne0Z.js +1 -0
  401. ksadk/server/static/assets/vhdl-CMrOq2q1.js +1 -0
  402. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +1 -0
  403. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-2x8G-tTM.js +78 -0
  404. ksadk/server/static/assets/webidl-D5jiJvOU.js +1 -0
  405. ksadk/server/static/assets/xquery-fj_R-kMw.js +1 -0
  406. ksadk/server/static/assets/xterm-DooSxjI5.js +36 -0
  407. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-Drma3AYl.js +7 -0
  408. ksadk/server/static/assets/yacas-CXXgtw0p.js +1 -0
  409. ksadk/server/static/assets/z80-CL1naaMV.js +1 -0
  410. ksadk/server/static/favicon.svg +1 -0
  411. ksadk/server/static/icons.svg +24 -0
  412. ksadk/server/static/index.html +14 -0
  413. ksadk/server/terminal_sessions.py +551 -0
  414. ksadk/sessions/__init__.py +279 -0
  415. ksadk/sessions/base.py +354 -0
  416. ksadk/sessions/continuity.py +337 -0
  417. ksadk/sessions/errors.py +7 -0
  418. ksadk/sessions/in_memory.py +273 -0
  419. ksadk/sessions/local_service.py +949 -0
  420. ksadk/sessions/postgres_service.py +901 -0
  421. ksadk/sessions/resilience.py +52 -0
  422. ksadk/sessions/resilient.py +360 -0
  423. ksadk/sessions/sqlite_service.py +13 -0
  424. ksadk/skills/__init__.py +9 -0
  425. ksadk/skills/loader.py +46 -0
  426. ksadk/skills/models.py +120 -0
  427. ksadk/skills/package_store.py +104 -0
  428. ksadk/skills/runtime/__init__.py +17 -0
  429. ksadk/skills/runtime/agent.py +183 -0
  430. ksadk/skills/runtime/artifacts.py +39 -0
  431. ksadk/skills/runtime/backends/__init__.py +1 -0
  432. ksadk/skills/runtime/backends/disabled.py +8 -0
  433. ksadk/skills/runtime/backends/e2b.py +168 -0
  434. ksadk/skills/runtime/backends/local.py +95 -0
  435. ksadk/skills/runtime/base.py +103 -0
  436. ksadk/skills/runtime/executor.py +219 -0
  437. ksadk/skills/runtime/factory.py +37 -0
  438. ksadk/skills/runtime/loader.py +131 -0
  439. ksadk/skills/runtime/registry.py +150 -0
  440. ksadk/skills/runtime/request.py +67 -0
  441. ksadk/skills/service_client.py +239 -0
  442. ksadk/skills/service_env.py +58 -0
  443. ksadk/skills/tool_defs.py +221 -0
  444. ksadk/terminal_client.py +69 -0
  445. ksadk/terminal_exec_policy.py +229 -0
  446. ksadk/tools/__init__.py +17 -0
  447. ksadk/tools/gateway.py +230 -0
  448. ksadk/tools/result_budget.py +154 -0
  449. ksadk/toolsets/__init__.py +854 -0
  450. ksadk/toolsets/_langchain.py +11 -0
  451. ksadk/toolsets/platform.py +93 -0
  452. ksadk/toolsets/sandbox.py +310 -0
  453. ksadk/toolsets/skills.py +217 -0
  454. ksadk/toolsets/web.py +266 -0
  455. ksadk/toolsets/workspace.py +917 -0
  456. ksadk/toolsets/workspace_state.py +44 -0
  457. ksadk/tracing/__init__.py +37 -0
  458. ksadk/tracing/exporters/__init__.py +1 -0
  459. ksadk/tracing/exporters/inmemory_exporter.py +116 -0
  460. ksadk/tracing/exporters/langfuse_exporter.py +445 -0
  461. ksadk/tracing/setup.py +892 -0
  462. ksadk/tracing/span_utils.py +114 -0
  463. ksadk/tui/__init__.py +27 -0
  464. ksadk/tui/loop.py +1877 -0
  465. ksadk/tui/stream_render.py +68 -0
  466. ksadk/ui_config.py +168 -0
  467. ksadk/version.py +4 -0
  468. ksadk_runtime_common/__init__.py +20 -0
  469. ksadk_runtime_common/memory_backend/__init__.py +29 -0
  470. ksadk_runtime_common/memory_backend/manifest.py +79 -0
  471. ksadk_runtime_common/memory_backend/providers/__init__.py +6 -0
  472. ksadk_runtime_common/memory_backend/providers/lancedb.py +151 -0
  473. ksadk_runtime_common/memory_backend/providers/mem0.py +74 -0
  474. ksadk_runtime_common/memory_backend/registry.py +56 -0
  475. ksadk_runtime_common/memory_backend/render.py +71 -0
  476. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -0
  477. ksadk_runtime_common/workspace_files/__init__.py +29 -0
  478. ksadk_runtime_common/workspace_files/bootstrap.py +56 -0
  479. ksadk_runtime_common/workspace_files/constants.py +9 -0
  480. ksadk_runtime_common/workspace_files/path_utils.py +71 -0
  481. ksadk_runtime_common/workspace_files/preview.py +96 -0
  482. ksadk_runtime_common/workspace_files/router.py +254 -0
  483. agentengine_sdk_python/__init__.py +0 -3
  484. agentengine_sdk_python-0.6.4.dist-info/METADATA +0 -48
  485. agentengine_sdk_python-0.6.4.dist-info/RECORD +0 -5
  486. agentengine_sdk_python-0.6.4.dist-info/top_level.txt +0 -1
@@ -0,0 +1,359 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from dataclasses import dataclass, field
5
+ from typing import Any, Mapping, Sequence
6
+
7
+ import httpx
8
+
9
+ from ksadk.configs.settings import settings
10
+ from ksadk.conversations.compaction_prompt import (
11
+ build_compaction_prompt_messages,
12
+ extract_summary_text,
13
+ )
14
+ from ksadk.conversations.context import canonical_event_type, extract_event_text, summarize_event_groups
15
+ from ksadk.sessions.base import SessionEvent
16
+
17
+ SUMMARY_VERSION = "v1"
18
+ DEFAULT_COMPACTION_SUMMARY_TIMEOUT_MS = 45_000
19
+ DEFAULT_COMPACTION_SUMMARY_MAX_GROUPS = 12
20
+ SUMMARY_PREFIX = "Earlier conversation summary:"
21
+
22
+ # L4 semantic 熔断:独立计数 semantic LLM 调用失败(不复用 governance compact failure counter,
23
+ # 因为 summarize_compaction 捕获异常后返回 extractive,外层看是成功,governance 不触发)。
24
+ # 超过阈值后直接走 extractive,避免 Claude Code 的"1279 会话连续失败 50+ 次"浪费。
25
+ # 已知局限(有意取舍,对齐 Claude Code 行为):
26
+ # - 默认 0(opt-in),避免 transient 失败永久禁用 semantic;用户显式设 N>0 才启用。
27
+ # - 打开后无 half-open 探测,需进程重启或显式 _reset_semantic_failures 恢复(CC 同样如此)。
28
+ # - 计数为模块级全局,跨 session/model 共享;per-model key 化留作 follow-up(对齐 governance per-session 范式)。
29
+ _semantic_summary_failures: int = 0
30
+
31
+
32
+ def _max_consecutive_semantic_failures() -> int:
33
+ raw = os.environ.get("KSADK_MAX_CONSECUTIVE_SEMANTIC_FAILURES", "0")
34
+ try:
35
+ return max(0, int(raw))
36
+ except (TypeError, ValueError):
37
+ return 0
38
+
39
+
40
+ def _semantic_circuit_open() -> bool:
41
+ """semantic 熔断是否打开(超阈值则跳过 LLM 直接走 extractive)。0 = 禁用熔断。"""
42
+ threshold = _max_consecutive_semantic_failures()
43
+ if threshold <= 0:
44
+ return False
45
+ return _semantic_summary_failures >= threshold
46
+
47
+
48
+ def _record_semantic_failure() -> None:
49
+ global _semantic_summary_failures
50
+ _semantic_summary_failures += 1
51
+
52
+
53
+ def _reset_semantic_failures() -> None:
54
+ global _semantic_summary_failures
55
+ _semantic_summary_failures = 0
56
+
57
+
58
+ @dataclass
59
+ class CompactionSummaryResult:
60
+ """一次 checkpoint 摘要的标准结果。"""
61
+
62
+ summary_text: str
63
+ summary_strategy: str
64
+ summary_version: str = SUMMARY_VERSION
65
+ summary_model: str = ""
66
+ summary_usage: dict[str, Any] = field(default_factory=dict)
67
+ fallback_reason: str | None = None
68
+
69
+
70
+ class SummaryModelClient:
71
+ """独立的摘要模型客户端。
72
+
73
+ 注意这里故意不复用 agent runner:
74
+ - runner 的职责是执行用户 agent;
75
+ - 摘要器的职责是平台内部的 context compaction。
76
+ 两者拆开后,失败隔离和后续替换模型都会更清晰。
77
+ """
78
+
79
+ def __init__(
80
+ self,
81
+ *,
82
+ api_base: str | None = None,
83
+ api_key: str | None = None,
84
+ ):
85
+ self.api_base = str(api_base or settings.model.api_base or "").rstrip("/")
86
+ self.api_key = str(api_key or settings.model.api_key or "").strip()
87
+
88
+ @property
89
+ def is_available(self) -> bool:
90
+ return bool(self.api_base and self.api_key)
91
+
92
+ def _chat_completions_url(self) -> str:
93
+ if self.api_base.endswith("/v1"):
94
+ return f"{self.api_base}/chat/completions"
95
+ return f"{self.api_base}/v1/chat/completions"
96
+
97
+ async def summarize(
98
+ self,
99
+ *,
100
+ model: str,
101
+ messages: Sequence[dict[str, str]],
102
+ timeout_ms: int,
103
+ ) -> tuple[str, dict[str, Any]]:
104
+ if not self.is_available:
105
+ raise RuntimeError("summary model client is not configured")
106
+ if not model:
107
+ raise RuntimeError("summary model is not configured")
108
+
109
+ headers = {
110
+ "Content-Type": "application/json",
111
+ "Authorization": f"Bearer {self.api_key}",
112
+ }
113
+ payload = {
114
+ "model": model,
115
+ "messages": list(messages),
116
+ "stream": False,
117
+ "temperature": 0,
118
+ }
119
+ timeout_seconds = max(1.0, float(timeout_ms) / 1000.0)
120
+ async with httpx.AsyncClient(timeout=timeout_seconds) as client:
121
+ response = await client.post(self._chat_completions_url(), headers=headers, json=payload)
122
+ response.raise_for_status()
123
+ data = response.json()
124
+
125
+ choices = data.get("choices") or []
126
+ message = choices[0].get("message") if choices else {}
127
+ content = message.get("content") if isinstance(message, Mapping) else ""
128
+ if isinstance(content, list):
129
+ fragments: list[str] = []
130
+ for item in content:
131
+ if isinstance(item, Mapping) and item.get("text"):
132
+ fragments.append(str(item["text"]))
133
+ content = "\n".join(fragment for fragment in fragments if fragment)
134
+ text = str(content or "").strip()
135
+ if not text:
136
+ raise RuntimeError("summary model returned empty content")
137
+ return text, dict(data.get("usage") or {})
138
+
139
+
140
+ def resolve_summary_model_client() -> SummaryModelClient:
141
+ return SummaryModelClient()
142
+
143
+
144
+ def _ensure_summary_prefix(summary_text: str) -> str:
145
+ text = str(summary_text or "").strip()
146
+ if not text or text.startswith(SUMMARY_PREFIX):
147
+ return text
148
+ return f"{SUMMARY_PREFIX}\n{text}"
149
+
150
+
151
+ def _env_truthy(name: str) -> bool:
152
+ value = str(os.getenv(name, "")).strip().lower()
153
+ return value in {"1", "true", "yes", "on"}
154
+
155
+
156
+ def semantic_compaction_disabled() -> bool:
157
+ return _env_truthy("COMPACTION_DISABLE_SEMANTIC")
158
+
159
+
160
+ def get_summary_timeout_ms() -> int:
161
+ raw = os.getenv("COMPACTION_SUMMARY_TIMEOUT_MS", "").strip()
162
+ try:
163
+ return max(1_000, int(raw))
164
+ except (TypeError, ValueError):
165
+ return DEFAULT_COMPACTION_SUMMARY_TIMEOUT_MS
166
+
167
+
168
+ def get_summary_max_groups() -> int:
169
+ raw = os.getenv("COMPACTION_SUMMARY_MAX_GROUPS", "").strip()
170
+ try:
171
+ return max(1, int(raw))
172
+ except (TypeError, ValueError):
173
+ return DEFAULT_COMPACTION_SUMMARY_MAX_GROUPS
174
+
175
+
176
+ def resolve_summary_model(current_model: str | None) -> str:
177
+ override = str(os.getenv("COMPACTION_SUMMARY_MODEL", "")).strip()
178
+ if override:
179
+ return override
180
+ if current_model:
181
+ return str(current_model)
182
+ return str(settings.model.model_name or "")
183
+
184
+
185
+ def find_pinned_group_indexes(groups: Sequence[Sequence[SessionEvent]]) -> set[int]:
186
+ """找出不能被 compact 的轮次。
187
+
188
+ 当前先严格保护两类未完成状态:
189
+ 1. approval_request 尚未收到 approval_response
190
+ 2. tool_call 尚未看到 tool_result
191
+ """
192
+
193
+ pending_approval_groups: list[int] = []
194
+ pending_tool_groups: list[int] = []
195
+ for index, group in enumerate(groups):
196
+ for event in group:
197
+ event_type = canonical_event_type(
198
+ event.event_type,
199
+ author=event.author,
200
+ role=str((event.content or {}).get("role") or ""),
201
+ )
202
+ if event_type == "approval_request":
203
+ pending_approval_groups.append(index)
204
+ continue
205
+ if event_type == "approval_response" and pending_approval_groups:
206
+ pending_approval_groups.pop()
207
+ continue
208
+ if event_type == "tool_call":
209
+ pending_tool_groups.append(index)
210
+ continue
211
+ if event_type == "tool_result" and pending_tool_groups:
212
+ pending_tool_groups.pop()
213
+ return set(pending_approval_groups + pending_tool_groups)
214
+
215
+
216
+ def extract_pinned_state(groups: Sequence[Sequence[SessionEvent]]) -> dict[str, Any]:
217
+ """提取必须在 checkpoint 里显式保留的状态。"""
218
+
219
+ pending_approvals: list[str] = []
220
+ pending_tools: list[str] = []
221
+ attachment_refs: list[str] = []
222
+ current_user_goal = ""
223
+
224
+ for group in groups:
225
+ for event in group:
226
+ event_type = canonical_event_type(
227
+ event.event_type,
228
+ author=event.author,
229
+ role=str((event.content or {}).get("role") or ""),
230
+ )
231
+ text = extract_event_text(event)
232
+ if event_type == "approval_request" and text:
233
+ pending_approvals.append(text)
234
+ elif event_type == "approval_response" and pending_approvals:
235
+ pending_approvals.pop()
236
+ elif event_type == "tool_call" and text:
237
+ pending_tools.append(text)
238
+ elif event_type == "tool_result" and pending_tools:
239
+ pending_tools.pop()
240
+ elif event_type == "attachment_ref":
241
+ attachment_refs.append(text)
242
+ elif event_type == "user_message" and text:
243
+ current_user_goal = text
244
+ for attachment in (event.metadata or {}).get("attachments") or []:
245
+ if not isinstance(attachment, Mapping):
246
+ continue
247
+ label = str(
248
+ attachment.get("display_name")
249
+ or attachment.get("file_uri")
250
+ or attachment.get("storage_path")
251
+ or ""
252
+ ).strip()
253
+ if label:
254
+ attachment_refs.append(label)
255
+
256
+ unique_attachments: list[str] = []
257
+ for item in attachment_refs:
258
+ normalized = str(item or "").strip()
259
+ if normalized and normalized not in unique_attachments:
260
+ unique_attachments.append(normalized)
261
+
262
+ return {
263
+ "pending_approvals": pending_approvals,
264
+ "pending_tools": pending_tools,
265
+ "attachment_refs": unique_attachments[-5:],
266
+ "current_user_goal": current_user_goal,
267
+ }
268
+
269
+
270
+ def _build_semantic_input(
271
+ *,
272
+ previous_summary: str,
273
+ groups_to_compact: Sequence[Sequence[SessionEvent]],
274
+ pinned_state: Mapping[str, Any],
275
+ model_metadata: Mapping[str, Any] | None,
276
+ ) -> tuple[str, list[list[SessionEvent]]]:
277
+ max_groups = get_summary_max_groups()
278
+ selected_groups = [list(group) for group in groups_to_compact]
279
+ merged_previous_summary = previous_summary.strip()
280
+ if len(selected_groups) > max_groups:
281
+ skipped_groups = selected_groups[:-max_groups]
282
+ selected_groups = selected_groups[-max_groups:]
283
+ skipped_summary = summarize_event_groups(skipped_groups, previous_summary=merged_previous_summary)
284
+ merged_previous_summary = skipped_summary
285
+ return merged_previous_summary, selected_groups
286
+
287
+
288
+ async def summarize_compaction(
289
+ *,
290
+ groups_to_compact: Sequence[Sequence[SessionEvent]],
291
+ previous_summary: str,
292
+ pinned_state: Mapping[str, Any],
293
+ model_metadata: Mapping[str, Any] | None,
294
+ model: str | None,
295
+ ) -> CompactionSummaryResult:
296
+ """语义摘要优先,失败后自动回退到 extractive。"""
297
+
298
+ fallback_summary = summarize_event_groups(list(groups_to_compact), previous_summary=previous_summary)
299
+ if semantic_compaction_disabled():
300
+ return CompactionSummaryResult(
301
+ summary_text=fallback_summary,
302
+ summary_strategy="extractive",
303
+ fallback_reason="semantic summarizer disabled",
304
+ )
305
+
306
+ # L4 semantic 熔断:连续失败超阈值则跳过 LLM 直接走 extractive,直到进程重启或显式 reset。
307
+ if _semantic_circuit_open():
308
+ return CompactionSummaryResult(
309
+ summary_text=fallback_summary,
310
+ summary_strategy="extractive",
311
+ fallback_reason="semantic_circuit_open",
312
+ )
313
+
314
+ summary_model = resolve_summary_model(model)
315
+ client = resolve_summary_model_client()
316
+ if not client.is_available:
317
+ return CompactionSummaryResult(
318
+ summary_text=fallback_summary,
319
+ summary_strategy="extractive",
320
+ fallback_reason="summary model client is not configured",
321
+ )
322
+
323
+ try:
324
+ merged_previous_summary, selected_groups = _build_semantic_input(
325
+ previous_summary=previous_summary,
326
+ groups_to_compact=groups_to_compact,
327
+ pinned_state=pinned_state,
328
+ model_metadata=model_metadata,
329
+ )
330
+ prompt_messages = build_compaction_prompt_messages(
331
+ previous_summary=merged_previous_summary,
332
+ groups_to_compact=selected_groups,
333
+ pinned_state=pinned_state,
334
+ model_metadata=model_metadata,
335
+ )
336
+ raw_text, usage = await client.summarize(
337
+ model=summary_model,
338
+ messages=prompt_messages,
339
+ timeout_ms=get_summary_timeout_ms(),
340
+ )
341
+ summary_text = extract_summary_text(raw_text)
342
+ if not summary_text:
343
+ raise RuntimeError("summary model returned empty <summary> block")
344
+ # LLM 调用成功,清零 semantic 失败计数。
345
+ _reset_semantic_failures()
346
+ return CompactionSummaryResult(
347
+ summary_text=_ensure_summary_prefix(summary_text),
348
+ summary_strategy="semantic",
349
+ summary_model=summary_model,
350
+ summary_usage=usage,
351
+ )
352
+ except Exception as exc:
353
+ # LLM 调用失败(非 extractive 主动选择),记录 semantic 失败用于熔断判定。
354
+ _record_semantic_failure()
355
+ return CompactionSummaryResult(
356
+ summary_text=fallback_summary,
357
+ summary_strategy="extractive",
358
+ fallback_reason=str(exc) or exc.__class__.__name__,
359
+ )
@@ -0,0 +1,254 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import re
5
+ from typing import Any, Sequence
6
+
7
+ import httpx
8
+
9
+ from ksadk.configs.settings import settings
10
+ from ksadk.conversations.model_options import model_options_for_chat_completions
11
+ from ksadk.conversations.reasoning_markup import strip_reasoning_markup
12
+
13
+ DEFAULT_SESSION_TITLE_TIMEOUT_MS = 8_000
14
+ SESSION_TITLE_MAX_CHARS = 24
15
+ HEURISTIC_SESSION_TITLE_SOURCE = "heuristic"
16
+ SESSION_TITLE_SOURCE_SCAN_LIMIT = 8_000
17
+
18
+ _TITLE_PROMPT = (
19
+ "你是会话标题生成器。"
20
+ "请基于首轮用户问题和首轮助手回答,生成一个适合左侧会话列表的中文标题。\n"
21
+ "要求:\n"
22
+ "1. 优先输出 4 到 8 个汉字,最多 12 个汉字\n"
23
+ "2. 输出主题名或任务名,不要直接复述整句提问\n"
24
+ "3. 去掉“你好”“请”“帮我”“看看这个”等口语前缀和文件名\n"
25
+ "4. 如果是自我介绍/能力说明,改写成“能力介绍”“功能概览”这类主题名\n"
26
+ "5. 如果是在看图或看附件,改写成“架构图分析”“附件分析”“简历分析”这类主题名\n"
27
+ "6. 不要标点、引号、书名号、解释,只输出标题本身\n"
28
+ "示例:\n"
29
+ "- 你好,请介绍一下你自己 -> 招聘助手能力\n"
30
+ "- 看看这个上传文件,这里还有他画的架构图 -> 架构图分析"
31
+ )
32
+
33
+ _SELF_INTRO_RE = re.compile(r"(介绍(?:一下)?你自己|你是谁|你的能力|你能做什么|自我介绍)")
34
+ _ARCH_RE = re.compile(r"(架构图|架构|微服务|系统设计|服务拓扑)")
35
+ _RECRUIT_RE = re.compile(r"(简历|候选人|面试|招聘|职位|jd\b)")
36
+ _FILE_RE = re.compile(r"(上传文件|上传图片|附件|file|pdf|png|jpg|jpeg)")
37
+ _ANALYZE_RE = re.compile(r"(分析|解读|评审|review|总结|说明|看下|看看|评估)")
38
+ _PROMPT_FILLERS_RE = re.compile(
39
+ r"^(你好|您好|请问|请|帮我|麻烦|看看这个|看看|看下|分析一下|分析|介绍一下|介绍|解释一下|解释|总结一下|总结|直接开始分析吧|直接开始|这里还有|这边有|给我看下)+",
40
+ )
41
+ _FILE_MARKER_WORDS = ("上传文件", "上传文件引用", "附件")
42
+
43
+
44
+ def _replace_file_markup(text: str) -> str:
45
+ segments: list[str] = []
46
+ for line in str(text or "").splitlines():
47
+ stripped = line.lstrip("#").strip()
48
+ if stripped.startswith("附件") and any(sep in stripped for sep in ("-", ":", ":")):
49
+ segments.append(" 附件 ")
50
+ continue
51
+
52
+ current = line
53
+ while "[" in current and "]" in current:
54
+ start = current.find("[")
55
+ end = current.find("]", start + 1)
56
+ if end < 0:
57
+ break
58
+ bracketed = current[start : end + 1]
59
+ if any(word in bracketed for word in _FILE_MARKER_WORDS):
60
+ current = f"{current[:start]} 附件 {current[end + 1:]}"
61
+ else:
62
+ break
63
+ segments.append(current)
64
+ return "\n".join(segments)
65
+
66
+
67
+ def _normalize_source_text(text: str) -> str:
68
+ value = strip_reasoning_markup(str(text or "")[:SESSION_TITLE_SOURCE_SCAN_LIMIT]).strip()
69
+ if not value:
70
+ return ""
71
+ value = _replace_file_markup(value)
72
+ value = re.sub(r"\s+", " ", value)
73
+ return value.strip()
74
+
75
+
76
+ def _sanitize_title(text: str) -> str:
77
+ value = strip_reasoning_markup(str(text or "")).strip()
78
+ if not value:
79
+ return ""
80
+ value = value.splitlines()[0].strip()
81
+ value = re.sub(r"^标题[::]\s*", "", value)
82
+ value = value.strip("`'\"“”‘’《》[]()()")
83
+ value = re.sub(r"[。!?!?;;::,,、]+$", "", value).strip()
84
+ value = " ".join(value.split())
85
+ if len(value) > SESSION_TITLE_MAX_CHARS:
86
+ value = value[:SESSION_TITLE_MAX_CHARS].rstrip()
87
+ return value
88
+
89
+
90
+ def _normalize_compare_text(text: str) -> str:
91
+ value = _normalize_source_text(text)
92
+ value = _PROMPT_FILLERS_RE.sub("", value).strip()
93
+ value = re.sub(r"[^\w\u4e00-\u9fff]+", "", value)
94
+ return value.lower()
95
+
96
+
97
+ def _truncate_title(text: str) -> str:
98
+ value = strip_reasoning_markup(str(text or "")).strip()
99
+ if len(value) <= SESSION_TITLE_MAX_CHARS:
100
+ return value
101
+ return value[:SESSION_TITLE_MAX_CHARS].rstrip()
102
+
103
+
104
+ def build_fallback_title(text: str) -> str:
105
+ value = _normalize_source_text(text)
106
+ value = _replace_file_markup(value)
107
+ value = re.sub(r"\s+", " ", value).strip()
108
+ return _truncate_title(value)
109
+
110
+
111
+ def build_heuristic_title(*, first_prompt: str, assistant_text: str) -> str:
112
+ prompt = _normalize_source_text(first_prompt)
113
+ assistant = _normalize_source_text(assistant_text)
114
+ combined = f"{prompt} {assistant}".strip()
115
+ prompt_lower = prompt.lower()
116
+ combined_lower = combined.lower()
117
+
118
+ if _SELF_INTRO_RE.search(prompt):
119
+ if _RECRUIT_RE.search(combined_lower):
120
+ return "招聘助手能力"
121
+ return "Agent能力介绍"
122
+
123
+ if _ARCH_RE.search(combined):
124
+ return "架构图分析" if _ANALYZE_RE.search(combined) or assistant else "架构讨论"
125
+
126
+ if _RECRUIT_RE.search(combined_lower):
127
+ if "简历" in combined_lower or "候选人" in combined_lower:
128
+ return "简历分析"
129
+ if "面试" in combined_lower and (_ANALYZE_RE.search(combined) or _FILE_RE.search(combined_lower)):
130
+ return "面试分析"
131
+
132
+ if _FILE_RE.search(combined_lower):
133
+ return "附件分析" if _ANALYZE_RE.search(combined) or assistant else "附件内容"
134
+
135
+ candidate = _PROMPT_FILLERS_RE.sub("", prompt).strip(",,。!?!?;;:: ")
136
+ candidate = re.sub(r"^(这个|这份|这张|这段|这个上传文件|上传文件|附件)\s*", "", candidate)
137
+ candidate = candidate.strip(",,。!?!?;;:: ")
138
+ if _SELF_INTRO_RE.search(candidate):
139
+ return "自我介绍"
140
+ if candidate.endswith("架构图") or candidate == "架构图":
141
+ return "架构图分析"
142
+ if _FILE_RE.search(candidate.lower()):
143
+ return "附件分析"
144
+ return _truncate_title(candidate)
145
+
146
+
147
+ def is_low_quality_title(title: str, *, first_prompt: str) -> bool:
148
+ cleaned_title = _sanitize_title(title)
149
+ if not cleaned_title:
150
+ return True
151
+ prompt_norm = _normalize_compare_text(first_prompt)
152
+ title_norm = _normalize_compare_text(cleaned_title)
153
+ if not title_norm:
154
+ return True
155
+ if title_norm == prompt_norm:
156
+ return True
157
+ if prompt_norm.startswith(title_norm) and len(prompt_norm) - len(title_norm) <= 4:
158
+ return True
159
+ if title_norm.startswith(("你好", "请", "帮我", "看看这个")):
160
+ return True
161
+ return False
162
+
163
+
164
+ def resolve_session_title_model(current_model: str | None) -> str:
165
+ override = str(os.getenv("SESSION_TITLE_MODEL", "")).strip()
166
+ if override:
167
+ return override
168
+ if current_model:
169
+ return str(current_model).strip()
170
+ return str(settings.model.model_name or "").strip()
171
+
172
+
173
+ def build_session_title_messages(*, first_prompt: str, assistant_text: str) -> list[dict[str, str]]:
174
+ assistant_excerpt = strip_reasoning_markup(str(assistant_text or "")).strip()
175
+ if len(assistant_excerpt) > 240:
176
+ assistant_excerpt = assistant_excerpt[:240].rstrip() + "…"
177
+ return [
178
+ {"role": "system", "content": _TITLE_PROMPT},
179
+ {
180
+ "role": "user",
181
+ "content": (
182
+ f"首轮用户问题:\n{str(first_prompt or '').strip()}\n\n"
183
+ f"首轮助手回答:\n{assistant_excerpt}"
184
+ ),
185
+ },
186
+ ]
187
+
188
+
189
+ class SessionTitleClient:
190
+ def __init__(
191
+ self,
192
+ *,
193
+ api_base: str | None = None,
194
+ api_key: str | None = None,
195
+ ):
196
+ self.api_base = str(api_base or settings.model.api_base or "").rstrip("/")
197
+ self.api_key = str(api_key or settings.model.api_key or "").strip()
198
+
199
+ @property
200
+ def is_available(self) -> bool:
201
+ return bool(self.api_base and self.api_key)
202
+
203
+ def _chat_completions_url(self) -> str:
204
+ if self.api_base.endswith("/v1"):
205
+ return f"{self.api_base}/chat/completions"
206
+ return f"{self.api_base}/v1/chat/completions"
207
+
208
+ async def generate_title(
209
+ self,
210
+ *,
211
+ model: str,
212
+ messages: Sequence[dict[str, str]],
213
+ timeout_ms: int = DEFAULT_SESSION_TITLE_TIMEOUT_MS,
214
+ ) -> tuple[str, dict[str, Any]]:
215
+ if not self.is_available:
216
+ raise RuntimeError("session title client is not configured")
217
+ if not model:
218
+ raise RuntimeError("session title model is not configured")
219
+
220
+ headers = {
221
+ "Content-Type": "application/json",
222
+ "Authorization": f"Bearer {self.api_key}",
223
+ }
224
+ payload = {
225
+ "model": model,
226
+ "messages": list(messages),
227
+ "stream": False,
228
+ "temperature": 0,
229
+ **model_options_for_chat_completions({"thinking": {"type": "disabled"}}),
230
+ }
231
+ timeout_seconds = max(1.0, float(timeout_ms) / 1000.0)
232
+ async with httpx.AsyncClient(timeout=timeout_seconds) as client:
233
+ response = await client.post(self._chat_completions_url(), headers=headers, json=payload)
234
+ response.raise_for_status()
235
+ data = response.json()
236
+
237
+ choices = data.get("choices") or []
238
+ message = choices[0].get("message") if choices else {}
239
+ content = message.get("content") if isinstance(message, dict) else ""
240
+ if isinstance(content, list):
241
+ fragments: list[str] = []
242
+ for item in content:
243
+ if isinstance(item, dict) and item.get("text"):
244
+ fragments.append(str(item["text"]))
245
+ content = "\n".join(fragment for fragment in fragments if fragment)
246
+
247
+ title = _sanitize_title(str(content or ""))
248
+ if not title:
249
+ raise RuntimeError("session title model returned empty content")
250
+ return title, dict(data.get("usage") or {})
251
+
252
+
253
+ def resolve_session_title_client() -> SessionTitleClient:
254
+ return SessionTitleClient()
@@ -0,0 +1,83 @@
1
+ """
2
+ 部署模块
3
+
4
+ 支持多种部署目标:
5
+ - docker: 本地 Docker 容器
6
+ - k8s: Kubernetes 集群
7
+ - serverless: 金山云 Serverless 计算引擎
8
+ """
9
+
10
+ from ksadk.deployment.base import (
11
+ BaseDeployProvider,
12
+ DeployTarget,
13
+ DeployResult,
14
+ DeployStatus,
15
+ PackageInfo,
16
+ ResourceSpec,
17
+ ScalingConfig,
18
+ NetworkConfig,
19
+ )
20
+ from ksadk.deployment.registry import DeployProviderRegistry
21
+
22
+ # 导入并注册所有 Provider
23
+ from ksadk.deployment import providers
24
+
25
+
26
+ class DeploymentManager:
27
+ """部署管理器 - 统一入口
28
+
29
+ 使用方式:
30
+ manager = DeploymentManager()
31
+ provider = manager.get_provider("docker")
32
+ result = await provider.deploy(package_info, target)
33
+ """
34
+
35
+ @staticmethod
36
+ def get_provider(name: str, config: dict = None) -> BaseDeployProvider:
37
+ """获取部署 Provider
38
+
39
+ Args:
40
+ name: Provider 名称 (docker, k8s, serverless)
41
+ config: Provider 配置
42
+
43
+ Returns:
44
+ Provider 实例
45
+ """
46
+ return DeployProviderRegistry.get(name, config)
47
+
48
+ @staticmethod
49
+ def list_providers() -> list:
50
+ """列出所有可用 Provider"""
51
+ return DeployProviderRegistry.get_provider_info()
52
+
53
+ @staticmethod
54
+ def has_provider(name: str) -> bool:
55
+ """检查 Provider 是否存在"""
56
+ return DeployProviderRegistry.has_provider(name)
57
+
58
+ # 向后兼容: create() 方法
59
+ @classmethod
60
+ def create(cls, target: str) -> DeployTarget:
61
+ """创建部署目标
62
+
63
+ Args:
64
+ target: 部署目标 (docker, k8s, serverless)
65
+
66
+ Returns:
67
+ 部署目标实例
68
+ """
69
+ return cls.get_provider(target)
70
+
71
+
72
+ __all__ = [
73
+ "DeploymentManager",
74
+ "BaseDeployProvider",
75
+ "DeployTarget",
76
+ "DeployResult",
77
+ "DeployStatus",
78
+ "PackageInfo",
79
+ "ResourceSpec",
80
+ "ScalingConfig",
81
+ "NetworkConfig",
82
+ "DeployProviderRegistry",
83
+ ]