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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.7.0.dist-info}/METADATA +6 -4
  2. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.7.0.dist-info}/RECORD +123 -128
  3. ksadk/api/client.py +19 -0
  4. ksadk/cli/cmd_create.py +34 -7
  5. ksadk/cli/cmd_hermes.py +6 -2
  6. ksadk/cli/cmd_invoke.py +208 -41
  7. ksadk/cli/cmd_mcp.py +6 -1
  8. ksadk/cli/cmd_openclaw.py +6 -2
  9. ksadk/cli/cmd_run.py +13 -6
  10. ksadk/cli/network_options.py +5 -3
  11. ksadk/configs/env_registry.py +1 -0
  12. ksadk/conversations/message_projection.py +269 -0
  13. ksadk/conversations/model_context.py +11 -1
  14. ksadk/conversations/runtime.py +81 -13
  15. ksadk/deployment/base.py +1 -1
  16. ksadk/deployment/providers/serverless.py +18 -8
  17. ksadk/memory/adk/resilient_session_service.py +268 -0
  18. ksadk/memory/adk/short_term_memory.py +21 -6
  19. ksadk/runners/adk_runner.py +974 -115
  20. ksadk/runners/langchain_runner.py +219 -7
  21. ksadk/runners/langgraph_runner.py +145 -12
  22. ksadk/runners/remote_runner.py +143 -18
  23. ksadk/server/app.py +148 -6
  24. ksadk/server/static/assets/{ArtifactsPanel-C0meuOdi.js → ArtifactsPanel-D-SSn2ee.js} +1 -1
  25. ksadk/server/static/assets/{CodeBlock-BbI4HPtJ.js → CodeBlock-P16VOLYi.js} +1 -1
  26. ksadk/server/static/assets/{MathMessageMarkdown-DMLQYoLp.js → MathMessageMarkdown-CdGiQWHR.js} +1 -1
  27. ksadk/server/static/assets/{MermaidBlock-DCR8WZ17.js → MermaidBlock-IOcal8cm.js} +6 -6
  28. ksadk/server/static/assets/{NativeTerminalPanel-CKUvWhUz.js → NativeTerminalPanel-DGSDWsei.js} +1 -1
  29. ksadk/server/static/assets/{arc-bj2rZnP5.js → arc-BA13sHc9.js} +1 -1
  30. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +1 -0
  31. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-2u1ltDIj.js → architectureDiagram-3BPJPVTR-DzJzgVoL.js} +1 -1
  32. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-D6fvdK20.js → blockDiagram-GPEHLZMM-UTdVcZhn.js} +1 -1
  33. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-BK82L5n5.js → c4Diagram-AAUBKEIU-Dix0GD4m.js} +1 -1
  34. ksadk/server/static/assets/channel-CTuydARX.js +1 -0
  35. ksadk/server/static/assets/{chunk-2J33WTMH-DLVdkeyQ.js → chunk-2J33WTMH-C2JxuZ42.js} +1 -1
  36. ksadk/server/static/assets/{chunk-4BX2VUAB-BbwsYcbW.js → chunk-4BX2VUAB-Be57QPgD.js} +1 -1
  37. ksadk/server/static/assets/{chunk-55IACEB6-DOairxzw.js → chunk-55IACEB6-WjSuy4nv.js} +1 -1
  38. ksadk/server/static/assets/{chunk-727SXJPM-hCO487gs.js → chunk-727SXJPM-BOovP-b5.js} +1 -1
  39. ksadk/server/static/assets/{chunk-AQP2D5EJ-XU8vDOuG.js → chunk-AQP2D5EJ-DOmZNmWj.js} +1 -1
  40. ksadk/server/static/assets/{chunk-FMBD7UC4-PrapyfMu.js → chunk-FMBD7UC4-DzwlodkU.js} +1 -1
  41. ksadk/server/static/assets/{chunk-ND2GUHAM-CboKhTZ3.js → chunk-ND2GUHAM-DMqAikEU.js} +1 -1
  42. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +1 -0
  43. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +1 -0
  44. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +1 -0
  45. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-_N8bJ-EU.js → cose-bilkent-S5V4N54A-Zhy2GBnP.js} +1 -1
  46. ksadk/server/static/assets/{dagre-BM42HDAG-FoDlo5J2.js → dagre-BM42HDAG-CbKrtIUz.js} +1 -1
  47. ksadk/server/static/assets/{diagram-2AECGRRQ-BBp6ebBw.js → diagram-2AECGRRQ-BRApgQRK.js} +1 -1
  48. ksadk/server/static/assets/{diagram-5GNKFQAL-CqOvG1PR.js → diagram-5GNKFQAL-D0xbnDiK.js} +1 -1
  49. ksadk/server/static/assets/{diagram-KO2AKTUF-O9T3t6ba.js → diagram-KO2AKTUF-CVugVI9L.js} +1 -1
  50. ksadk/server/static/assets/{diagram-LMA3HP47-CGG8ekBO.js → diagram-LMA3HP47-DozUGgee.js} +1 -1
  51. ksadk/server/static/assets/{diagram-OG6HWLK6-4BmH1EEg.js → diagram-OG6HWLK6-ZOYsKlru.js} +1 -1
  52. ksadk/server/static/assets/{dist-BmuTWcm7.js → dist-2hInLS_J.js} +1 -1
  53. ksadk/server/static/assets/{dist-BMKM66B4.js → dist-8EEyGgDx.js} +1 -1
  54. ksadk/server/static/assets/{dist-Cp1_jKwf.js → dist-8_SfK1IP.js} +1 -1
  55. ksadk/server/static/assets/{dist-CZ6C3x8B.js → dist-B0NP_Z0z.js} +1 -1
  56. ksadk/server/static/assets/{dist-DLeM1OCK.js → dist-BIJVDMuB.js} +1 -1
  57. ksadk/server/static/assets/{dist-Cwhk4lwI.js → dist-BmlMPsCc.js} +1 -1
  58. ksadk/server/static/assets/{dist-D99wf6_X.js → dist-BrCcQ47T.js} +1 -1
  59. ksadk/server/static/assets/{dist-CWiTDN_V.js → dist-BssVmjIo.js} +1 -1
  60. ksadk/server/static/assets/{dist-BVzcWa6D.js → dist-C3HIIaN5.js} +1 -1
  61. ksadk/server/static/assets/{dist-DM0rEQPk.js → dist-CPBtqRTW.js} +1 -1
  62. ksadk/server/static/assets/{dist-BkJjNih3.js → dist-CkEKJFtk.js} +1 -1
  63. ksadk/server/static/assets/{dist-B67uF2uK.js → dist-D-JMdWPQ.js} +1 -1
  64. ksadk/server/static/assets/{dist-DI-oVAXw.js → dist-D-xOD048.js} +1 -1
  65. ksadk/server/static/assets/{dist-6kSZvCZh.js → dist-D57wnGWd.js} +1 -1
  66. ksadk/server/static/assets/{dist-Bk1l05Ni.js → dist-DL_NKc_z.js} +1 -1
  67. ksadk/server/static/assets/{dist-DbaH3p5h.js → dist-DMezvBGJ.js} +1 -1
  68. ksadk/server/static/assets/{dist-CiZHB6ZW.js → dist-DmFaq_Iy.js} +1 -1
  69. ksadk/server/static/assets/{dist-DLMjL01k.js → dist-Dp0k7bWI.js} +1 -1
  70. ksadk/server/static/assets/{dist-DCpZrjaK.js → dist-DpKtt4Bo.js} +1 -1
  71. ksadk/server/static/assets/{dist-D5JGcxBx.js → dist-DyOkZmze.js} +1 -1
  72. ksadk/server/static/assets/{dist-C2DKRFVK.js → dist-DyWsb78Q.js} +1 -1
  73. ksadk/server/static/assets/{dist-S4klkK5W.js → dist-gX6GOLKq.js} +1 -1
  74. ksadk/server/static/assets/{erDiagram-TEJ5UH35-oJhaci7S.js → erDiagram-TEJ5UH35-Bk-9bgE5.js} +1 -1
  75. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +1 -0
  76. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-DtTmUan-.js → flowDiagram-I6XJVG4X-Dn9kZVuZ.js} +1 -1
  77. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BSsb_eij.js → ganttDiagram-6RSMTGT7-BGxXlJqm.js} +1 -1
  78. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +1 -0
  79. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-BR5s6Pws.js → gitGraphDiagram-PVQCEYII-C7Q0X-wi.js} +1 -1
  80. ksadk/server/static/assets/{index-BH7-pC0B.js → index-C00Lwg3L.js} +6 -6
  81. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +1 -0
  82. ksadk/server/static/assets/{infoDiagram-5YYISTIA-DYPc5cvh.js → infoDiagram-5YYISTIA-BO_CSqq5.js} +1 -1
  83. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-MoBdALDg.js → ishikawaDiagram-YF4QCWOH-eYLPLd46.js} +1 -1
  84. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-DgLiQT8l.js → journeyDiagram-JHISSGLW-De9geSb0.js} +1 -1
  85. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-CsFx112F.js → kanban-definition-UN3LZRKU-Cs80kQto.js} +1 -1
  86. ksadk/server/static/assets/{katex-DRsiwpM2.js → katex-DSrCFD8n.js} +1 -1
  87. ksadk/server/static/assets/{linear-TNRQ5Orv.js → linear-CN9sbKTF.js} +1 -1
  88. ksadk/server/static/assets/{mermaid-parser.core-D2eMVOgo.js → mermaid-parser.core-DlgSBU8l.js} +2 -2
  89. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-BtByYFhL.js → mindmap-definition-RKZ34NQL-9afz7Oug.js} +1 -1
  90. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +1 -0
  91. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +1 -0
  92. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPnuCB8c.js → pieDiagram-4H26LBE5-DPv_VstN.js} +1 -1
  93. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-miFpCPv4.js → quadrantDiagram-W4KKPZXB-o77wZ1XK.js} +1 -1
  94. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +1 -0
  95. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-mjB_yYkW.js → requirementDiagram-4Y6WPE33-BYVw81VC.js} +1 -1
  96. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-D7hSlZZZ.js → sankeyDiagram-5OEKKPKP-B7nZFMKT.js} +1 -1
  97. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-D9Cx6hC3.js → sequenceDiagram-3UESZ5HK-BGRRrFw5.js} +1 -1
  98. ksadk/server/static/assets/{stateDiagram-AJRCARHV-D_zrg47o.js → stateDiagram-AJRCARHV-BUfHCoPs.js} +1 -1
  99. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +1 -0
  100. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-CwSec0Wa.js → timeline-definition-PNZ67QCA-FbCTGrf9.js} +1 -1
  101. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +1 -0
  102. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +1 -0
  103. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-agCVobiF.js → vennDiagram-CIIHVFJN-DWgwtPsJ.js} +1 -1
  104. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +1 -0
  105. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-TmrlhWNt.js → wardleyDiagram-YWT4CUSO-2x8G-tTM.js} +1 -1
  106. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-DV71V-ah.js → xychartDiagram-2RQKCTM6-Drma3AYl.js} +1 -1
  107. ksadk/server/static/index.html +1 -1
  108. ksadk/sessions/__init__.py +17 -21
  109. ksadk/sessions/continuity.py +28 -4
  110. ksadk/sessions/postgres_service.py +77 -14
  111. ksadk/sessions/resilience.py +52 -0
  112. ksadk/sessions/resilient.py +360 -0
  113. ksadk/toolsets/__init__.py +2 -0
  114. ksadk/toolsets/workspace.py +49 -10
  115. ksadk/tracing/setup.py +63 -0
  116. ksadk/tui/__init__.py +22 -7
  117. ksadk/tui/loop.py +1877 -0
  118. ksadk/tui/stream_render.py +68 -0
  119. ksadk/version.py +1 -1
  120. ksadk/server/static/assets/architecture-7EHR7CIX-Cr6Xz1_c.js +0 -1
  121. ksadk/server/static/assets/channel-BSSOwFIb.js +0 -1
  122. ksadk/server/static/assets/chunk-QZHKN3VN-XXpdiwUL.js +0 -1
  123. ksadk/server/static/assets/classDiagram-4FO5ZUOK-C5HvGiyK.js +0 -1
  124. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-C5HvGiyK.js +0 -1
  125. ksadk/server/static/assets/eventmodeling-FCH6USID-CIgwHJLL.js +0 -1
  126. ksadk/server/static/assets/gitGraph-WXDBUCRP-BVAJ7uo0.js +0 -1
  127. ksadk/server/static/assets/info-J43DQDTF-MT80V4ge.js +0 -1
  128. ksadk/server/static/assets/packet-YPE3B663-BLKhbXZB.js +0 -1
  129. ksadk/server/static/assets/pie-LRSECV5Y-DFOikjSY.js +0 -1
  130. ksadk/server/static/assets/radar-GUYGQ44K-095b1Ikw.js +0 -1
  131. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-J9kCb0nC.js +0 -1
  132. ksadk/server/static/assets/treeView-BLDUP644-yinfJEY6.js +0 -1
  133. ksadk/server/static/assets/treemap-LRROVOQU-DosUqN1Q.js +0 -1
  134. ksadk/server/static/assets/wardley-L42UT6IY-Bvp7-5uH.js +0 -1
  135. ksadk/tui/app.py +0 -400
  136. ksadk/tui/clipboard.py +0 -100
  137. ksadk/tui/widgets/__init__.py +0 -22
  138. ksadk/tui/widgets/assistant.py +0 -89
  139. ksadk/tui/widgets/base.py +0 -54
  140. ksadk/tui/widgets/chat_input.py +0 -246
  141. ksadk/tui/widgets/history.py +0 -156
  142. ksadk/tui/widgets/system.py +0 -87
  143. ksadk/tui/widgets/thinking.py +0 -110
  144. ksadk/tui/widgets/tool_call.py +0 -161
  145. ksadk/tui/widgets/user.py +0 -37
  146. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.7.0.dist-info}/WHEEL +0 -0
  147. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.7.0.dist-info}/entry_points.txt +0 -0
  148. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.7.0.dist-info}/licenses/LICENSE +0 -0
  149. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,68 @@
