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
@@ -0,0 +1,900 @@
1
+ """agentengine dashboard - Dashboard 命令组(canonical: `dashboard open`)。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import os
7
+ import webbrowser
8
+ from datetime import datetime, timedelta, timezone
9
+ from pathlib import Path
10
+ from typing import Optional, Tuple
11
+
12
+ import click
13
+
14
+ from ksadk.api import AgentEngineAPIError, AgentEngineClient
15
+ from ksadk.cli.agent_ref import (
16
+ ResolvedAgentRef,
17
+ merge_agent_inputs,
18
+ resolve_agent_ref,
19
+ resolve_openclaw_ref,
20
+ )
21
+ from ksadk.cli.dry_run import dry_run_option, effective_dry_run, run_async_with_dry_run
22
+ from ksadk.cli.error_utils import abort_with_cli_error, remote_error, resolution_error, usage_error
23
+ from ksadk.cli.resource_common import (
24
+ CONTEXT_SETTINGS,
25
+ ResourceActionSet,
26
+ ResourceDescriptor,
27
+ ResourceListSchema,
28
+ ResourceStatusSchema,
29
+ build_resource_group_help,
30
+ confirm_destructive,
31
+ confirm_options,
32
+ pagination_options,
33
+ print_compatibility_hint,
34
+ render_descriptor_list,
35
+ render_descriptor_status,
36
+ )
37
+ from ksadk.cli.ui import print_info, print_kv, print_success, print_warn
38
+ from ksadk.cli.ui import is_json_output, is_stdout_tty, output_option as cli_output_option
39
+ from ksadk.deployment.state import load_state
40
+ from ksadk.deployment.ui_config import resolve_ui_config
41
+ from ksadk.openclaw_gateway import OpenClawGatewayClient
42
+
43
+ _PATH_EMBEDDED_OPTION_HINTS = (
44
+ "--share",
45
+ "--expires-seconds",
46
+ "--force-new",
47
+ "--no-open",
48
+ "--direct",
49
+ "--output",
50
+ "--agent",
51
+ "--agent-id",
52
+ "--region",
53
+ )
54
+
55
+ DEFAULT_PRIVATE_LINK_EXPIRES_SECONDS = 24 * 60 * 60
56
+ MAX_PRIVATE_LINK_EXPIRES_SECONDS = 365 * 24 * 60 * 60
57
+ DEFAULT_REGION = "cn-beijing-6"
58
+
59
+ DASHBOARD_RESOURCE = ResourceDescriptor(
60
+ name="Dashboard",
61
+ summary="Dashboard 资源管理。",
62
+ resource_key="dashboard",
63
+ actions=ResourceActionSet(
64
+ open="agentengine dashboard open [agent_ref]",
65
+ extra=("share",),
66
+ ),
67
+ examples=(
68
+ "agentengine dashboard open",
69
+ "agentengine dashboard open ar-xxxx",
70
+ "agentengine dashboard share list ar-xxxx",
71
+ ),
72
+ missing_ref_message="未找到可用 Agent,请指定 Agent(--agent 或位置参数)",
73
+ resolution_commands=(
74
+ "agentengine agent list",
75
+ "agentengine dashboard open --agent <AgentName|AgentId>",
76
+ ),
77
+ open_action_help="打开 Agent Dashboard",
78
+ extra_action_help=(
79
+ ("share", "管理 Dashboard 分享链接"),
80
+ ),
81
+ )
82
+
83
+ DASHBOARD_SHARE_RESOURCE = ResourceDescriptor(
84
+ name="Dashboard 链接",
85
+ summary="Dashboard 分享链接管理。",
86
+ resource_key="dashboard_share",
87
+ actions=ResourceActionSet(
88
+ list="agentengine dashboard share list [agent_ref]",
89
+ delete="agentengine dashboard share revoke <link_id>",
90
+ ),
91
+ list_schema=ResourceListSchema(
92
+ title="Dashboard 链接列表",
93
+ noun="Dashboard 链接",
94
+ columns=(
95
+ {"header": "ID", "key": "id", "style": "#58a6ff", "no_wrap": True},
96
+ {"header": "类型", "key": "type", "no_wrap": True},
97
+ {"header": "状态", "key": "status", "no_wrap": True},
98
+ {"header": "路径", "key": "path", "no_wrap": True},
99
+ {"header": "过期时间", "key": "expires_at", "overflow": "fold"},
100
+ {"header": "创建时间", "key": "created_at", "overflow": "fold"},
101
+ ),
102
+ empty_message="没有找到匹配的 Dashboard 链接",
103
+ summary_lines=("使用 `agentengine dashboard share revoke <link_id>` 撤销链接。",),
104
+ ),
105
+ status_schema=ResourceStatusSchema(
106
+ title="Dashboard 链接结果",
107
+ next_steps=("agentengine dashboard share list --agent <AgentName|AgentId>",),
108
+ ),
109
+ missing_ref_message="未找到可用 Agent,请指定 Agent(--agent 或位置参数)",
110
+ resolution_commands=(
111
+ "agentengine agent list",
112
+ "agentengine dashboard open --agent <AgentName|AgentId>",
113
+ ),
114
+ list_action_help="列出 Dashboard 分享链接",
115
+ delete_action_help="撤销 Dashboard 分享链接",
116
+ )
117
+
118
+ class DashboardGroup(click.Group):
119
+ """支持 `dashboard open` canonical + `dashboard [agent_ref]` 兼容路径。"""
120
+
121
+ def parse_args(self, ctx, args):
122
+ ctx.ensure_object(dict)
123
+ if args:
124
+ first = args[0]
125
+ if first == "list":
126
+ raise click.UsageError(
127
+ "不支持 `agentengine dashboard list`。打开 Dashboard 请使用 "
128
+ "`agentengine dashboard open [agent_ref]`;查看分享链接请使用 "
129
+ "`agentengine dashboard share list`。"
130
+ )
131
+ if not first.startswith("-") and first not in self.commands:
132
+ ctx.obj["positional_agent_ref"] = first
133
+ args = args[1:]
134
+ return super().parse_args(ctx, args)
135
+
136
+
137
+ def _parse_expires_seconds_option(
138
+ _ctx: click.Context,
139
+ _param: click.Parameter,
140
+ value: Optional[str],
141
+ ) -> Optional[int]:
142
+ if value is None:
143
+ return None
144
+ text = str(value).strip().lower()
145
+ if not text:
146
+ return None
147
+ if text in {"never", "permanent", "forever"}:
148
+ return 0
149
+ try:
150
+ return int(text)
151
+ except ValueError as e:
152
+ raise click.BadParameter("必须是整数秒,或 never") from e
153
+
154
+
155
+ def _abort_dashboard_error(
156
+ err: Exception,
157
+ *,
158
+ context: str | None = None,
159
+ argv: list[str] | None = None,
160
+ show_help: bool = False,
161
+ ) -> None:
162
+ abort_with_cli_error(err, context=context, argv=argv, show_help=show_help)
163
+
164
+
165
+ @click.group(
166
+ "dashboard",
167
+ cls=DashboardGroup,
168
+ invoke_without_command=True,
169
+ context_settings=CONTEXT_SETTINGS,
170
+ help=build_resource_group_help(DASHBOARD_RESOURCE),
171
+ )
172
+ @click.option("--agent", "--agent-id", "agent_option", "-a", hidden=True, help="(兼容) Agent 名称或 ID")
173
+ @click.option("--region", "-r", default=None, envvar="KSYUN_REGION", hidden=True, help="(兼容) 区域")
174
+ @click.option("--path", "ui_path", default=None, hidden=True, help="(兼容) 目标 UI 路径")
175
+ @click.option("--share", is_flag=True, hidden=True, help="(兼容) 创建可分享链接")
176
+ @click.option(
177
+ "--expires-seconds",
178
+ default=None,
179
+ type=str,
180
+ callback=_parse_expires_seconds_option,
181
+ hidden=True,
182
+ help="(兼容) 链接有效期(秒);支持 never(=0)",
183
+ )
184
+ @click.option("--force-new", is_flag=True, hidden=True, help="(兼容) 强制新建链接(跳过复用)")
185
+ @click.option("--no-open", is_flag=True, hidden=True, help="(兼容) 仅打印 URL,不自动打开浏览器")
186
+ @click.option("--direct", is_flag=True, hidden=True, help="(兼容) 直接打开 endpoint/path")
187
+ @cli_output_option(hidden=True)
188
+ @click.pass_context
189
+ def dashboard(
190
+ ctx: click.Context,
191
+ agent_option: Optional[str],
192
+ region: Optional[str],
193
+ ui_path: Optional[str],
194
+ share: bool,
195
+ expires_seconds: Optional[int],
196
+ force_new: bool,
197
+ no_open: bool,
198
+ direct: bool,
199
+ output_mode: str | None,
200
+ ):
201
+ _ = output_mode
202
+ ctx.obj["dashboard_region_source"] = _region_parameter_source(ctx, "region")
203
+ if ctx.invoked_subcommand is not None:
204
+ return
205
+
206
+ positional_ref = None
207
+ if isinstance(ctx.obj, dict):
208
+ positional_ref = ctx.obj.get("positional_agent_ref")
209
+
210
+ print_compatibility_hint(
211
+ legacy="agentengine dashboard",
212
+ canonical="agentengine dashboard open",
213
+ )
214
+ _open_dashboard(
215
+ positional_agent=positional_ref,
216
+ agent_option=agent_option,
217
+ region=region,
218
+ region_source=str(ctx.obj.get("dashboard_region_source") or ""),
219
+ ui_path=ui_path,
220
+ share=share,
221
+ expires_seconds=expires_seconds,
222
+ force_new=force_new,
223
+ no_open=no_open,
224
+ direct=direct,
225
+ )
226
+
227
+
228
+ @dashboard.command("open", context_settings=CONTEXT_SETTINGS)
229
+ @click.argument("agent_ref", required=False)
230
+ @click.option("--agent", "--agent-id", "agent_option", "-a", help="Agent 名称或 ID")
231
+ @click.option("--region", "-r", default=None, envvar="KSYUN_REGION", help="区域")
232
+ @click.option("--path", "ui_path", default=None, help="目标 UI 路径(默认根据配置自动推导)")
233
+ @click.option("--share", is_flag=True, help="创建可分享链接(默认创建私有临时链接)")
234
+ @click.option(
235
+ "--expires-seconds",
236
+ default=None,
237
+ type=str,
238
+ callback=_parse_expires_seconds_option,
239
+ help="链接有效期(秒);支持 never(=0)",
240
+ )
241
+ @click.option("--force-new", is_flag=True, help="强制新建链接(跳过复用)")
242
+ @click.option("--no-open", is_flag=True, help="仅打印 URL,不自动打开浏览器")
243
+ @click.option("--direct", is_flag=True, help="直接打开 endpoint/path(跳过短链接创建)")
244
+ @cli_output_option()
245
+ @click.pass_context
246
+ def dashboard_open(
247
+ ctx: click.Context,
248
+ agent_ref: Optional[str],
249
+ agent_option: Optional[str],
250
+ region: Optional[str],
251
+ ui_path: Optional[str],
252
+ share: bool,
253
+ expires_seconds: Optional[int],
254
+ force_new: bool,
255
+ no_open: bool,
256
+ direct: bool,
257
+ output_mode: str | None,
258
+ ):
259
+ """打开 Agent Dashboard。"""
260
+ _ = output_mode
261
+ _open_dashboard(
262
+ positional_agent=agent_ref,
263
+ agent_option=agent_option,
264
+ region=region,
265
+ region_source=_region_parameter_source(ctx, "region"),
266
+ ui_path=ui_path,
267
+ share=share,
268
+ expires_seconds=expires_seconds,
269
+ force_new=force_new,
270
+ no_open=no_open,
271
+ direct=direct,
272
+ )
273
+
274
+
275
+ @dashboard.group("share", context_settings=CONTEXT_SETTINGS, help=build_resource_group_help(DASHBOARD_SHARE_RESOURCE))
276
+ def dashboard_share():
277
+ pass
278
+
279
+
280
+ @dashboard_share.command("list", context_settings=CONTEXT_SETTINGS)
281
+ @click.argument("agent_ref", required=False)
282
+ @click.option("--agent", "--agent-id", "agent_option", "-a", help="Agent 名称或 ID")
283
+ @click.option("--region", "-r", default=None, envvar="KSYUN_REGION", help="区域")
284
+ @click.option("--type", "link_type", type=click.Choice(["private", "share"]), default=None, help="链接类型过滤")
285
+ @click.option("--status", type=click.Choice(["active", "revoked"]), default=None, help="状态过滤")
286
+ @pagination_options(default_page=1, default_size=20)
287
+ @cli_output_option()
288
+ @click.pass_context
289
+ def dashboard_share_list(
290
+ ctx: click.Context,
291
+ agent_ref: Optional[str],
292
+ agent_option: Optional[str],
293
+ region: Optional[str],
294
+ link_type: Optional[str],
295
+ status: Optional[str],
296
+ page: int,
297
+ size: int,
298
+ output_mode: str | None,
299
+ ):
300
+ """列出 Agent 的 Dashboard 分享链接。"""
301
+ _ = output_mode
302
+ try:
303
+ explicit_ref = merge_agent_inputs(agent_option=agent_option, positional_agent=agent_ref)
304
+ except ValueError as e:
305
+ _abort_dashboard_error(
306
+ usage_error(str(e)),
307
+ argv=["dashboard", "share", "list"],
308
+ )
309
+
310
+ cwd = Path(".").resolve()
311
+ state = load_state(cwd)
312
+ effective_region = _resolve_effective_region(region, state, region_source=_region_parameter_source(ctx, "region"))
313
+ primary_ref, fallback_ref = _resolve_references(explicit_ref, cwd)
314
+ if not primary_ref:
315
+ _abort_dashboard_error(
316
+ resolution_error(
317
+ DASHBOARD_SHARE_RESOURCE.missing_ref_message or "未找到可用 Agent。",
318
+ hints=list(DASHBOARD_SHARE_RESOURCE.resolution_commands),
319
+ ),
320
+ argv=["dashboard", "share", "list"],
321
+ )
322
+
323
+ try:
324
+ detail, _, _ = asyncio.run(_resolve_agent_detail(effective_region, primary_ref, fallback_ref))
325
+ except Exception as e:
326
+ _abort_dashboard_error(e, context="获取 Agent 信息失败", argv=["dashboard", "share", "list"])
327
+ agent_id = (detail.get("agent_id") or "").strip()
328
+ agent_name = (detail.get("name") or "").strip()
329
+ if not agent_id and not agent_name:
330
+ _abort_dashboard_error(
331
+ resolution_error("无法解析 Agent 标识", hints=list(DASHBOARD_SHARE_RESOURCE.resolution_commands)),
332
+ argv=["dashboard", "share", "list"],
333
+ )
334
+
335
+ try:
336
+ result = asyncio.run(
337
+ _list_dashboard_access_links(
338
+ region=effective_region,
339
+ agent_id=agent_id or None,
340
+ agent_name=agent_name or None,
341
+ link_type=link_type,
342
+ status=status,
343
+ page=page,
344
+ size=size,
345
+ )
346
+ )
347
+ except Exception as e:
348
+ _abort_dashboard_error(e, context="查询 Dashboard 链接失败", argv=["dashboard", "share", "list"])
349
+ links = result.get("links") or []
350
+ total = int(result.get("total") or len(links))
351
+ render_descriptor_list(
352
+ DASHBOARD_SHARE_RESOURCE,
353
+ rows=[
354
+ (
355
+ str(item.get("link_id") or "-"),
356
+ str(item.get("link_type") or "-"),
357
+ str(item.get("status") or "-"),
358
+ str(item.get("path") or "/"),
359
+ _format_dashboard_time(item.get("expires_at"), never_text="永久"),
360
+ _format_dashboard_time(item.get("created_at"), never_text="-"),
361
+ )
362
+ for item in links
363
+ ],
364
+ total=total,
365
+ page=page,
366
+ size=size,
367
+ )
368
+ if state and state.get("agent_id"):
369
+ print_kv("当前状态文件 Agent", str(state.get("agent_id")))
370
+
371
+
372
+ @dashboard_share.command("revoke", context_settings=CONTEXT_SETTINGS)
373
+ @click.argument("link_id", required=True)
374
+ @click.option("--region", "-r", default="cn-beijing-6", envvar="KSYUN_REGION", help="区域")
375
+ @confirm_options()
376
+ @dry_run_option()
377
+ @cli_output_option()
378
+ def dashboard_share_revoke(
379
+ link_id: str,
380
+ region: str,
381
+ assume_yes: bool,
382
+ dry_run: bool,
383
+ output_mode: str | None,
384
+ ):
385
+ """撤销 Dashboard 分享链接。"""
386
+ _ = output_mode
387
+ dry_run = effective_dry_run(dry_run)
388
+ if not confirm_destructive(
389
+ assume_yes=assume_yes,
390
+ dry_run=dry_run,
391
+ prompt=f"确定要撤销 Dashboard 分享链接 `{link_id}` 吗?",
392
+ ):
393
+ return
394
+ try:
395
+ result = run_async_with_dry_run(
396
+ _delete_dashboard_access_link(region=region, link_id=link_id.strip(), dry_run=dry_run),
397
+ dry_run=dry_run,
398
+ dry_run_resource="dashboard_share",
399
+ dry_run_action="revoke",
400
+ )
401
+ except Exception as e:
402
+ _abort_dashboard_error(e, context="撤销失败", argv=["dashboard", "share", "revoke"])
403
+ return
404
+ if result is None:
405
+ return
406
+ deleted = bool(result.get("deleted", False))
407
+ if deleted:
408
+ render_descriptor_status(
409
+ DASHBOARD_SHARE_RESOURCE,
410
+ title="Dashboard 链接撤销结果",
411
+ subtitle=link_id,
412
+ fields=[("ID", link_id, "#58a6ff"), ("状态", "已撤销", "ok")],
413
+ action="revoke",
414
+ item={"id": link_id, "status": "revoked", "deleted": True},
415
+ )
416
+ else:
417
+ _abort_dashboard_error(
418
+ remote_error(
419
+ "接口未确认撤销成功。",
420
+ details={"id": link_id, "deleted": False},
421
+ ),
422
+ argv=["dashboard", "share", "revoke"],
423
+ )
424
+
425
+
426
+ def _open_dashboard(
427
+ *,
428
+ positional_agent: Optional[str],
429
+ agent_option: Optional[str],
430
+ region: Optional[str],
431
+ region_source: str,
432
+ ui_path: Optional[str],
433
+ share: bool,
434
+ expires_seconds: Optional[int],
435
+ force_new: bool,
436
+ no_open: bool,
437
+ direct: bool,
438
+ ):
439
+ no_open = bool(no_open or is_json_output() or not is_stdout_tty())
440
+ try:
441
+ _validate_ui_path_option(ui_path)
442
+ except ValueError as e:
443
+ _abort_dashboard_error(usage_error(str(e)), argv=["dashboard", "open"])
444
+ return
445
+
446
+ try:
447
+ explicit_ref = merge_agent_inputs(agent_option=agent_option, positional_agent=positional_agent)
448
+ except ValueError as e:
449
+ _abort_dashboard_error(usage_error(str(e)), argv=["dashboard", "open"])
450
+
451
+ cwd = Path(".").resolve()
452
+ state = load_state(cwd)
453
+ effective_region = _resolve_effective_region(region, state, region_source=region_source)
454
+ primary_ref, fallback_ref = _resolve_references(explicit_ref, cwd)
455
+ if not primary_ref:
456
+ _abort_dashboard_error(
457
+ resolution_error(
458
+ DASHBOARD_RESOURCE.missing_ref_message or "未找到可用 Agent。",
459
+ hints=list(DASHBOARD_RESOURCE.resolution_commands),
460
+ ),
461
+ argv=["dashboard", "open"],
462
+ )
463
+
464
+ if primary_ref.source != "cli":
465
+ print_info(f"未显式指定 Agent,使用 {primary_ref.source_text}: {primary_ref.value}")
466
+
467
+ try:
468
+ detail, used_ref, state_stale = asyncio.run(_resolve_agent_detail(effective_region, primary_ref, fallback_ref))
469
+ except Exception as e:
470
+ _abort_dashboard_error(e, context="获取 Agent 信息失败", argv=["dashboard", "open"])
471
+ return
472
+ if state_stale:
473
+ print_warn(".agentengine.state 指向的 Agent 不存在,已自动回退到项目配置")
474
+ if used_ref.source != primary_ref.source:
475
+ print_info(f"当前使用 {used_ref.source_text}: {used_ref.value}")
476
+
477
+ endpoint = (detail.get("endpoint") or "").strip()
478
+ if not endpoint:
479
+ _abort_dashboard_error(
480
+ resolution_error("目标 Agent 未返回 Endpoint,无法打开 Dashboard"),
481
+ argv=["dashboard", "open"],
482
+ )
483
+
484
+ resolved_ui = resolve_ui_config(
485
+ framework=(detail.get("framework") or "").strip(),
486
+ state=state,
487
+ cli_profile=None,
488
+ cli_path=ui_path,
489
+ cli_url=None,
490
+ )
491
+ normalized_path = _normalize_ui_path(resolved_ui.path or "/")
492
+ custom_ui_enabled = str(resolved_ui.profile or "").strip().lower() == "custom"
493
+ link_path = normalized_path if ui_path is not None or custom_ui_enabled else None
494
+ base_url = _build_base_ui_url(endpoint, normalized_path)
495
+
496
+ if direct:
497
+ _emit_url("打开 Dashboard(direct)", base_url, no_open=no_open)
498
+ return
499
+
500
+ if _is_openclaw_target(state=state, detail=detail):
501
+ openclaw_link_path = _resolve_openclaw_link_path(
502
+ state=state,
503
+ cli_path=ui_path,
504
+ normalized_path=normalized_path,
505
+ )
506
+ try:
507
+ link_data = asyncio.run(
508
+ _create_openclaw_gateway_access_link(
509
+ region=effective_region,
510
+ detail=detail,
511
+ path=openclaw_link_path,
512
+ link_type="share" if share else "private",
513
+ expires_seconds=_normalize_expires_seconds(
514
+ link_type="share" if share else "private",
515
+ expires_seconds=expires_seconds,
516
+ ),
517
+ force_new=force_new,
518
+ )
519
+ )
520
+ except Exception as e:
521
+ _abort_dashboard_error(e, context="创建 OpenClaw gateway 链接失败", argv=["dashboard", "open"])
522
+ return
523
+ _render_dashboard_open_result(detail=detail, link_data=link_data, no_open=no_open)
524
+ return
525
+
526
+ link_type = "share" if share else "private"
527
+ validated_expires = _normalize_expires_seconds(link_type=link_type, expires_seconds=expires_seconds)
528
+ try:
529
+ link_data = asyncio.run(
530
+ _create_dashboard_access_link(
531
+ region=effective_region,
532
+ agent_id=(detail.get("agent_id") or "").strip() or None,
533
+ agent_name=(detail.get("name") or "").strip() or None,
534
+ link_type=link_type,
535
+ path=link_path,
536
+ expires_seconds=validated_expires,
537
+ force_new=force_new,
538
+ )
539
+ )
540
+ except Exception as e:
541
+ _abort_dashboard_error(e, context="创建 Dashboard 链接失败", argv=["dashboard", "open"])
542
+ return
543
+ access_url = (link_data.get("access_url") or "").strip()
544
+ if not access_url:
545
+ _abort_dashboard_error(
546
+ remote_error("CreateDashboardAccessLink 返回为空"),
547
+ argv=["dashboard", "open"],
548
+ )
549
+ _render_dashboard_open_result(detail=detail, link_data=link_data, no_open=no_open, default_link_type=link_type)
550
+
551
+
552
+ def _render_dashboard_open_result(
553
+ *,
554
+ detail: dict,
555
+ link_data: dict,
556
+ no_open: bool,
557
+ default_link_type: str = "private",
558
+ ):
559
+ open_url = (link_data.get("access_url") or "").strip()
560
+ actual_link_type = str(link_data.get("link_type") or default_link_type or "").strip() or default_link_type
561
+
562
+ render_descriptor_status(
563
+ DASHBOARD_SHARE_RESOURCE,
564
+ title="Dashboard 打开结果",
565
+ subtitle=str(detail.get("name") or detail.get("agent_id") or "-"),
566
+ fields=[
567
+ ("ID", str(link_data.get("link_id") or "-"), "#58a6ff"),
568
+ ("类型", actual_link_type, None),
569
+ ("过期时间", _format_dashboard_time(link_data.get("expires_at"), never_text="server-default"), None),
570
+ ],
571
+ action="open",
572
+ item={
573
+ "link_id": str(link_data.get("link_id") or "-"),
574
+ "type": actual_link_type,
575
+ "expires_at": _format_dashboard_time(link_data.get("expires_at"), never_text="server-default"),
576
+ "url": open_url,
577
+ "agent_id": str(detail.get("agent_id") or ""),
578
+ "agent_name": str(detail.get("name") or ""),
579
+ },
580
+ )
581
+ langfuse_url = str(detail.get("langfuse_url") or "").strip()
582
+ if langfuse_url:
583
+ print_kv("Langfuse", langfuse_url, value_style="#58a6ff")
584
+ _emit_url("打开 Dashboard", open_url, no_open=no_open)
585
+
586
+
587
+ def _validate_ui_path_option(ui_path: Optional[str]) -> None:
588
+ if not ui_path:
589
+ return
590
+ path_text = str(ui_path).strip()
591
+ for option_hint in _PATH_EMBEDDED_OPTION_HINTS:
592
+ if option_hint in path_text:
593
+ raise ValueError(
594
+ f"--path 的值疑似拼入了 `{option_hint}`。"
595
+ "请把路径和选项分开,例如:`agentengine dashboard open --path /chat --share`。"
596
+ )
597
+
598
+
599
+ def _resolve_effective_region(region: Optional[str], state: Optional[dict], *, region_source: str) -> str:
600
+ explicit_region = str(region or "").strip()
601
+ if explicit_region and region_source == "commandline":
602
+ return explicit_region
603
+ if explicit_region and region_source == "environment" and not _is_global_config_injected_region():
604
+ return explicit_region
605
+ state_region = str((state or {}).get("region") or "").strip()
606
+ return state_region or explicit_region or DEFAULT_REGION
607
+
608
+
609
+ def _region_parameter_source(ctx: click.Context, name: str) -> str:
610
+ try:
611
+ source = ctx.get_parameter_source(name)
612
+ except Exception:
613
+ return ""
614
+ if source == click.core.ParameterSource.COMMANDLINE:
615
+ return "commandline"
616
+ if source == click.core.ParameterSource.ENVIRONMENT:
617
+ return "environment"
618
+ return ""
619
+
620
+
621
+ def _is_global_config_injected_region() -> bool:
622
+ keys = {
623
+ item.strip()
624
+ for item in os.environ.get("KSADK_GLOBAL_CONFIG_ENV_KEYS", "").split(",")
625
+ if item.strip()
626
+ }
627
+ return "KSYUN_REGION" in keys
628
+
629
+
630
+ def _is_openclaw_target(*, state: Optional[dict], detail: dict) -> bool:
631
+ state_type = str((state or {}).get("type") or "").strip().lower()
632
+ framework = str(detail.get("framework") or "").strip().lower()
633
+ return state_type == "openclaw" or framework == "openclaw"
634
+
635
+
636
+ def _resolve_openclaw_link_path(
637
+ *,
638
+ state: Optional[dict],
639
+ cli_path: Optional[str],
640
+ normalized_path: str,
641
+ ) -> Optional[str]:
642
+ if cli_path is not None:
643
+ return normalized_path
644
+
645
+ state_data = state if isinstance(state, dict) else {}
646
+ nested = state_data.get("ui") if isinstance(state_data.get("ui"), dict) else {}
647
+ state_path = state_data.get("ui_path") or nested.get("path")
648
+ if state_path is None:
649
+ return None
650
+
651
+ # OpenClaw 的历史默认路径曾经落在 / 或 /chat。这里不把 legacy 默认
652
+ # 当作显式 Path 传给 server,让 server 端按当前运行时规则推导。
653
+ state_normalized = _normalize_ui_path(str(state_path))
654
+ if state_normalized in {"/", "/chat"}:
655
+ return None
656
+ return normalized_path
657
+
658
+
659
+ def _emit_url(title: str, url: str, *, no_open: bool):
660
+ print_success(title)
661
+ print_kv("URL", url, value_style="#58a6ff")
662
+ if not no_open:
663
+ webbrowser.open(url)
664
+
665
+
666
+ def _normalize_expires_seconds(*, link_type: str, expires_seconds: Optional[int]) -> Optional[int]:
667
+ if expires_seconds is None:
668
+ return None
669
+ seconds = int(expires_seconds)
670
+ if link_type == "private":
671
+ if seconds < 30 or seconds > MAX_PRIVATE_LINK_EXPIRES_SECONDS:
672
+ raise click.BadParameter(
673
+ f"private 链接 expires-seconds 必须在 30~{MAX_PRIVATE_LINK_EXPIRES_SECONDS}"
674
+ )
675
+ return seconds
676
+ if seconds == 0:
677
+ return 0
678
+ if seconds < 300 or seconds > 2592000:
679
+ raise click.BadParameter("share 链接 expires-seconds 必须为 0 或 300~2592000")
680
+ return seconds
681
+
682
+
683
+ def _resolve_references(
684
+ explicit_ref: Optional[str],
685
+ cwd: Path,
686
+ ) -> Tuple[Optional[ResolvedAgentRef], Optional[ResolvedAgentRef]]:
687
+ if explicit_ref:
688
+ return ResolvedAgentRef(value=explicit_ref, source="cli"), None
689
+
690
+ hermes_state_ref = resolve_agent_ref(None, cwd=cwd, include_state=True, include_project_config=False)
691
+ openclaw_state_ref = resolve_openclaw_ref(
692
+ None,
693
+ cwd=cwd,
694
+ include_state=True,
695
+ )
696
+ config_ref = resolve_agent_ref(
697
+ None,
698
+ cwd=cwd,
699
+ include_state=False,
700
+ include_project_config=True,
701
+ )
702
+ if hermes_state_ref:
703
+ fallback = None
704
+ if config_ref and config_ref.value != hermes_state_ref.value:
705
+ fallback = config_ref
706
+ return hermes_state_ref, fallback
707
+ if openclaw_state_ref:
708
+ fallback = None
709
+ if config_ref and config_ref.value != openclaw_state_ref.value:
710
+ fallback = config_ref
711
+ return (
712
+ ResolvedAgentRef(
713
+ value=openclaw_state_ref.value,
714
+ source=openclaw_state_ref.source,
715
+ source_path=openclaw_state_ref.source_path,
716
+ ),
717
+ fallback,
718
+ )
719
+ return config_ref, None
720
+
721
+
722
+ async def _resolve_agent_detail(
723
+ region: str,
724
+ primary_ref: ResolvedAgentRef,
725
+ fallback_ref: Optional[ResolvedAgentRef],
726
+ ) -> Tuple[dict, ResolvedAgentRef, bool]:
727
+ async with AgentEngineClient(region=region) as client:
728
+ detail, err = await _try_get_agent_detail(client, primary_ref.value)
729
+ if detail:
730
+ return detail, primary_ref, False
731
+
732
+ can_fallback = (
733
+ primary_ref.source.startswith("state.")
734
+ and fallback_ref is not None
735
+ and _is_not_found_error(err)
736
+ )
737
+ if can_fallback:
738
+ fallback_detail, fallback_err = await _try_get_agent_detail(client, fallback_ref.value)
739
+ if fallback_detail:
740
+ return fallback_detail, fallback_ref, True
741
+ if fallback_err:
742
+ raise fallback_err
743
+
744
+ if err:
745
+ raise err
746
+ raise Exception("Agent not found")
747
+
748
+
749
+ async def _try_get_agent_detail(client: AgentEngineClient, agent_ref: str) -> Tuple[Optional[dict], Optional[Exception]]:
750
+ err: Optional[Exception] = None
751
+ for kwargs in ({"agent_id": agent_ref}, {"name": agent_ref}):
752
+ try:
753
+ agent = await client.get_agent(**kwargs)
754
+ if agent:
755
+ return _flatten_agent_detail(agent), None
756
+ except Exception as e:
757
+ err = e
758
+ if not _is_not_found_error(e):
759
+ return None, err
760
+ return None, err
761
+
762
+
763
+ async def _create_dashboard_access_link(
764
+ *,
765
+ region: str,
766
+ agent_id: Optional[str],
767
+ agent_name: Optional[str],
768
+ link_type: str,
769
+ path: Optional[str],
770
+ expires_seconds: Optional[int],
771
+ force_new: bool,
772
+ ) -> dict:
773
+ async with AgentEngineClient(region=region) as client:
774
+ kwargs = {
775
+ "link_type": link_type,
776
+ "path": path,
777
+ "expires_seconds": expires_seconds,
778
+ "force_new": force_new,
779
+ }
780
+ if agent_id:
781
+ kwargs["agent_id"] = agent_id
782
+ elif agent_name:
783
+ kwargs["name"] = agent_name
784
+ else:
785
+ raise Exception("missing agent reference")
786
+ return await client.create_dashboard_access_link(**kwargs)
787
+
788
+
789
+ def _build_openclaw_gateway_client(region: str, detail: dict) -> OpenClawGatewayClient:
790
+ return OpenClawGatewayClient(
791
+ region=region,
792
+ agent_id=str(detail.get("agent_id") or "").strip(),
793
+ agent_name=str(detail.get("name") or "").strip() or None,
794
+ )
795
+
796
+
797
+ async def _create_openclaw_gateway_access_link(
798
+ *,
799
+ region: str,
800
+ detail: dict,
801
+ path: Optional[str] = None,
802
+ link_type: str,
803
+ expires_seconds: Optional[int],
804
+ force_new: bool = False,
805
+ ) -> dict:
806
+ gateway = _build_openclaw_gateway_client(region, detail)
807
+ try:
808
+ info = await gateway.build_access_info(
809
+ path=path,
810
+ expires_seconds=expires_seconds,
811
+ link_type=link_type,
812
+ force_new=force_new,
813
+ )
814
+ finally:
815
+ await gateway.close()
816
+ return {
817
+ "link_id": info.link_id,
818
+ "link_type": link_type,
819
+ "expires_at": info.expires_at,
820
+ "access_url": info.access_url,
821
+ }
822
+
823
+
824
+ async def _list_dashboard_access_links(
825
+ *,
826
+ region: str,
827
+ agent_id: Optional[str],
828
+ agent_name: Optional[str],
829
+ link_type: Optional[str],
830
+ status: Optional[str],
831
+ page: int,
832
+ size: int,
833
+ ) -> dict:
834
+ async with AgentEngineClient(region=region) as client:
835
+ kwargs = {
836
+ "link_type": link_type,
837
+ "status": status,
838
+ "page": int(page),
839
+ "size": int(size),
840
+ }
841
+ if agent_id:
842
+ kwargs["agent_id"] = agent_id
843
+ elif agent_name:
844
+ kwargs["name"] = agent_name
845
+ else:
846
+ raise Exception("missing agent reference")
847
+ return await client.list_dashboard_access_links(**kwargs)
848
+
849
+
850
+ async def _delete_dashboard_access_link(*, region: str, link_id: str, dry_run: bool = False) -> dict:
851
+ async with AgentEngineClient(region=region, dry_run=dry_run) as client:
852
+ return await client.delete_dashboard_access_link(link_id=link_id)
853
+
854
+
855
+ def _flatten_agent_detail(agent: dict) -> dict:
856
+ basic = agent.get("basic", {}) if isinstance(agent, dict) else {}
857
+ quick = agent.get("quick_access", {}) if isinstance(agent, dict) else {}
858
+ deploy = agent.get("deployment", {}) if isinstance(agent, dict) else {}
859
+ adv = agent.get("advanced", {}) if isinstance(agent, dict) else {}
860
+ return {
861
+ "agent_id": basic.get("agent_id") or agent.get("agent_id") or "",
862
+ "name": basic.get("name") or agent.get("name") or "",
863
+ "framework": deploy.get("framework") or basic.get("framework") or agent.get("framework") or "",
864
+ "endpoint": quick.get("public_endpoint") or quick.get("private_endpoint") or agent.get("endpoint") or "",
865
+ "langfuse_url": adv.get("observability_url") or agent.get("langfuse_trace_url") or "",
866
+ }
867
+
868
+
869
+ def _normalize_ui_path(path: str) -> str:
870
+ normalized = (path or "/").strip() or "/"
871
+ if not normalized.startswith("/"):
872
+ normalized = "/" + normalized
873
+ return normalized
874
+
875
+
876
+ def _build_base_ui_url(endpoint: str, ui_path: str) -> str:
877
+ return f"{endpoint.rstrip('/')}{_normalize_ui_path(ui_path)}"
878
+
879
+
880
+ def _is_not_found_error(err: Optional[Exception]) -> bool:
881
+ if isinstance(err, AgentEngineAPIError):
882
+ return err.code == 404 or "not found" in (err.message or "").lower()
883
+ text = str(err or "").lower()
884
+ return "code: 404" in text or "not found" in text
885
+
886
+
887
+ def _format_dashboard_time(value: Optional[str], *, never_text: str) -> str:
888
+ raw = str(value or "").strip()
889
+ if not raw:
890
+ return never_text
891
+ try:
892
+ dt = datetime.fromisoformat(raw.replace("Z", "+00:00"))
893
+ if dt.tzinfo is None:
894
+ dt = dt.replace(tzinfo=timezone.utc)
895
+ beijing = dt.astimezone(timezone(timedelta(hours=8)))
896
+ beijing_text = beijing.strftime("%Y-%m-%d %H:%M:%S CST")
897
+ utc_text = dt.astimezone(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
898
+ return f"{beijing_text} ({utc_text})"
899
+ except Exception:
900
+ return raw