agentengine-sdk-python 0.6.2__py3-none-any.whl → 0.6.9__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 (490) hide show
  1. agentengine_sdk_python-0.6.9.dist-info/METADATA +179 -0
  2. agentengine_sdk_python-0.6.9.dist-info/RECORD +487 -0
  3. {agentengine_sdk_python-0.6.2.dist-info → agentengine_sdk_python-0.6.9.dist-info}/WHEEL +1 -1
  4. agentengine_sdk_python-0.6.9.dist-info/entry_points.txt +3 -0
  5. agentengine_sdk_python-0.6.9.dist-info/licenses/LICENSE +175 -0
  6. agentengine_sdk_python-0.6.9.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 +2227 -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 +2277 -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 +1259 -0
  46. ksadk/cli/cmd_invoke.py +1336 -0
  47. ksadk/cli/cmd_launch.py +564 -0
  48. ksadk/cli/cmd_mcp.py +1174 -0
  49. ksadk/cli/cmd_model.py +302 -0
  50. ksadk/cli/cmd_openclaw.py +3918 -0
  51. ksadk/cli/cmd_run.py +232 -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 +410 -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 +342 -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/model_context.py +360 -0
  83. ksadk/conversations/model_options.py +136 -0
  84. ksadk/conversations/normalize.py +446 -0
  85. ksadk/conversations/reasoning_markup.py +91 -0
  86. ksadk/conversations/run_kinds.py +61 -0
  87. ksadk/conversations/run_status.py +53 -0
  88. ksadk/conversations/runtime.py +5208 -0
  89. ksadk/conversations/semantic_summary.py +359 -0
  90. ksadk/conversations/session_title.py +254 -0
  91. ksadk/deployment/__init__.py +83 -0
  92. ksadk/deployment/agent_access.py +226 -0
  93. ksadk/deployment/base.py +229 -0
  94. ksadk/deployment/manager.py +332 -0
  95. ksadk/deployment/providers/__init__.py +10 -0
  96. ksadk/deployment/providers/serverless.py +1105 -0
  97. ksadk/deployment/registry.py +120 -0
  98. ksadk/deployment/state.py +78 -0
  99. ksadk/deployment/ui_config.py +21 -0
  100. ksadk/detection/__init__.py +7 -0
  101. ksadk/detection/detector.py +431 -0
  102. ksadk/detection/mcp_detector.py +250 -0
  103. ksadk/hermes_terminal.py +467 -0
  104. ksadk/identity/__init__.py +17 -0
  105. ksadk/identity/resolver.py +385 -0
  106. ksadk/knowledge_base/__init__.py +62 -0
  107. ksadk/knowledge_base/adk_tool.py +47 -0
  108. ksadk/knowledge_base/client.py +297 -0
  109. ksadk/knowledge_base/langchain_tool.py +55 -0
  110. ksadk/knowledge_base/service.py +66 -0
  111. ksadk/knowledge_base/tool.py +50 -0
  112. ksadk/markdown.py +169 -0
  113. ksadk/mcp_runtime/__init__.py +231 -0
  114. ksadk/memory/__init__.py +57 -0
  115. ksadk/memory/adk/__init__.py +51 -0
  116. ksadk/memory/adk/backends/__init__.py +5 -0
  117. ksadk/memory/adk/backends/base_ltm_backend.py +52 -0
  118. ksadk/memory/adk/backends/http_ltm_backend.py +183 -0
  119. ksadk/memory/adk/backends/inmemory_ltm_backend.py +96 -0
  120. ksadk/memory/adk/backends/sdk_ltm_backend.py +456 -0
  121. ksadk/memory/adk/long_term_memory.py +273 -0
  122. ksadk/memory/adk/short_term_memory.py +289 -0
  123. ksadk/memory/adk_tool.py +31 -0
  124. ksadk/memory/backends/__init__.py +6 -0
  125. ksadk/memory/backends/base.py +103 -0
  126. ksadk/memory/backends/memory.py +112 -0
  127. ksadk/memory/backends/redis.py +146 -0
  128. ksadk/memory/langchain_tool.py +39 -0
  129. ksadk/memory/ltm_backend_factory.py +24 -0
  130. ksadk/memory/manager.py +215 -0
  131. ksadk/memory/service.py +172 -0
  132. ksadk/memory/tool.py +96 -0
  133. ksadk/model_policy.py +223 -0
  134. ksadk/openclaw_gateway.py +378 -0
  135. ksadk/runners/__init__.py +8 -0
  136. ksadk/runners/adk_runner.py +1135 -0
  137. ksadk/runners/base_runner.py +305 -0
  138. ksadk/runners/deepagents_runner.py +13 -0
  139. ksadk/runners/factory.py +73 -0
  140. ksadk/runners/langchain_runner.py +539 -0
  141. ksadk/runners/langgraph_runner.py +852 -0
  142. ksadk/runners/patch_langchain.py +187 -0
  143. ksadk/runners/remote_runner.py +667 -0
  144. ksadk/runners/usage_accumulator.py +38 -0
  145. ksadk/runners/utils/__init__.py +19 -0
  146. ksadk/runners/utils/langfuse.py +230 -0
  147. ksadk/runners/utils/loader.py +62 -0
  148. ksadk/runtime_context.py +166 -0
  149. ksadk/runtime_state.py +25 -0
  150. ksadk/sandbox/__init__.py +28 -0
  151. ksadk/sandbox/backends/__init__.py +9 -0
  152. ksadk/sandbox/backends/e2b.py +154 -0
  153. ksadk/sandbox/backends/local_process.py +131 -0
  154. ksadk/sandbox/base.py +101 -0
  155. ksadk/sandbox/factory.py +53 -0
  156. ksadk/sandbox/registry.py +187 -0
  157. ksadk/server/__init__.py +7 -0
  158. ksadk/server/api_models.py +73 -0
  159. ksadk/server/app.py +3789 -0
  160. ksadk/server/static/assets/ArtifactsPanel-C0meuOdi.js +1 -0
  161. ksadk/server/static/assets/CodeBlock-BbI4HPtJ.js +9 -0
  162. ksadk/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  163. ksadk/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  164. ksadk/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  165. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  166. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  167. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  168. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  169. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  170. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  171. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  172. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  173. ksadk/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  174. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  175. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  176. ksadk/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  177. ksadk/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  178. ksadk/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  179. ksadk/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  180. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  181. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  182. ksadk/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  183. ksadk/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  184. ksadk/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  185. ksadk/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  186. ksadk/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  187. ksadk/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  188. ksadk/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  189. ksadk/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  190. ksadk/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  191. ksadk/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  192. ksadk/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  193. ksadk/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  194. ksadk/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  195. ksadk/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  196. ksadk/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  197. ksadk/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  198. ksadk/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  199. ksadk/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  200. ksadk/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  201. ksadk/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  202. ksadk/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  203. ksadk/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  204. ksadk/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  205. ksadk/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  206. ksadk/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  207. ksadk/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  208. ksadk/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  209. ksadk/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  210. ksadk/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  211. ksadk/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  212. ksadk/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  213. ksadk/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  214. ksadk/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  215. ksadk/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  216. ksadk/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  217. ksadk/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  218. ksadk/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  219. ksadk/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  220. ksadk/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  221. ksadk/server/static/assets/MathMessageMarkdown-DMLQYoLp.js +8 -0
  222. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +1 -0
  223. ksadk/server/static/assets/MermaidBlock-DCR8WZ17.js +303 -0
  224. ksadk/server/static/assets/NativeTerminalPanel-CHOd7Rch.css +1 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-CKUvWhUz.js +1 -0
  226. ksadk/server/static/assets/addon-fit-DthTIhi3.js +1 -0
  227. ksadk/server/static/assets/apl-CnwPGSsG.js +1 -0
  228. ksadk/server/static/assets/arc-bj2rZnP5.js +1 -0
  229. ksadk/server/static/assets/architecture-7EHR7CIX-Cr6Xz1_c.js +1 -0
  230. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-2u1ltDIj.js +36 -0
  231. ksadk/server/static/assets/asciiarmor-qTkVPQu6.js +1 -0
  232. ksadk/server/static/assets/asn1-Dr8qZg38.js +1 -0
  233. ksadk/server/static/assets/asterisk-Bja0s6e1.js +1 -0
  234. ksadk/server/static/assets/blockDiagram-GPEHLZMM-D6fvdK20.js +132 -0
  235. ksadk/server/static/assets/brainfuck-D5EjA2JK.js +1 -0
  236. ksadk/server/static/assets/c4Diagram-AAUBKEIU-BK82L5n5.js +10 -0
  237. ksadk/server/static/assets/channel-BSSOwFIb.js +1 -0
  238. ksadk/server/static/assets/chunk-2J33WTMH-DLVdkeyQ.js +1 -0
  239. ksadk/server/static/assets/chunk-4BX2VUAB-BbwsYcbW.js +1 -0
  240. ksadk/server/static/assets/chunk-55IACEB6-DOairxzw.js +1 -0
  241. ksadk/server/static/assets/chunk-727SXJPM-hCO487gs.js +206 -0
  242. ksadk/server/static/assets/chunk-AQP2D5EJ-XU8vDOuG.js +231 -0
  243. ksadk/server/static/assets/chunk-FMBD7UC4-PrapyfMu.js +15 -0
  244. ksadk/server/static/assets/chunk-ND2GUHAM-CboKhTZ3.js +1 -0
  245. ksadk/server/static/assets/chunk-QZHKN3VN-XXpdiwUL.js +1 -0
  246. ksadk/server/static/assets/classDiagram-4FO5ZUOK-C5HvGiyK.js +1 -0
  247. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-C5HvGiyK.js +1 -0
  248. ksadk/server/static/assets/clike-DHH8Ad3s.js +1 -0
  249. ksadk/server/static/assets/clojure-BflJGmDX.js +1 -0
  250. ksadk/server/static/assets/cmake-CyVbuzPu.js +1 -0
  251. ksadk/server/static/assets/cobol-B_OZ4V-R.js +1 -0
  252. ksadk/server/static/assets/coffeescript-B2pKbFk8.js +1 -0
  253. ksadk/server/static/assets/commonlisp-CcllspGY.js +1 -0
  254. ksadk/server/static/assets/cose-bilkent-S5V4N54A-_N8bJ-EU.js +1 -0
  255. ksadk/server/static/assets/crystal-M5-qzICs.js +1 -0
  256. ksadk/server/static/assets/css-CYpP4FRV.js +1 -0
  257. ksadk/server/static/assets/cypher-p9eYesGn.js +1 -0
  258. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +321 -0
  259. ksadk/server/static/assets/d-BhMjBjQP.js +1 -0
  260. ksadk/server/static/assets/dagre-BM42HDAG-FoDlo5J2.js +4 -0
  261. ksadk/server/static/assets/dagre-Bx709z4p.js +1 -0
  262. ksadk/server/static/assets/defaultLocale-C8Fc0cco.js +1 -0
  263. ksadk/server/static/assets/diagram-2AECGRRQ-BBp6ebBw.js +43 -0
  264. ksadk/server/static/assets/diagram-5GNKFQAL-CqOvG1PR.js +10 -0
  265. ksadk/server/static/assets/diagram-KO2AKTUF-O9T3t6ba.js +3 -0
  266. ksadk/server/static/assets/diagram-LMA3HP47-CGG8ekBO.js +24 -0
  267. ksadk/server/static/assets/diagram-OG6HWLK6-4BmH1EEg.js +24 -0
  268. ksadk/server/static/assets/diff-ChtP43wD.js +1 -0
  269. ksadk/server/static/assets/dist-6kSZvCZh.js +1 -0
  270. ksadk/server/static/assets/dist-B67uF2uK.js +1 -0
  271. ksadk/server/static/assets/dist-BMKM66B4.js +1 -0
  272. ksadk/server/static/assets/dist-BVzcWa6D.js +1 -0
  273. ksadk/server/static/assets/dist-Bk1l05Ni.js +1 -0
  274. ksadk/server/static/assets/dist-BkJjNih3.js +1 -0
  275. ksadk/server/static/assets/dist-BmuTWcm7.js +9 -0
  276. ksadk/server/static/assets/dist-C2DKRFVK.js +1 -0
  277. ksadk/server/static/assets/dist-CWiTDN_V.js +6 -0
  278. ksadk/server/static/assets/dist-CZ6C3x8B.js +23 -0
  279. ksadk/server/static/assets/dist-CiZHB6ZW.js +1 -0
  280. ksadk/server/static/assets/dist-Cp1_jKwf.js +1 -0
  281. ksadk/server/static/assets/dist-Cwhk4lwI.js +2 -0
  282. ksadk/server/static/assets/dist-D5JGcxBx.js +11 -0
  283. ksadk/server/static/assets/dist-D99wf6_X.js +1 -0
  284. ksadk/server/static/assets/dist-DCpZrjaK.js +1 -0
  285. ksadk/server/static/assets/dist-DI-oVAXw.js +1 -0
  286. ksadk/server/static/assets/dist-DLMjL01k.js +1 -0
  287. ksadk/server/static/assets/dist-DLeM1OCK.js +1 -0
  288. ksadk/server/static/assets/dist-DM0rEQPk.js +1 -0
  289. ksadk/server/static/assets/dist-DbaH3p5h.js +1 -0
  290. ksadk/server/static/assets/dist-S4klkK5W.js +1 -0
  291. ksadk/server/static/assets/dockerfile-BLkNEvjs.js +1 -0
  292. ksadk/server/static/assets/dtd-DTF72YNO.js +1 -0
  293. ksadk/server/static/assets/dylan-C6jEEEk-.js +1 -0
  294. ksadk/server/static/assets/ebnf-D4c0_ac3.js +1 -0
  295. ksadk/server/static/assets/ecl-BSZaIHnp.js +1 -0
  296. ksadk/server/static/assets/eiffel-BEjRio4Q.js +1 -0
  297. ksadk/server/static/assets/elm-Cshzl8qu.js +1 -0
  298. ksadk/server/static/assets/erDiagram-TEJ5UH35-oJhaci7S.js +85 -0
  299. ksadk/server/static/assets/erlang-DaB2Rkuy.js +1 -0
  300. ksadk/server/static/assets/eventmodeling-FCH6USID-CIgwHJLL.js +1 -0
  301. ksadk/server/static/assets/factor-D7LVTn2l.js +1 -0
  302. ksadk/server/static/assets/fcl-ClOhbFR7.js +1 -0
  303. ksadk/server/static/assets/flowDiagram-I6XJVG4X-DtTmUan-.js +162 -0
  304. ksadk/server/static/assets/forth-Cezjo90N.js +1 -0
  305. ksadk/server/static/assets/fortran-Bt6PBEDR.js +1 -0
  306. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-BSsb_eij.js +292 -0
  307. ksadk/server/static/assets/gas-BHEdbvp9.js +1 -0
  308. ksadk/server/static/assets/gherkin-oBAE_ms0.js +1 -0
  309. ksadk/server/static/assets/gitGraph-WXDBUCRP-BVAJ7uo0.js +1 -0
  310. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-BR5s6Pws.js +106 -0
  311. ksadk/server/static/assets/graphlib-B8gBHxth.js +1 -0
  312. ksadk/server/static/assets/groovy-BC3IOsC8.js +1 -0
  313. ksadk/server/static/assets/haskell-BRsoo5mP.js +1 -0
  314. ksadk/server/static/assets/haxe-DIz0ZZqd.js +1 -0
  315. ksadk/server/static/assets/http-CLVgA2GD.js +1 -0
  316. ksadk/server/static/assets/idl-BUZw3wgd.js +1 -0
  317. ksadk/server/static/assets/index-BH7-pC0B.js +165 -0
  318. ksadk/server/static/assets/index-DAURbCsP.css +1 -0
  319. ksadk/server/static/assets/info-J43DQDTF-MT80V4ge.js +1 -0
  320. ksadk/server/static/assets/infoDiagram-5YYISTIA-DYPc5cvh.js +2 -0
  321. ksadk/server/static/assets/init-D6jRqBbL.js +1 -0
  322. ksadk/server/static/assets/ishikawaDiagram-YF4QCWOH-MoBdALDg.js +70 -0
  323. ksadk/server/static/assets/javascript-9Tg8ixDm.js +1 -0
  324. ksadk/server/static/assets/journeyDiagram-JHISSGLW-DgLiQT8l.js +139 -0
  325. ksadk/server/static/assets/julia-CQfgDRfP.js +1 -0
  326. ksadk/server/static/assets/kanban-definition-UN3LZRKU-CsFx112F.js +89 -0
  327. ksadk/server/static/assets/katex-DRsiwpM2.js +265 -0
  328. ksadk/server/static/assets/linear-TNRQ5Orv.js +1 -0
  329. ksadk/server/static/assets/livescript-BXxG0Yva.js +1 -0
  330. ksadk/server/static/assets/lua-CiA1ziua.js +1 -0
  331. ksadk/server/static/assets/mathematica-u8YMmbU0.js +1 -0
  332. ksadk/server/static/assets/mbox-BEMVcqjs.js +1 -0
  333. ksadk/server/static/assets/mermaid-parser.core-D2eMVOgo.js +161 -0
  334. ksadk/server/static/assets/mindmap-definition-RKZ34NQL-BtByYFhL.js +96 -0
  335. ksadk/server/static/assets/mirc-C9zpzAZU.js +1 -0
  336. ksadk/server/static/assets/mllike-B45xgp2S.js +1 -0
  337. ksadk/server/static/assets/modelica-CqHI_q-D.js +1 -0
  338. ksadk/server/static/assets/mscgen-qgSLujhx.js +1 -0
  339. ksadk/server/static/assets/mumps-CW_TBmxz.js +1 -0
  340. ksadk/server/static/assets/nginx-BMaDbqW3.js +1 -0
  341. ksadk/server/static/assets/nsis-AQ_alPln.js +1 -0
  342. ksadk/server/static/assets/ntriples-d28e9m0E.js +1 -0
  343. ksadk/server/static/assets/octave-D2Q8cUp1.js +1 -0
  344. ksadk/server/static/assets/ordinal-hYBb2elL.js +1 -0
  345. ksadk/server/static/assets/oz-BwTct_5T.js +1 -0
  346. ksadk/server/static/assets/packet-YPE3B663-BLKhbXZB.js +1 -0
  347. ksadk/server/static/assets/pascal-Dp_KdFgX.js +1 -0
  348. ksadk/server/static/assets/perl-CdEHsPfU.js +1 -0
  349. ksadk/server/static/assets/pie-LRSECV5Y-DFOikjSY.js +1 -0
  350. ksadk/server/static/assets/pieDiagram-4H26LBE5-DPnuCB8c.js +30 -0
  351. ksadk/server/static/assets/pig-AF4Hwhju.js +1 -0
  352. ksadk/server/static/assets/powershell-CzG71I4L.js +1 -0
  353. ksadk/server/static/assets/properties-C357ku5U.js +1 -0
  354. ksadk/server/static/assets/protobuf-D1ij_kNL.js +1 -0
  355. ksadk/server/static/assets/pug-Bugr-47h.js +1 -0
  356. ksadk/server/static/assets/puppet-B4hC2X4m.js +1 -0
  357. ksadk/server/static/assets/python-BqYw9LYJ.js +1 -0
  358. ksadk/server/static/assets/q-B9NhS7L_.js +1 -0
  359. ksadk/server/static/assets/quadrantDiagram-W4KKPZXB-miFpCPv4.js +7 -0
  360. ksadk/server/static/assets/r-DADKenSm.js +1 -0
  361. ksadk/server/static/assets/radar-GUYGQ44K-095b1Ikw.js +1 -0
  362. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-mjB_yYkW.js +84 -0
  363. ksadk/server/static/assets/rpm-gpDK5sbt.js +1 -0
  364. ksadk/server/static/assets/ruby-DsYpTuWg.js +1 -0
  365. ksadk/server/static/assets/sankeyDiagram-5OEKKPKP-D7hSlZZZ.js +40 -0
  366. ksadk/server/static/assets/sas-C2OyD2Y6.js +1 -0
  367. ksadk/server/static/assets/scheme-CyDdOh7e.js +1 -0
  368. ksadk/server/static/assets/sequenceDiagram-3UESZ5HK-D9Cx6hC3.js +162 -0
  369. ksadk/server/static/assets/shell-Du5Qg9im.js +1 -0
  370. ksadk/server/static/assets/sieve-BAxa3IjF.js +1 -0
  371. ksadk/server/static/assets/simple-mode-DRpGK0lJ.js +1 -0
  372. ksadk/server/static/assets/smalltalk-BLp5-jwC.js +1 -0
  373. ksadk/server/static/assets/solr-BBopId9w.js +1 -0
  374. ksadk/server/static/assets/sparql-Dz-mlCAC.js +1 -0
  375. ksadk/server/static/assets/spreadsheet-CTIncYxj.js +1 -0
  376. ksadk/server/static/assets/sql-DcCJ9jop.js +1 -0
  377. ksadk/server/static/assets/stateDiagram-AJRCARHV-D_zrg47o.js +1 -0
  378. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-J9kCb0nC.js +1 -0
  379. ksadk/server/static/assets/stex-sDrdk2BW.js +1 -0
  380. ksadk/server/static/assets/stylus-DLLZ8dgm.js +1 -0
  381. ksadk/server/static/assets/swift-DKB6_1j6.js +1 -0
  382. ksadk/server/static/assets/tcl-BGfruO1u.js +1 -0
  383. ksadk/server/static/assets/textile-DWBqthVk.js +1 -0
  384. ksadk/server/static/assets/tiddlywiki-VlUiK86J.js +1 -0
  385. ksadk/server/static/assets/tiki-CxVlf5KZ.js +1 -0
  386. ksadk/server/static/assets/timeline-definition-PNZ67QCA-CwSec0Wa.js +120 -0
  387. ksadk/server/static/assets/toml-LvoKBwCs.js +1 -0
  388. ksadk/server/static/assets/treeView-BLDUP644-yinfJEY6.js +1 -0
  389. ksadk/server/static/assets/treemap-LRROVOQU-DosUqN1Q.js +1 -0
  390. ksadk/server/static/assets/troff-C2dAgh7P.js +1 -0
  391. ksadk/server/static/assets/ttcn-BePYh-hG.js +1 -0
  392. ksadk/server/static/assets/ttcn-cfg-CY0aot7Q.js +1 -0
  393. ksadk/server/static/assets/turtle-BDLWE2cD.js +1 -0
  394. ksadk/server/static/assets/vb-BthdM_4N.js +1 -0
  395. ksadk/server/static/assets/vbscript-D9f6rSsU.js +1 -0
  396. ksadk/server/static/assets/velocity-CqftRsjg.js +1 -0
  397. ksadk/server/static/assets/vennDiagram-CIIHVFJN-agCVobiF.js +34 -0
  398. ksadk/server/static/assets/verilog-D-x6ne0Z.js +1 -0
  399. ksadk/server/static/assets/vhdl-CMrOq2q1.js +1 -0
  400. ksadk/server/static/assets/wardley-L42UT6IY-Bvp7-5uH.js +1 -0
  401. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-TmrlhWNt.js +78 -0
  402. ksadk/server/static/assets/webidl-D5jiJvOU.js +1 -0
  403. ksadk/server/static/assets/xquery-fj_R-kMw.js +1 -0
  404. ksadk/server/static/assets/xterm-DooSxjI5.js +36 -0
  405. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-DV71V-ah.js +7 -0
  406. ksadk/server/static/assets/yacas-CXXgtw0p.js +1 -0
  407. ksadk/server/static/assets/z80-CL1naaMV.js +1 -0
  408. ksadk/server/static/favicon.svg +1 -0
  409. ksadk/server/static/icons.svg +24 -0
  410. ksadk/server/static/index.html +14 -0
  411. ksadk/server/terminal_sessions.py +551 -0
  412. ksadk/sessions/__init__.py +283 -0
  413. ksadk/sessions/base.py +354 -0
  414. ksadk/sessions/continuity.py +313 -0
  415. ksadk/sessions/errors.py +7 -0
  416. ksadk/sessions/in_memory.py +273 -0
  417. ksadk/sessions/local_service.py +949 -0
  418. ksadk/sessions/postgres_service.py +838 -0
  419. ksadk/sessions/sqlite_service.py +13 -0
  420. ksadk/skills/__init__.py +9 -0
  421. ksadk/skills/loader.py +46 -0
  422. ksadk/skills/models.py +120 -0
  423. ksadk/skills/package_store.py +104 -0
  424. ksadk/skills/runtime/__init__.py +17 -0
  425. ksadk/skills/runtime/agent.py +183 -0
  426. ksadk/skills/runtime/artifacts.py +39 -0
  427. ksadk/skills/runtime/backends/__init__.py +1 -0
  428. ksadk/skills/runtime/backends/disabled.py +8 -0
  429. ksadk/skills/runtime/backends/e2b.py +168 -0
  430. ksadk/skills/runtime/backends/local.py +95 -0
  431. ksadk/skills/runtime/base.py +103 -0
  432. ksadk/skills/runtime/executor.py +219 -0
  433. ksadk/skills/runtime/factory.py +37 -0
  434. ksadk/skills/runtime/loader.py +131 -0
  435. ksadk/skills/runtime/registry.py +150 -0
  436. ksadk/skills/runtime/request.py +67 -0
  437. ksadk/skills/service_client.py +239 -0
  438. ksadk/skills/service_env.py +58 -0
  439. ksadk/skills/tool_defs.py +221 -0
  440. ksadk/terminal_client.py +69 -0
  441. ksadk/terminal_exec_policy.py +229 -0
  442. ksadk/tools/__init__.py +17 -0
  443. ksadk/tools/gateway.py +230 -0
  444. ksadk/tools/result_budget.py +154 -0
  445. ksadk/toolsets/__init__.py +852 -0
  446. ksadk/toolsets/_langchain.py +11 -0
  447. ksadk/toolsets/platform.py +93 -0
  448. ksadk/toolsets/sandbox.py +310 -0
  449. ksadk/toolsets/skills.py +217 -0
  450. ksadk/toolsets/web.py +266 -0
  451. ksadk/toolsets/workspace.py +878 -0
  452. ksadk/toolsets/workspace_state.py +44 -0
  453. ksadk/tracing/__init__.py +37 -0
  454. ksadk/tracing/exporters/__init__.py +1 -0
  455. ksadk/tracing/exporters/inmemory_exporter.py +116 -0
  456. ksadk/tracing/exporters/langfuse_exporter.py +445 -0
  457. ksadk/tracing/setup.py +829 -0
  458. ksadk/tracing/span_utils.py +114 -0
  459. ksadk/tui/__init__.py +12 -0
  460. ksadk/tui/app.py +400 -0
  461. ksadk/tui/clipboard.py +100 -0
  462. ksadk/tui/widgets/__init__.py +22 -0
  463. ksadk/tui/widgets/assistant.py +89 -0
  464. ksadk/tui/widgets/base.py +54 -0
  465. ksadk/tui/widgets/chat_input.py +246 -0
  466. ksadk/tui/widgets/history.py +156 -0
  467. ksadk/tui/widgets/system.py +87 -0
  468. ksadk/tui/widgets/thinking.py +110 -0
  469. ksadk/tui/widgets/tool_call.py +161 -0
  470. ksadk/tui/widgets/user.py +37 -0
  471. ksadk/ui_config.py +168 -0
  472. ksadk/version.py +4 -0
  473. ksadk_runtime_common/__init__.py +20 -0
  474. ksadk_runtime_common/memory_backend/__init__.py +29 -0
  475. ksadk_runtime_common/memory_backend/manifest.py +79 -0
  476. ksadk_runtime_common/memory_backend/providers/__init__.py +6 -0
  477. ksadk_runtime_common/memory_backend/providers/lancedb.py +151 -0
  478. ksadk_runtime_common/memory_backend/providers/mem0.py +74 -0
  479. ksadk_runtime_common/memory_backend/registry.py +56 -0
  480. ksadk_runtime_common/memory_backend/render.py +71 -0
  481. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -0
  482. ksadk_runtime_common/workspace_files/__init__.py +29 -0
  483. ksadk_runtime_common/workspace_files/bootstrap.py +56 -0
  484. ksadk_runtime_common/workspace_files/constants.py +9 -0
  485. ksadk_runtime_common/workspace_files/path_utils.py +71 -0
  486. ksadk_runtime_common/workspace_files/preview.py +96 -0
  487. ksadk_runtime_common/workspace_files/router.py +254 -0
  488. agentengine_sdk_python-0.6.2.dist-info/METADATA +0 -46
  489. agentengine_sdk_python-0.6.2.dist-info/RECORD +0 -4
  490. agentengine_sdk_python-0.6.2.dist-info/top_level.txt +0 -1