1
+ """TUI 流式渲染共享纯函数。
2
+
3
+ 从 RemoteRunner.stream 的归一化 chunk 提取 delta/usage/终止信号,格式化 usage 文本。
4
+ 被 loop.py(交互 TUI)和 cmd_invoke._invoke_once(-m 单次)共用,保证两路径渲染口径一致。
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import re
9
+ from typing import Any, Optional
10
+
11
+
12
+ def clean_response(text: str) -> str:
13
+ """清理 LLM 响应中的内部调试伪影。
14
+
15
+ 只删内部调试残留(Tool Result 标记、python repr 片段、tool_call_id),
16
+ 不动正常的 XML/HTML 标签(用户可能需要 <tag> 输出)。
17
+ """
18
+ text = re.sub(r"\[Tool Result:.*?\]", "", text, flags=re.DOTALL)
19
+ text = re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL)
20
+ text = re.sub(r"name='[^']*'\s*tool_call_id='[^']*'", "", text)
21
+ return text.strip()
22
+
23
+
24
+ def extract_stream_delta(chunk: dict) -> tuple[str, dict | None, bool]:
25
+ """从 RemoteRunner.stream 的 chunk 提取 (delta 文本, usage, 是否终止信号)。
26
+
27
+ - text/thinking 等普通 chunk:取 delta,非终止。
28
+ - final(chat 路径结束,output=完整文本)/ responses_output(responses 路径
29
+ response.completed,output=list):只取 usage,不把 output 当 delta——
30
+ 否则末尾会把完整文本或 list 再 append 一遍(重复/乱码)。
31
+ """
32
+ chunk_type = str(chunk.get("type") or "text")
33
+ if chunk_type in {"final", "responses_output"}:
34
+ usage = chunk.get("usage")
35
+ usage = dict(usage) if isinstance(usage, dict) else None
36
+ # terminal chunk 可能带 metadata.last_usage(上下文用量),合并进 usage
37
+ # 让 TUI 能显示 context 占比,不丢这条 metadata。
38
+ metadata = chunk.get("metadata")
39
+ if isinstance(metadata, dict) and isinstance(metadata.get("last_usage"), dict):
40
+ if usage is None:
41
+ usage = {}
42
+ usage.setdefault("last_usage", dict(metadata["last_usage"]))
43
+ return "", (usage or None), True
44
+ delta = chunk.get("delta") or ""
45
+ if not isinstance(delta, str):
46
+ delta = str(delta or "")
47
+ return delta, None, False
48
+
49
+
50
+ def format_usage(usage: Optional[dict[str, Any]]) -> str:
51
+ """把 usage dict 格式成紧凑文本:↑输入 ↓输出 ⌀总计。
52
+
53
+ 兼容 input_tokens/output_tokens(chat 路径)与 prompt_tokens/completion_tokens
54
+ (responses 路径)两种字段名。
55
+ """
56
+ if not isinstance(usage, dict) or not usage:
57
+ return ""
58
+ inp = usage.get("input_tokens") or usage.get("prompt_tokens")
59
+ out = usage.get("output_tokens") or usage.get("completion_tokens")
60
+ total = usage.get("total_tokens")
61
+ parts = []
62
+ if inp:
63
+ parts.append(f"↑{inp}")
64
+ if out:
65
+ parts.append(f"↓{out}")
66
+ if total:
67
+ parts.append(f"⌀{total}")
68
+ return " ".join(parts)
ksadk/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  """KsADK 版本信息"""
2
2
 
3
- VERSION = "0.6.9"
3
+ VERSION = "0.7.0"
4
4
  __version__ = VERSION
@@ -1 +0,0 @@
1
- import{x as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createArchitectureServices};
@@ -1 +0,0 @@
1
- import{Dn as e,En as t}from"./MermaidBlock-DCR8WZ17.js";var n=(n,r)=>e.lang.round(t.parse(n)[r]);export{n as t};
@@ -1 +0,0 @@
1
- import{kn as e}from"./MermaidBlock-DCR8WZ17.js";var t=class{constructor(e){this.init=e,this.records=this.init()}static{e(this,`ImperativeState`)}reset(){this.records=this.init()}};export{t};
@@ -1 +0,0 @@
1
- import"./chunk-FMBD7UC4-PrapyfMu.js";import"./chunk-ND2GUHAM-CboKhTZ3.js";import"./chunk-55IACEB6-DOairxzw.js";import"./chunk-2J33WTMH-DLVdkeyQ.js";import{i as e,n as t,r as n,t as r}from"./chunk-727SXJPM-hCO487gs.js";import{kn as i}from"./MermaidBlock-DCR8WZ17.js";var a={parser:t,get db(){return new r},renderer:n,styles:e,init:i(e=>{e.class||={},e.class.arrowMarkerAbsolute=e.arrowMarkerAbsolute},`init`)};export{a as diagram};
@@ -1 +0,0 @@
1
- import"./chunk-FMBD7UC4-PrapyfMu.js";import"./chunk-ND2GUHAM-CboKhTZ3.js";import"./chunk-55IACEB6-DOairxzw.js";import"./chunk-2J33WTMH-DLVdkeyQ.js";import{i as e,n as t,r as n,t as r}from"./chunk-727SXJPM-hCO487gs.js";import{kn as i}from"./MermaidBlock-DCR8WZ17.js";var a={parser:t,get db(){return new r},renderer:n,styles:e,init:i(e=>{e.class||={},e.class.arrowMarkerAbsolute=e.arrowMarkerAbsolute},`init`)};export{a as diagram};
@@ -1 +0,0 @@
1
- import{y as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createEventModelingServices};
@@ -1 +0,0 @@
1
- import{_ as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createGitGraphServices};
@@ -1 +0,0 @@
1
- import{h as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createInfoServices};
@@ -1 +0,0 @@
1
- import{p as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createPacketServices};
@@ -1 +0,0 @@
1
- import{d as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createPieServices};
@@ -1 +0,0 @@
1
- import{l as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createRadarServices};
@@ -1 +0,0 @@
1
- import"./chunk-55IACEB6-DOairxzw.js";import"./chunk-2J33WTMH-DLVdkeyQ.js";import{i as e,n as t,r as n,t as r}from"./chunk-AQP2D5EJ-XU8vDOuG.js";import{kn as i}from"./MermaidBlock-DCR8WZ17.js";var a={parser:t,get db(){return new r(2)},renderer:n,styles:e,init:i(e=>{e.state||={},e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},`init`)};export{a as diagram};
@@ -1 +0,0 @@
1
- import{s as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createTreeViewServices};
@@ -1 +0,0 @@
1
- import{a as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createTreemapServices};
@@ -1 +0,0 @@
1
- import{r as e}from"./mermaid-parser.core-D2eMVOgo.js";export{e as createWardleyServices};
ksadk/tui/app.py DELETED
@@ -1,400 +0,0 @@
1
- """
2
- KsADK Agent TUI - 简洁交互界面
3
-
4
- 基本功能:
5
- - 对话交互
6
- - 思考过程显示(通过 --show-thinking 参数控制)
7
- - 工具调用显示
8
- - 退出:输入 exit/quit 或 Ctrl+C/Ctrl+D
9
- """
10
-
11
- from __future__ import annotations
12
-
13
- import asyncio
14
- import os
15
- import uuid
16
- import re
17
- from pathlib import Path
18
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
19
-
20
- from textual import on
21
- from textual.app import App, ComposeResult
22
- from textual.binding import Binding
23
- from textual.containers import Container, Vertical, VerticalScroll
24
- from textual.screen import ModalScreen
25
- from textual.widgets import Static
26
- from textual.events import MouseUp
27
-
28
- from rich.panel import Panel
29
-
30
- from ksadk.tui.clipboard import copy_selection_to_clipboard
31
- from ksadk.tui.widgets.user import UserMessage
32
- from ksadk.tui.widgets.assistant import AssistantMessage
33
- from ksadk.tui.widgets.thinking import ThinkingMessage
34
- from ksadk.tui.widgets.system import SystemMessage
35
- from ksadk.tui.widgets.chat_input import ChatInput
36
-
37
- if TYPE_CHECKING:
38
- from ksadk.runners.base_runner import BaseRunner
39
-
40
-
41
- def _clean_response(text: str) -> str:
42
- """清理 LLM 响应中的内部调试信息"""
43
- text = re.sub(r'\[Tool Result:.*?\]', '', text, flags=re.DOTALL)
44
- text = re.sub(r'<tool_call>.*?</tool_call>', '', text, flags=re.DOTALL)
45
- text = re.sub(r"name='[^']*'\s*tool_call_id='[^']*'", '', text)
46
- return text.strip()
47
-
48
-
49
- class ApprovalScreen(ModalScreen[bool]):
50
- """敏感操作确认弹窗"""
51
-
52
- BINDINGS = [
53
- Binding("y", "approve", "确认"),
54
- Binding("n", "reject", "取消"),
55
- Binding("escape", "reject", "取消"),
56
- ]
57
-
58
- def __init__(self, tool_name: str, args: Dict[str, Any], **kwargs):
59
- super().__init__(**kwargs)
60
- self.tool_name = tool_name
61
- self.tool_args = args
62
-
63
- def compose(self) -> ComposeResult:
64
- args_str = "\n".join(f" {k}: {v}" for k, v in self.tool_args.items()) if self.tool_args else " (无参数)"
65
- yield Container(
66
- Static(
67
- Panel(
68
- f"[bold yellow]⚠️ 需要您确认敏感操作[/]\n\n"
69
- f"[bold]操作:[/] {self.tool_name}\n"
70
- f"[bold]参数:[/]\n{args_str}\n\n"
71
- f"[green]y[/] 确认 [red]n[/] 取消",
72
- title="🔒 确认",
73
- border_style="yellow",
74
- ),
75
- ),
76
- id="approval-dialog",
77
- )
78
-
79
- def action_approve(self) -> None:
80
- self.dismiss(True)
81
-
82
- def action_reject(self) -> None:
83
- self.dismiss(False)
84
-
85
- CSS = """
86
- #approval-dialog {
87
- align: center middle;
88
- width: 60;
89
- height: auto;
90
- }
91
- """
92
-
93
-
94
- class AgentTUI(App):
95
- """KsADK Agent TUI - 简洁交互界面"""
96
-
97
- CSS = """
98
- Screen {
99
- background: $background;
100
- }
101
-
102
- #main-scroll {
103
- height: 100%;
104
- padding: 0 1;
105
- }
106
-
107
- #title-bar {
108
- height: 1;
109
- color: $primary;
110
- padding: 0;
111
- }
112
-
113
- #welcome-area {
114
- height: auto;
115
- padding: 2 0;
116
- content-align: center middle;
117
- text-align: center;
118
- }
119
-
120
- #chat-log {
121
- height: auto;
122
- background: transparent;
123
- padding: 0;
124
- }
125
-
126
- #input-area {
127
- height: auto;
128
- padding: 1 0;
129
- }
130
-
131
- #hint {
132
- height: 1;
133
- color: $text-muted;
134
- padding: 0 0 0 2;
135
- }
136
-
137
- .started #welcome-area {
138
- display: none;
139
- }
140
- """
141
-
142
- BINDINGS = [
143
- Binding("escape", "interrupt", "中断", show=False, priority=True),
144
- Binding("ctrl+c", "quit_or_interrupt", "退出/中断", show=False),
145
- Binding("ctrl+d", "quit_app", "退出", show=False, priority=True),
146
- Binding("ctrl+q", "quit_app", "退出", show=False),
147
- ]
148
-
149
- TITLE = "KsADK"
150
-
151
- def __init__(
152
- self,
153
- runner: "BaseRunner",
154
- show_thinking: bool = False,
155
- project_dir: str = ".",
156
- **kwargs,
157
- ):
158
- super().__init__(**kwargs)
159
- self.runner = runner
160
- self.show_thinking = show_thinking
161
- self.project_dir = Path(project_dir).resolve()
162
-
163
- self.session_id = getattr(runner, "session_id", None) or str(uuid.uuid4())[:8]
164
- if getattr(self.runner, "session_id", None) is None:
165
- self.runner.session_id = self.session_id
166
- self.history: List[Dict[str, str]] = []
167
- self._is_streaming = False
168
- self._started = False
169
- self.model_name = os.getenv("MODEL_NAME", "unknown")
170
-
171
- try:
172
- from ksadk import __version__
173
- self.version = __version__
174
- except ImportError:
175
- self.version = "0.2.0"
176
-
177
- def compose(self) -> ComposeResult:
178
- """构建 UI 布局"""
179
- with VerticalScroll(id="main-scroll"):
180
- yield Static(f"─ KsADK v{self.version} ─", id="title-bar")
181
-
182
- yield Container(
183
- Static(
184
- f"[bold]Welcome![/]\n"
185
- f"🤖\n"
186
- f"[dim]{self.model_name} · Interactive Mode[/]\n"
187
- f"[dim]{self._short_path()}[/]",
188
- id="welcome-content",
189
- ),
190
- id="welcome-area",
191
- )
192
-
193
- with Vertical(id="chat-log"):
194
- pass
195
-
196
- yield Container(
197
- ChatInput(cwd=self.project_dir, id="chat-input-widget"),
198
- Static("Ctrl+C 退出", id="hint"),
199
- id="input-area",
200
- )
201
-
202
- def _short_path(self) -> str:
203
- home = Path.home()
204
- try:
205
- return "~/" + str(self.project_dir.relative_to(home))
206
- except ValueError:
207
- return str(self.project_dir)
208
-
209
- def on_mount(self) -> None:
210
- self.query_one("#chat-input-widget", ChatInput).focus_input()
211
-
212
- @on(ChatInput.Submitted)
213
- async def handle_input(self, event: ChatInput.Submitted) -> None:
214
- """处理用户输入"""
215
- user_input = event.value.strip()
216
-
217
- if not user_input:
218
- return
219
-
220
- # 检查退出
221
- if user_input.lower() in ("exit", "quit", "退出"):
222
- self.exit()
223
- return
224
-
225
- # 隐藏欢迎区域
226
- if not self._started:
227
- self._started = True
228
- self.add_class("started")
229
-
230
- asyncio.create_task(self._stream_response(user_input))
231
-
232
- async def _stream_response(self, user_input: str) -> None:
233
- """流式获取 Agent 响应"""
234
- chat_log = self.query_one("#chat-log", Vertical)
235
- main_scroll = self.query_one("#main-scroll", VerticalScroll)
236
-
237
- self._is_streaming = True
238
-
239
- input_data = {
240
- "input": user_input,
241
- "session_id": self.session_id,
242
- "history": self.history,
243
- }
244
-
245
- thinking_msg: Optional[ThinkingMessage] = None
246
- assistant_msg: Optional[AssistantMessage] = None
247
- full_response_text = ""
248
-
249
- try:
250
- await chat_log.mount(UserMessage(user_input))
251
- main_scroll.scroll_end(animate=False)
252
-
253
- async for chunk in self.runner.stream(input_data):
254
- if not self._is_streaming:
255
- if thinking_msg:
256
- thinking_msg.stop()
257
- if assistant_msg:
258
- await assistant_msg.stop_stream()
259
- await chat_log.mount(SystemMessage("已中断", level="warning"))
260
- break
261
-
262
- chunk_type = chunk.get("type", "text")
263
-
264
- # 思考过程
265
- if chunk_type == "thinking":
266
- delta = chunk.get("delta", "")
267
- if delta and self.show_thinking:
268
- if not thinking_msg:
269
- thinking_msg = ThinkingMessage()
270
- await chat_log.mount(thinking_msg)
271
- main_scroll.scroll_end(animate=False)
272
- await thinking_msg.append_content(delta)
273
- continue
274
-
275
- if thinking_msg and thinking_msg.is_active:
276
- thinking_msg.stop()
277
-
278
- # 中断/确认
279
- if chunk_type == "interrupt":
280
- await self._handle_interrupt(chunk)
281
- return
282
-
283
- # 工具调用 - 跳过不显示
284
- if chunk_type == "tool_call":
285
- continue
286
-
287
- # 文本响应
288
- delta = chunk.get("output", "") or chunk.get("delta", "")
289
- if delta:
290
- if not assistant_msg:
291
- assistant_msg = AssistantMessage()
292
- await chat_log.mount(assistant_msg)
293
- main_scroll.scroll_end(animate=False)
294
- await assistant_msg.append_content(delta)
295
- full_response_text += delta
296
-
297
- if thinking_msg:
298
- thinking_msg.stop()
299
- if assistant_msg:
300
- await assistant_msg.stop_stream()
301
-
302
- cleaned_response = _clean_response(full_response_text)
303
- if cleaned_response:
304
- self.history.append({"role": "user", "content": user_input})
305
- self.history.append({"role": "model", "content": cleaned_response})
306
- elif self._is_streaming and not full_response_text:
307
- result = await self.runner.invoke(input_data)
308
- response_text = result.get("output", "")
309
- cleaned_response = _clean_response(response_text)
310
-
311
- if cleaned_response:
312
- assistant_msg = AssistantMessage()
313
- await chat_log.mount(assistant_msg)
314
- await assistant_msg.append_content(cleaned_response)
315
- await assistant_msg.stop_stream()
316
- self.history.append({"role": "user", "content": user_input})
317
- self.history.append({"role": "model", "content": cleaned_response})
318
- else:
319
- await chat_log.mount(SystemMessage("(无响应)", level="warning"))
320
-
321
- except asyncio.CancelledError:
322
- await chat_log.mount(SystemMessage("已取消", level="warning"))
323
- except Exception as e:
324
- await chat_log.mount(SystemMessage(f"错误: {e}", level="error"))
325
- finally:
326
- self._is_streaming = False
327
- main_scroll.scroll_end(animate=False)
328
-
329
- async def _handle_interrupt(self, interrupt_chunk: Dict[str, Any]) -> None:
330
- """处理敏感操作确认"""
331
- interrupt_info = interrupt_chunk.get("interrupt_info", {})
332
-
333
- if isinstance(interrupt_info, dict):
334
- tool_name = interrupt_info.get("tool", "未知操作")
335
- args = interrupt_info.get("args", {})
336
- elif isinstance(interrupt_info, list) and interrupt_info:
337
- first = interrupt_info[0]
338
- tool_name = str(getattr(first, "value", first))
339
- args = {}
340
- else:
341
- tool_name = str(interrupt_info)
342
- args = {}
343
-
344
- approved = await self.push_screen_wait(ApprovalScreen(tool_name, args))
345
- chat_log = self.query_one("#chat-log", Vertical)
346
-
347
- if approved:
348
- await chat_log.mount(SystemMessage("✓ 已确认,继续执行...", level="success"))
349
-
350
- resume_data = {
351
- "input": "确认",
352
- "session_id": interrupt_chunk.get("session_id", self.session_id),
353
- "history": self.history,
354
- "resume": True,
355
- }
356
-
357
- assistant_msg = AssistantMessage()
358
- await chat_log.mount(assistant_msg)
359
-
360
- try:
361
- async for chunk in self.runner.stream(resume_data):
362
- delta = chunk.get("output", "") or chunk.get("delta", "")
363
- if delta:
364
- await assistant_msg.append_content(delta)
365
- await assistant_msg.stop_stream()
366
- if assistant_msg.content:
367
- self.history.append({"role": "model", "content": assistant_msg.content})
368
- except Exception as e:
369
- await chat_log.mount(SystemMessage(f"错误: {e}", level="error"))
370
- else:
371
- await chat_log.mount(SystemMessage("✗ 已取消操作", level="warning"))
372
-
373
- def action_interrupt(self) -> None:
374
- self._is_streaming = False
375
-
376
- def action_quit_or_interrupt(self) -> None:
377
- if self._is_streaming:
378
- self.action_interrupt()
379
- else:
380
- self.exit()
381
-
382
- def action_quit_app(self) -> None:
383
- self.exit()
384
-
385
- def on_mouse_up(self, event: MouseUp) -> None:
386
- copy_selection_to_clipboard(self)
387
-
388
-
389
- def run_tui(
390
- runner: "BaseRunner",
391
- show_thinking: bool = False,
392
- project_dir: str = ".",
393
- ) -> None:
394
- """启动 TUI 应用"""
395
- app = AgentTUI(
396
- runner=runner,
397
- show_thinking=show_thinking,
398
- project_dir=project_dir,
399
- )
400
- app.run()
ksadk/tui/clipboard.py DELETED
@@ -1,100 +0,0 @@
1
- """剪贴板工具 - 支持鼠标选择复制"""
2
-
3
- from __future__ import annotations
4
-
5
- import base64
6
- import os
7
- from typing import TYPE_CHECKING
8
-
9
- if TYPE_CHECKING:
10
- from textual.app import App
11
-
12
- _PREVIEW_MAX_LENGTH = 40
13
-
14
-
15
- def _copy_osc52(text: str) -> None:
16
- """使用 OSC 52 转义序列复制(支持 SSH/tmux)"""
17
- encoded = base64.b64encode(text.encode("utf-8")).decode("ascii")
18
- osc52_seq = f"\033]52;c;{encoded}\a"
19
- if os.environ.get("TMUX"):
20
- osc52_seq = f"\033Ptmux;\033{osc52_seq}\033\\"
21
-
22
- try:
23
- with open("/dev/tty", "w") as tty:
24
- tty.write(osc52_seq)
25
- tty.flush()
26
- except Exception:
27
- raise RuntimeError("OSC52 复制失败")
28
-
29
-
30
- def _shorten_preview(texts: list[str]) -> str:
31
- """缩短文本预览"""
32
- dense_text = "⏎".join(texts).replace("\n", "⏎")
33
- if len(dense_text) > _PREVIEW_MAX_LENGTH:
34
- return f"{dense_text[: _PREVIEW_MAX_LENGTH - 1]}…"
35
- return dense_text
36
-
37
-
38
- def _clipboard_copy_methods(app: App):
39
- copy_methods = []
40
- if os.name != "nt":
41
- copy_methods.append(_copy_osc52)
42
-
43
- try:
44
- import pyperclip
45
- copy_methods.append(pyperclip.copy)
46
- except ImportError:
47
- pass
48
-
49
- copy_methods.append(app.copy_to_clipboard)
50
- return copy_methods
51
-
52
-
53
- def copy_selection_to_clipboard(app: App) -> None:
54
- """复制选中文本到剪贴板
55
-
56
- 遍历所有 widgets 获取选中文本并复制到系统剪贴板
57
- """
58
- selected_texts = []
59
-
60
- for widget in app.query("*"):
61
- if not hasattr(widget, "text_selection") or not widget.text_selection:
62
- continue
63
-
64
- selection = widget.text_selection
65
-
66
- try:
67
- result = widget.get_selection(selection)
68
- except Exception:
69
- continue
70
-
71
- if not result:
72
- continue
73
-
74
- selected_text, _ = result
75
- if selected_text.strip():
76
- selected_texts.append(selected_text)
77
-
78
- if not selected_texts:
79
- return
80
-
81
- combined_text = "\n".join(selected_texts)
82
-
83
- for copy_fn in _clipboard_copy_methods(app):
84
- try:
85
- copy_fn(combined_text)
86
- app.notify(
87
- f'"{_shorten_preview(selected_texts)}" 已复制',
88
- severity="information",
89
- timeout=2,
90
- )
91
- return
92
- except Exception:
93
- continue
94
-
95
- # 所有方式都失败
96
- app.notify(
97
- "复制失败 - 剪贴板不可用",
98
- severity="warning",
99
- timeout=3,
100
- )
@@ -1,22 +0,0 @@
1
- """
2
- TUI Widgets - 消息组件
3
-
4
- 提供各类消息组件,用于 TUI 渲染。
5
- 参考 deepagents-cli 的消息组件设计。
6
- """
7
-
8
- from .base import MessageWidget
9
- from .user import UserMessage
10
- from .assistant import AssistantMessage
11
- from .thinking import ThinkingMessage
12
- from .tool_call import ToolCallMessage
13
- from .system import SystemMessage
14
-
15
- __all__ = [
16
- "MessageWidget",
17
- "UserMessage",
18
- "AssistantMessage",
19
- "ThinkingMessage",
20
- "ToolCallMessage",
21
- "SystemMessage",
22
- ]