ksadk/tracing/setup.py ADDED
@@ -0,0 +1,829 @@
1
+ """
2
+ Tracing 初始化 - 支持多 Exporter (InMemory + Langfuse + OTLP)
3
+ 支持 ADK 自动插桩 via openinference-instrumentation-google-adk
4
+ """
5
+
6
+ import atexit
7
+ import base64
8
+ import logging
9
+ import os
10
+ from dataclasses import dataclass
11
+ from typing import Any, Optional
12
+ from urllib.parse import unquote
13
+
14
+ from ksadk.tracing.exporters.inmemory_exporter import InMemoryExporter
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ def _batch_span_processor_kwargs() -> dict:
20
+ """BatchSpanProcessor 参数:限制单次 export 体积,避免 OTLP collector 413。
21
+
22
+ 默认 max_export_batch_size=64(OTel 默认 512),单 batch 过大会触发 collector
23
+ `Request Entity Too Large (413)`。可用 KSADK_OTLP_MAX_EXPORT_BATCH_SIZE 覆盖。
24
+ """
25
+ try:
26
+ max_batch = int(os.environ.get("KSADK_OTLP_MAX_EXPORT_BATCH_SIZE", "64"))
27
+ except ValueError:
28
+ max_batch = 64
29
+ if max_batch <= 0:
30
+ max_batch = 64
31
+ return {
32
+ "max_queue_size": max(512, max_batch * 8),
33
+ "max_export_batch_size": max_batch,
34
+ "export_timeout_millis": 30000,
35
+ }
36
+
37
+
38
+ _exporter_instance: Optional[InMemoryExporter] = None
39
+ _langfuse_exporter: Optional[Any] = None
40
+ _tracing_initialized: bool = False
41
+ _adk_instrumented: bool = False
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class _OtlpHttpConfig:
46
+ endpoint: str
47
+ headers: dict[str, str]
48
+ protocol: str
49
+ service_name: str
50
+
51
+
52
+ class _LoggingSpanExporter:
53
+ """Small delegating exporter that logs external trace export flow."""
54
+
55
+ def __init__(
56
+ self,
57
+ exporter: Any,
58
+ *,
59
+ name: str,
60
+ endpoint: str,
61
+ service_name: str,
62
+ header_keys: list[str],
63
+ span_transform: Any = None,
64
+ ):
65
+ self._exporter = exporter
66
+ self._name = name
67
+ self._endpoint = endpoint
68
+ self._service_name = service_name
69
+ self._header_keys = header_keys
70
+ self._span_transform = span_transform
71
+
72
+ def export(self, spans):
73
+ span_count = len(spans) if hasattr(spans, "__len__") else "unknown"
74
+ logger.info(
75
+ "%s export started: endpoint=%s service_name=%s spans=%s headers=%s",
76
+ self._name,
77
+ self._endpoint,
78
+ self._service_name or "",
79
+ span_count,
80
+ ",".join(self._header_keys),
81
+ )
82
+ try:
83
+ export_spans = self._span_transform(spans) if self._span_transform else spans
84
+ result = self._exporter.export(export_spans)
85
+ except Exception:
86
+ logger.exception(
87
+ "%s export failed: endpoint=%s service_name=%s spans=%s",
88
+ self._name,
89
+ self._endpoint,
90
+ self._service_name or "",
91
+ span_count,
92
+ )
93
+ raise
94
+ logger.info(
95
+ "%s export result: endpoint=%s service_name=%s spans=%s result=%s",
96
+ self._name,
97
+ self._endpoint,
98
+ self._service_name or "",
99
+ span_count,
100
+ result,
101
+ )
102
+ return result
103
+
104
+ def shutdown(self):
105
+ shutdown = getattr(self._exporter, "shutdown", None)
106
+ if shutdown is None:
107
+ return None
108
+ logger.info("%s exporter shutdown: endpoint=%s", self._name, self._endpoint)
109
+ return shutdown()
110
+
111
+ def force_flush(self, timeout_millis: int = 30000) -> bool:
112
+ force_flush = getattr(self._exporter, "force_flush", None)
113
+ if force_flush is None:
114
+ return True
115
+ logger.info(
116
+ "%s exporter force_flush: endpoint=%s timeout_millis=%s",
117
+ self._name,
118
+ self._endpoint,
119
+ timeout_millis,
120
+ )
121
+ return force_flush(timeout_millis)
122
+
123
+
124
+ def _coerce_int(value: Any) -> int:
125
+ if value is None or isinstance(value, bool):
126
+ return 0
127
+ try:
128
+ return int(value)
129
+ except (TypeError, ValueError):
130
+ try:
131
+ return int(float(value))
132
+ except (TypeError, ValueError):
133
+ return 0
134
+
135
+
136
+ def _span_context(span: Any) -> Any:
137
+ context = getattr(span, "context", None)
138
+ if context is not None:
139
+ return context
140
+ get_context = getattr(span, "get_span_context", None)
141
+ if callable(get_context):
142
+ try:
143
+ return get_context()
144
+ except Exception:
145
+ return None
146
+ return None
147
+
148
+
149
+ def _span_id(span: Any) -> Optional[int]:
150
+ return getattr(_span_context(span), "span_id", None)
151
+
152
+
153
+ def _trace_id(span: Any) -> Optional[int]:
154
+ return getattr(_span_context(span), "trace_id", None)
155
+
156
+
157
+ def _parent_span_id(span: Any) -> Optional[int]:
158
+ return getattr(getattr(span, "parent", None), "span_id", None)
159
+
160
+
161
+ def _span_token_usage(span: Any) -> dict[str, int]:
162
+ attributes = getattr(span, "attributes", None) or {}
163
+ return {
164
+ "input": _coerce_int(attributes.get("gen_ai.usage.input_tokens")),
165
+ "output": _coerce_int(attributes.get("gen_ai.usage.output_tokens")),
166
+ "cache_read": _coerce_int(attributes.get("gen_ai.usage.cache_read.input_tokens")),
167
+ "reasoning_output": _coerce_int(
168
+ attributes.get("gen_ai.usage.reasoning.output_tokens")
169
+ ),
170
+ }
171
+
172
+
173
+ def _has_nonzero_token_usage(usage: dict[str, int]) -> bool:
174
+ return any(value > 0 for value in usage.values())
175
+
176
+
177
+ def _clone_span_with_attributes(span: Any, attributes: dict[str, Any]) -> Any:
178
+ try:
179
+ from opentelemetry.sdk.trace import ReadableSpan
180
+
181
+ return ReadableSpan(
182
+ name=span.name,
183
+ context=span.context,
184
+ parent=span.parent,
185
+ resource=span.resource,
186
+ attributes=attributes,
187
+ events=span.events,
188
+ links=span.links,
189
+ kind=span.kind,
190
+ instrumentation_info=getattr(span, "instrumentation_info", None),
191
+ status=span.status,
192
+ start_time=span.start_time,
193
+ end_time=span.end_time,
194
+ instrumentation_scope=getattr(span, "instrumentation_scope", None),
195
+ )
196
+ except Exception:
197
+ logger.debug("Failed to clone span for CloudMonitor token compatibility", exc_info=True)
198
+ return span
199
+
200
+
201
+ def _prepare_cloud_monitor_spans(spans: Any) -> Any:
202
+ """Add root token rollups for CloudMonitor without changing other exporters.
203
+
204
+ CloudMonitor already parses gen_ai.usage.* on LLM child spans, but its root-span
205
+ and overview APIs currently use root-level token fields. ADK/OpenInference often
206
+ emits token usage on nested LLM spans only, and sometimes duplicates the same LLM
207
+ usage on a parent and a child span. To avoid double counting, aggregate only
208
+ token-bearing leaf spans and copy the result to the root span for this exporter.
209
+ """
210
+ if not spans:
211
+ return spans
212
+ span_list = list(spans)
213
+ span_ids = {_span_id(span) for span in span_list if _span_id(span) is not None}
214
+ if not span_ids:
215
+ return spans
216
+
217
+ children_by_parent: dict[tuple[Optional[int], int], list[Any]] = {}
218
+ roots: list[Any] = []
219
+ for span in span_list:
220
+ sid = _span_id(span)
221
+ if sid is None:
222
+ continue
223
+ parent_id = _parent_span_id(span)
224
+ trace_id = _trace_id(span)
225
+ if parent_id is None or parent_id not in span_ids:
226
+ roots.append(span)
227
+ else:
228
+ children_by_parent.setdefault((trace_id, parent_id), []).append(span)
229
+
230
+ token_usage_by_id = {
231
+ (_trace_id(span), _span_id(span)): _span_token_usage(span)
232
+ for span in span_list
233
+ if _span_id(span) is not None
234
+ }
235
+
236
+ has_token_descendant_cache: dict[tuple[Optional[int], int], bool] = {}
237
+
238
+ def has_token_descendant(span: Any) -> bool:
239
+ sid = _span_id(span)
240
+ key = (_trace_id(span), sid)
241
+ if sid is None:
242
+ return False
243
+ if key in has_token_descendant_cache:
244
+ return has_token_descendant_cache[key]
245
+ for child in children_by_parent.get(key, []):
246
+ child_key = (_trace_id(child), _span_id(child))
247
+ if _has_nonzero_token_usage(token_usage_by_id.get(child_key, {})):
248
+ has_token_descendant_cache[key] = True
249
+ return True
250
+ if has_token_descendant(child):
251
+ has_token_descendant_cache[key] = True
252
+ return True
253
+ has_token_descendant_cache[key] = False
254
+ return False
255
+
256
+ def collect_leaf_usage(span: Any, usage: dict[str, int]) -> None:
257
+ sid = _span_id(span)
258
+ key = (_trace_id(span), sid)
259
+ own_usage = token_usage_by_id.get(key, {})
260
+ if _has_nonzero_token_usage(own_usage) and not has_token_descendant(span):
261
+ for usage_key, value in own_usage.items():
262
+ usage[usage_key] += value
263
+ return
264
+ for child in children_by_parent.get(key, []):
265
+ collect_leaf_usage(child, usage)
266
+
267
+ replacements: dict[int, Any] = {}
268
+ for root in roots:
269
+ aggregate = {"input": 0, "output": 0, "cache_read": 0, "reasoning_output": 0}
270
+ collect_leaf_usage(root, aggregate)
271
+ if not _has_nonzero_token_usage(aggregate):
272
+ continue
273
+
274
+ attributes = dict(getattr(root, "attributes", None) or {})
275
+ updated = False
276
+ attr_map = {
277
+ "gen_ai.usage.input_tokens": "input",
278
+ "gen_ai.usage.output_tokens": "output",
279
+ "gen_ai.usage.cache_read.input_tokens": "cache_read",
280
+ "gen_ai.usage.reasoning.output_tokens": "reasoning_output",
281
+ }
282
+ for attr_name, usage_key in attr_map.items():
283
+ if _coerce_int(attributes.get(attr_name)) <= 0 and aggregate[usage_key] > 0:
284
+ attributes[attr_name] = aggregate[usage_key]
285
+ updated = True
286
+
287
+ if updated:
288
+ replacements[id(root)] = _clone_span_with_attributes(root, attributes)
289
+
290
+ if not replacements:
291
+ return spans
292
+ return [replacements.get(id(span), span) for span in span_list]
293
+
294
+
295
+ def _build_langfuse_otlp_config(langfuse_config: dict = None) -> Optional[dict]:
296
+ """Build Langfuse OTLP direct exporter config from explicit config or env."""
297
+ if langfuse_config:
298
+ public_key = langfuse_config.get("public_key") or ""
299
+ secret_key = langfuse_config.get("secret_key") or ""
300
+ host = langfuse_config.get("host") or "http://localhost:3000"
301
+ else:
302
+ public_key = os.getenv("LANGFUSE_PUBLIC_KEY", "")
303
+ secret_key = os.getenv("LANGFUSE_SECRET_KEY", "")
304
+ host = os.getenv("LANGFUSE_BASE_URL") or os.getenv("LANGFUSE_HOST") or "http://localhost:3000"
305
+
306
+ if not public_key or not secret_key:
307
+ return None
308
+
309
+ headers = _build_langfuse_otlp_headers(public_key, secret_key)
310
+ return {
311
+ "endpoint": f"{host.rstrip('/')}/api/public/otel/v1/traces",
312
+ "headers": headers,
313
+ "protocol": "http/protobuf",
314
+ }
315
+
316
+
317
+ def _build_langfuse_otlp_headers(public_key: str, secret_key: str) -> dict[str, str]:
318
+ auth = base64.b64encode(f"{public_key}:{secret_key}".encode("utf-8")).decode("ascii")
319
+ return {
320
+ "Authorization": f"Basic {auth}",
321
+ "x-langfuse-ingestion-version": "4",
322
+ }
323
+
324
+
325
+ def _parse_otlp_headers(raw: str) -> dict[str, str]:
326
+ """Parse OTEL_EXPORTER_OTLP_HEADERS into an HTTP headers dict."""
327
+ headers: dict[str, str] = {}
328
+ for part in (raw or "").split(","):
329
+ item = part.strip()
330
+ if not item or "=" not in item:
331
+ continue
332
+ key, value = item.split("=", 1)
333
+ key = key.strip()
334
+ if not key:
335
+ continue
336
+ headers[key] = _decode_otlp_header_value(key, value)
337
+ return headers
338
+
339
+
340
+ def _decode_otlp_header_value(key: str, value: str) -> str:
341
+ decoded = unquote(value.strip())
342
+ if key.strip().lower() != "authorization":
343
+ return decoded
344
+
345
+ for scheme in ("Basic", "Bearer"):
346
+ prefix = f"{scheme}+"
347
+ if decoded.startswith(prefix):
348
+ return f"{scheme} {decoded[len(prefix):]}"
349
+ return decoded
350
+
351
+
352
+ def _derive_otlp_traces_endpoint(endpoint: str) -> str:
353
+ """Derive the HTTP trace endpoint from a generic OTLP endpoint."""
354
+ endpoint = endpoint.strip().rstrip("/")
355
+ if endpoint.endswith("/v1/traces"):
356
+ return endpoint
357
+ return f"{endpoint}/v1/traces"
358
+
359
+
360
+ def _env_flag_disabled(value: str) -> bool:
361
+ return value.strip().lower() in {"0", "false", "no", "off", "disabled"}
362
+
363
+
364
+ def _env_flag_enabled(value: str) -> bool:
365
+ return value.strip().lower() in {"1", "true", "yes", "on"}
366
+
367
+
368
+ def _has_header(headers: dict[str, str], header_name: str) -> bool:
369
+ expected = header_name.strip().lower()
370
+ return any(key.strip().lower() == expected for key in headers)
371
+
372
+
373
+ def _get_service_name() -> str:
374
+ service_name = os.getenv("OTEL_SERVICE_NAME", "").strip()
375
+ if service_name:
376
+ return service_name
377
+
378
+ for part in os.getenv("OTEL_RESOURCE_ATTRIBUTES", "").split(","):
379
+ item = part.strip()
380
+ if not item or "=" not in item:
381
+ continue
382
+ key, value = item.split("=", 1)
383
+ if key.strip() == "service.name":
384
+ return unquote(value.strip())
385
+ return ""
386
+
387
+
388
+ def _build_cloud_monitor_otlp_http_config() -> Optional[_OtlpHttpConfig]:
389
+ """Build CloudMonitor OTLP HTTP traces exporter config from CLOUD_MONITOR_* env."""
390
+ enabled = os.getenv("CLOUD_MONITOR_OTLP_ENABLED", "").strip()
391
+ if enabled and _env_flag_disabled(enabled):
392
+ logger.info("CloudMonitor OTLP exporter disabled by CLOUD_MONITOR_OTLP_ENABLED=%s", enabled)
393
+ return None
394
+ cloud_monitor_langfuse_configured = all(
395
+ os.getenv(name, "").strip()
396
+ for name in (
397
+ "CLOUD_MONITOR_LANGFUSE_PUBLIC_KEY",
398
+ "CLOUD_MONITOR_LANGFUSE_SECRET_KEY",
399
+ )
400
+ ) and bool(
401
+ os.getenv("CLOUD_MONITOR_LANGFUSE_HOST", "").strip()
402
+ or os.getenv("CLOUD_MONITOR_OTLP_ENDPOINT", "").strip()
403
+ )
404
+ cloud_monitor_otlp_forced = _env_flag_enabled(enabled)
405
+ cloud_monitor_callback_requested = _env_flag_enabled(
406
+ os.getenv("LANGFUSE_USE_CALLBACK", "")
407
+ ) and not _env_flag_disabled(os.getenv("CLOUD_MONITOR_LANGFUSE_ENABLED", ""))
408
+ if (
409
+ cloud_monitor_langfuse_configured
410
+ and cloud_monitor_callback_requested
411
+ and not cloud_monitor_otlp_forced
412
+ ):
413
+ logger.info(
414
+ "CloudMonitor OTLP exporter skipped because CloudMonitor Langfuse SDK "
415
+ "callback is requested"
416
+ )
417
+ return None
418
+
419
+ app_key = os.getenv("CLOUD_MONITOR_APP_KEY", "").strip()
420
+ traces_endpoint = os.getenv("CLOUD_MONITOR_OTLP_TRACES_ENDPOINT", "").strip()
421
+ base_endpoint = os.getenv("CLOUD_MONITOR_OTLP_ENDPOINT", "").strip()
422
+ endpoint = traces_endpoint
423
+ if not endpoint and base_endpoint:
424
+ endpoint = _derive_otlp_traces_endpoint(base_endpoint)
425
+
426
+ if not app_key and not endpoint:
427
+ logger.debug("CloudMonitor OTLP exporter not configured: missing app key and endpoint")
428
+ return None
429
+ if not app_key:
430
+ logger.warning("CloudMonitor OTLP exporter skipped: CLOUD_MONITOR_APP_KEY is missing")
431
+ return None
432
+ if not endpoint:
433
+ logger.warning(
434
+ "CloudMonitor OTLP exporter skipped: CLOUD_MONITOR_OTLP_ENDPOINT or "
435
+ "CLOUD_MONITOR_OTLP_TRACES_ENDPOINT is missing"
436
+ )
437
+ return None
438
+
439
+ protocol = (
440
+ os.getenv("CLOUD_MONITOR_OTLP_TRACES_PROTOCOL", "").strip().lower()
441
+ or os.getenv("CLOUD_MONITOR_OTLP_PROTOCOL", "").strip().lower()
442
+ or "http/protobuf"
443
+ )
444
+ if protocol != "http/protobuf":
445
+ logger.warning(
446
+ "CloudMonitor OTLP exporter skipped: unsupported protocol %s, expected http/protobuf",
447
+ protocol,
448
+ )
449
+ return None
450
+
451
+ headers = _parse_otlp_headers(os.getenv("CLOUD_MONITOR_OTLP_HEADERS", ""))
452
+ headers["Ksc-Appkey"] = app_key
453
+ service_name = _get_service_name()
454
+ logger.info(
455
+ "CloudMonitor OTLP config resolved: endpoint=%s protocol=%s service_name=%s "
456
+ "app_key_present=%s header_keys=%s",
457
+ endpoint,
458
+ protocol,
459
+ service_name or "",
460
+ bool(app_key),
461
+ ",".join(sorted(headers)),
462
+ )
463
+ return _OtlpHttpConfig(
464
+ endpoint=endpoint,
465
+ headers=headers,
466
+ protocol=protocol,
467
+ service_name=service_name,
468
+ )
469
+
470
+
471
+ def _is_langfuse_otlp_endpoint(endpoint: str) -> bool:
472
+ if not endpoint:
473
+ return False
474
+ normalized_endpoint = endpoint.strip().rstrip("/")
475
+ langfuse_hosts = [
476
+ os.getenv("LANGFUSE_HOST", "").strip().rstrip("/"),
477
+ os.getenv("LANGFUSE_BASE_URL", "").strip().rstrip("/"),
478
+ ]
479
+ if any(host and normalized_endpoint.startswith(host) for host in langfuse_hosts):
480
+ return True
481
+ return "/api/public/otel" in normalized_endpoint
482
+
483
+
484
+ def _is_langfuse_callback_endpoint(endpoint: str) -> bool:
485
+ return _env_flag_enabled(os.getenv("LANGFUSE_USE_CALLBACK", "")) and _is_langfuse_otlp_endpoint(
486
+ endpoint
487
+ )
488
+
489
+
490
+ def _apply_langfuse_auth_fallback(endpoint: str, headers: dict[str, str]) -> bool:
491
+ """Add Langfuse OTLP auth when the platform provides endpoint + keys but no headers."""
492
+ if not _is_langfuse_otlp_endpoint(endpoint) or _has_header(headers, "Authorization"):
493
+ return False
494
+
495
+ public_key = os.getenv("LANGFUSE_PUBLIC_KEY", "").strip()
496
+ secret_key = os.getenv("LANGFUSE_SECRET_KEY", "").strip()
497
+ if not public_key or not secret_key:
498
+ logger.warning(
499
+ "Generic OTLP endpoint looks like Langfuse but LANGFUSE_PUBLIC_KEY/SECRET_KEY "
500
+ "are missing; Authorization header was not added"
501
+ )
502
+ return False
503
+
504
+ langfuse_headers = _build_langfuse_otlp_headers(public_key, secret_key)
505
+ headers["Authorization"] = langfuse_headers["Authorization"]
506
+ if not _has_header(headers, "x-langfuse-ingestion-version"):
507
+ headers["x-langfuse-ingestion-version"] = langfuse_headers[
508
+ "x-langfuse-ingestion-version"
509
+ ]
510
+ return True
511
+
512
+
513
+ def _build_generic_otlp_http_config() -> Optional[dict]:
514
+ """Build generic OTLP HTTP traces exporter config from standard OTEL env."""
515
+ traces_endpoint = os.getenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "").strip()
516
+ base_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "").strip()
517
+ endpoint = traces_endpoint
518
+ if not endpoint and base_endpoint:
519
+ endpoint = _derive_otlp_traces_endpoint(base_endpoint)
520
+ if not endpoint:
521
+ return None
522
+ if _is_langfuse_callback_endpoint(endpoint):
523
+ logger.info(
524
+ "Generic OTLP HTTP exporter skipped because LANGFUSE_USE_CALLBACK is enabled "
525
+ "for endpoint=%s",
526
+ endpoint,
527
+ )
528
+ return None
529
+
530
+ protocol = (
531
+ os.getenv("OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", "").strip().lower()
532
+ or os.getenv("OTEL_EXPORTER_OTLP_PROTOCOL", "").strip().lower()
533
+ )
534
+ if protocol and protocol != "http/protobuf":
535
+ logger.warning(
536
+ "Unsupported OTEL_EXPORTER_OTLP protocol for KsADK auto HTTP exporter: %s",
537
+ protocol,
538
+ )
539
+ return None
540
+
541
+ raw_headers = (
542
+ os.getenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS", "").strip()
543
+ or os.getenv("OTEL_EXPORTER_OTLP_HEADERS", "")
544
+ )
545
+ headers = _parse_otlp_headers(raw_headers)
546
+ langfuse_auth_fallback = _apply_langfuse_auth_fallback(endpoint, headers)
547
+ logger.info(
548
+ "Generic OTLP HTTP config resolved: endpoint=%s protocol=http/protobuf "
549
+ "header_keys=%s langfuse_auth_fallback=%s",
550
+ endpoint,
551
+ ",".join(sorted(headers)),
552
+ langfuse_auth_fallback,
553
+ )
554
+ return {
555
+ "endpoint": endpoint,
556
+ "headers": headers,
557
+ "protocol": "http/protobuf",
558
+ "langfuse_auth_fallback": langfuse_auth_fallback,
559
+ }
560
+
561
+
562
+ def setup_tracing(
563
+ enable_inmemory: bool = True,
564
+ enable_langfuse: bool = None, # Auto-detect from env
565
+ langfuse_config: dict = None,
566
+ enable_otlp: bool = False,
567
+ otlp_endpoint: str = "localhost:4317",
568
+ enable_adk_instrumentation: bool = True, # Auto-instrument ADK
569
+ use_callback_only: bool = None, # Explicit override
570
+ **kwargs
571
+ ) -> Optional[InMemoryExporter]:
572
+ """初始化 Tracing (支持多 Exporter)
573
+
574
+ Args:
575
+ enable_inmemory: 是否启用内存 Exporter (Web UI 使用)
576
+ enable_langfuse: 是否启用 Langfuse (None = 自动检测环境变量)
577
+ langfuse_config: Langfuse 配置 {"public_key", "secret_key", "host"}
578
+ enable_otlp: 是否启用 OTLP Exporter
579
+ otlp_endpoint: OTLP 端点地址
580
+ enable_adk_instrumentation: 是否启用 ADK 自动插桩
581
+ use_callback_only: 是否仅使用 CallbackHandler (防止 OTel 重复)
582
+
583
+ Returns:
584
+ InMemoryExporter 实例 (用于 Web UI 获取 traces)
585
+ """
586
+ global _exporter_instance, _langfuse_exporter, _tracing_initialized, _adk_instrumented
587
+
588
+ # 防止重复初始化
589
+ if _tracing_initialized:
590
+ logger.debug("Tracing already initialized, skipping")
591
+ return _exporter_instance
592
+
593
+ try:
594
+ from opentelemetry import trace
595
+ from opentelemetry.sdk.trace import TracerProvider
596
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor, SimpleSpanProcessor
597
+ except ImportError:
598
+ logger.warning("OpenTelemetry not installed, tracing disabled")
599
+ return None
600
+
601
+ # 检查是否已有 TracerProvider (避免覆盖)
602
+ existing_provider = trace.get_tracer_provider()
603
+ if existing_provider and hasattr(existing_provider, 'add_span_processor'):
604
+ # 使用现有 provider,直接添加 processor
605
+ provider = existing_provider
606
+ logger.debug("Using existing TracerProvider")
607
+ else:
608
+ # 创建新的 TracerProvider
609
+ provider = TracerProvider()
610
+ trace.set_tracer_provider(provider)
611
+ logger.debug("Created new TracerProvider")
612
+
613
+ # 1. InMemory Exporter (for Web UI)
614
+ if enable_inmemory:
615
+ exporter = InMemoryExporter(max_traces=kwargs.get("max_traces", 1000))
616
+ _exporter_instance = exporter
617
+ provider.add_span_processor(SimpleSpanProcessor(exporter))
618
+ logger.info("InMemory exporter enabled")
619
+
620
+ # 2. Generic OTLP HTTP exporter from standard environment variables.
621
+ # This keeps user code backend-agnostic; Langfuse is only one possible OTLP backend.
622
+ generic_otlp_config = _build_generic_otlp_http_config()
623
+ if generic_otlp_config:
624
+ try:
625
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
626
+
627
+ otlp_exporter = OTLPSpanExporter(
628
+ endpoint=generic_otlp_config["endpoint"],
629
+ headers=generic_otlp_config["headers"],
630
+ )
631
+ otlp_exporter = _LoggingSpanExporter(
632
+ otlp_exporter,
633
+ name="Generic OTLP",
634
+ endpoint=generic_otlp_config["endpoint"],
635
+ service_name=_get_service_name(),
636
+ header_keys=sorted(generic_otlp_config["headers"]),
637
+ )
638
+ provider.add_span_processor(
639
+ BatchSpanProcessor(
640
+ otlp_exporter,
641
+ **_batch_span_processor_kwargs(),
642
+ )
643
+ )
644
+ logger.info(
645
+ "Generic OTLP HTTP exporter enabled: %s (%s) headers=%s",
646
+ generic_otlp_config["endpoint"],
647
+ generic_otlp_config["protocol"],
648
+ ",".join(sorted(generic_otlp_config["headers"])),
649
+ )
650
+ except ImportError as e:
651
+ logger.warning(f"Generic OTLP HTTP exporter not available: {e}")
652
+ except Exception as e:
653
+ logger.error(f"Failed to initialize generic OTLP HTTP exporter: {e}")
654
+
655
+ # 3. CloudMonitor OTLP HTTP exporter.
656
+ # This uses CloudMonitor-specific env vars, so existing Langfuse / generic OTLP paths
657
+ # continue to behave exactly as configured by the user or platform.
658
+ cloud_monitor_config = _build_cloud_monitor_otlp_http_config()
659
+ if cloud_monitor_config:
660
+ try:
661
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
662
+
663
+ cloud_monitor_exporter = OTLPSpanExporter(
664
+ endpoint=cloud_monitor_config.endpoint,
665
+ headers=cloud_monitor_config.headers,
666
+ )
667
+ cloud_monitor_exporter = _LoggingSpanExporter(
668
+ cloud_monitor_exporter,
669
+ name="CloudMonitor OTLP",
670
+ endpoint=cloud_monitor_config.endpoint,
671
+ service_name=cloud_monitor_config.service_name,
672
+ header_keys=sorted(cloud_monitor_config.headers),
673
+ span_transform=_prepare_cloud_monitor_spans,
674
+ )
675
+ provider.add_span_processor(
676
+ BatchSpanProcessor(
677
+ cloud_monitor_exporter,
678
+ **_batch_span_processor_kwargs(),
679
+ )
680
+ )
681
+ logger.info(
682
+ "CloudMonitor OTLP exporter enabled: endpoint=%s protocol=%s service_name=%s",
683
+ cloud_monitor_config.endpoint,
684
+ cloud_monitor_config.protocol,
685
+ cloud_monitor_config.service_name or "",
686
+ )
687
+ except ImportError as e:
688
+ logger.warning(f"CloudMonitor OTLP exporter not available: {e}")
689
+ except Exception as e:
690
+ logger.error(f"Failed to initialize CloudMonitor OTLP exporter: {e}")
691
+
692
+ # 4. Langfuse OTLP direct exporter (auto-detect or explicit config)
693
+ # 注意: 对于 LangGraph/LangChain 框架,推荐使用 CallbackHandler 而非 OTel Exporter
694
+ # 同时使用两者会导致重复的 trace
695
+ langfuse_enabled = enable_langfuse
696
+ if langfuse_enabled is None:
697
+ # Auto-detect from environment variables
698
+ langfuse_enabled = (
699
+ not generic_otlp_config
700
+ and bool(os.getenv("LANGFUSE_PUBLIC_KEY") or (langfuse_config or {}).get("public_key"))
701
+ )
702
+
703
+ # 检查是否应该禁用 LangfuseExporter (当使用 LangChain/LangGraph 时)
704
+ # 优先使用显式参数,否则读取环境变量
705
+ if use_callback_only is None:
706
+ use_callback_only = os.getenv("LANGFUSE_USE_CALLBACK", "false").lower() == "true"
707
+
708
+ if langfuse_enabled and not use_callback_only:
709
+ try:
710
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
711
+
712
+ config = _build_langfuse_otlp_config(langfuse_config)
713
+ if config:
714
+ otlp_exporter = OTLPSpanExporter(
715
+ endpoint=config["endpoint"],
716
+ headers=config["headers"],
717
+ )
718
+ otlp_exporter = _LoggingSpanExporter(
719
+ otlp_exporter,
720
+ name="Langfuse OTLP",
721
+ endpoint=config["endpoint"],
722
+ service_name=_get_service_name(),
723
+ header_keys=sorted(config["headers"]),
724
+ )
725
+ provider.add_span_processor(
726
+ BatchSpanProcessor(
727
+ otlp_exporter,
728
+ **_batch_span_processor_kwargs(),
729
+ )
730
+ )
731
+ logger.info(
732
+ "Langfuse OTLP exporter enabled: %s (%s) headers=%s",
733
+ config["endpoint"],
734
+ config["protocol"],
735
+ ",".join(sorted(config["headers"])),
736
+ )
737
+ else:
738
+ logger.warning("Langfuse credentials not found, skipping")
739
+
740
+ except ImportError as e:
741
+ logger.warning(f"Langfuse OTLP exporter not available: {e}")
742
+ except Exception as e:
743
+ logger.error(f"Failed to initialize Langfuse OTLP exporter: {e}")
744
+ elif langfuse_enabled:
745
+ logger.info("Langfuse will use CallbackHandler (recommended for LangChain/LangGraph)")
746
+
747
+ # 5. OTLP Exporter (optional)
748
+ if enable_otlp:
749
+ try:
750
+ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
751
+ otlp_exporter = OTLPSpanExporter(endpoint=otlp_endpoint)
752
+ provider.add_span_processor(
753
+ BatchSpanProcessor(
754
+ otlp_exporter,
755
+ **_batch_span_processor_kwargs(),
756
+ )
757
+ )
758
+ logger.info(f"OTLP exporter enabled: {otlp_endpoint}")
759
+ except ImportError:
760
+ logger.warning("OTLP exporter not installed")
761
+
762
+ # 6. ADK Auto-Instrumentation (for Google ADK projects)
763
+ if enable_adk_instrumentation and not _adk_instrumented:
764
+ try:
765
+ from openinference.instrumentation.google_adk import GoogleADKInstrumentor
766
+ GoogleADKInstrumentor().instrument()
767
+ _adk_instrumented = True
768
+ logger.info("Google ADK instrumentation enabled")
769
+ except ImportError:
770
+ logger.debug(
771
+ "openinference-instrumentation-google-adk not installed, "
772
+ "ADK auto-instrumentation disabled"
773
+ )
774
+ except Exception as e:
775
+ logger.debug(f"ADK instrumentation failed: {e}")
776
+
777
+ # 7. LangChain Auto-Instrumentation
778
+ if enable_adk_instrumentation:
779
+ try:
780
+ from openinference.instrumentation.langchain import LangChainInstrumentor
781
+ LangChainInstrumentor().instrument()
782
+ logger.info("LangChain instrumentation enabled")
783
+ except ImportError:
784
+ logger.warning(
785
+ "Auto-instrumentation skipped: 'openinference-instrumentation-langchain' "
786
+ "not installed. Install with `pip install ksadk[tracing]` for detailed traces."
787
+ )
788
+ except Exception as e:
789
+ logger.error(f"LangChain instrumentation failed: {e}")
790
+
791
+ # Register graceful shutdown
792
+ atexit.register(shutdown_tracing)
793
+
794
+ _tracing_initialized = True
795
+ return _exporter_instance
796
+
797
+
798
+ def shutdown_tracing():
799
+ """Gracefully shutdown tracing to prevent Ctrl+C errors"""
800
+ global _langfuse_exporter, _tracing_initialized
801
+
802
+ if _langfuse_exporter is not None:
803
+ try:
804
+ if hasattr(_langfuse_exporter, '_exporter'):
805
+ _langfuse_exporter._exporter.shutdown()
806
+ logger.debug("Langfuse exporter shutdown gracefully")
807
+ except Exception:
808
+ pass # Ignore shutdown errors
809
+
810
+ _tracing_initialized = False
811
+
812
+
813
+ def get_memory_exporter() -> Optional[InMemoryExporter]:
814
+ """获取当前的 Memory Exporter 实例"""
815
+ return _exporter_instance
816
+
817
+
818
+ def get_langfuse_exporter():
819
+ """获取 Langfuse Exporter 实例"""
820
+ return _langfuse_exporter
821
+
822
+
823
+ def get_tracer(name: str = "ksadk"):
824
+ """获取 Tracer"""
825
+ try:
826
+ from opentelemetry import trace
827
+ return trace.get_tracer(name)
828
+ except ImportError:
829
+ return None