@researai/deepscientist 1.5.0 → 1.5.1

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 (163) hide show
  1. package/AGENTS.md +26 -0
  2. package/README.md +19 -179
  3. package/assets/connectors/lingzhu/openclaw-bridge/README.md +124 -0
  4. package/assets/connectors/lingzhu/openclaw-bridge/index.ts +162 -0
  5. package/assets/connectors/lingzhu/openclaw-bridge/openclaw.plugin.json +145 -0
  6. package/assets/connectors/lingzhu/openclaw-bridge/package.json +35 -0
  7. package/assets/connectors/lingzhu/openclaw-bridge/src/cli.ts +180 -0
  8. package/assets/connectors/lingzhu/openclaw-bridge/src/config.ts +196 -0
  9. package/assets/connectors/lingzhu/openclaw-bridge/src/debug-log.ts +111 -0
  10. package/assets/connectors/lingzhu/openclaw-bridge/src/events.ts +4 -0
  11. package/assets/connectors/lingzhu/openclaw-bridge/src/http-handler.ts +1133 -0
  12. package/assets/connectors/lingzhu/openclaw-bridge/src/image-cache.ts +75 -0
  13. package/assets/connectors/lingzhu/openclaw-bridge/src/lingzhu-tools.ts +246 -0
  14. package/assets/connectors/lingzhu/openclaw-bridge/src/transform.ts +541 -0
  15. package/assets/connectors/lingzhu/openclaw-bridge/src/types.ts +131 -0
  16. package/assets/connectors/lingzhu/openclaw-bridge/tsconfig.json +14 -0
  17. package/assets/connectors/lingzhu/openclaw.lingzhu.config.template.json +39 -0
  18. package/bin/ds.js +233 -53
  19. package/docs/en/00_QUICK_START.md +134 -0
  20. package/docs/en/01_SETTINGS_REFERENCE.md +1104 -0
  21. package/docs/en/02_START_RESEARCH_GUIDE.md +404 -0
  22. package/docs/en/03_QQ_CONNECTOR_GUIDE.md +325 -0
  23. package/docs/en/04_LINGZHU_CONNECTOR_GUIDE.md +216 -0
  24. package/docs/en/05_TUI_GUIDE.md +141 -0
  25. package/docs/en/06_RUNTIME_AND_CANVAS.md +679 -0
  26. package/docs/en/07_MEMORY_AND_MCP.md +253 -0
  27. package/docs/en/08_FIGURE_STYLE_GUIDE.md +97 -0
  28. package/docs/en/09_DOCTOR.md +108 -0
  29. package/docs/en/90_ARCHITECTURE.md +245 -0
  30. package/docs/en/91_DEVELOPMENT.md +195 -0
  31. package/docs/en/99_ACKNOWLEDGEMENTS.md +29 -0
  32. package/docs/zh/00_QUICK_START.md +134 -0
  33. package/docs/zh/01_SETTINGS_REFERENCE.md +1137 -0
  34. package/docs/zh/02_START_RESEARCH_GUIDE.md +414 -0
  35. package/docs/zh/03_QQ_CONNECTOR_GUIDE.md +324 -0
  36. package/docs/zh/04_LINGZHU_CONNECTOR_GUIDE.md +230 -0
  37. package/docs/zh/05_TUI_GUIDE.md +128 -0
  38. package/docs/zh/06_RUNTIME_AND_CANVAS.md +271 -0
  39. package/docs/zh/07_MEMORY_AND_MCP.md +235 -0
  40. package/docs/zh/08_FIGURE_STYLE_GUIDE.md +97 -0
  41. package/docs/zh/09_DOCTOR.md +112 -0
  42. package/docs/zh/99_ACKNOWLEDGEMENTS.md +29 -0
  43. package/install.sh +32 -8
  44. package/package.json +4 -2
  45. package/pyproject.toml +1 -1
  46. package/src/deepscientist/artifact/guidance.py +9 -2
  47. package/src/deepscientist/artifact/service.py +482 -22
  48. package/src/deepscientist/bash_exec/monitor.py +27 -5
  49. package/src/deepscientist/bash_exec/runtime.py +639 -0
  50. package/src/deepscientist/bash_exec/service.py +99 -16
  51. package/src/deepscientist/bridges/base.py +3 -0
  52. package/src/deepscientist/bridges/connectors.py +292 -13
  53. package/src/deepscientist/channels/qq.py +19 -2
  54. package/src/deepscientist/channels/relay.py +1 -0
  55. package/src/deepscientist/cli.py +32 -25
  56. package/src/deepscientist/config/models.py +28 -2
  57. package/src/deepscientist/config/service.py +201 -6
  58. package/src/deepscientist/connector_runtime.py +2 -0
  59. package/src/deepscientist/daemon/api/handlers.py +50 -5
  60. package/src/deepscientist/daemon/api/router.py +1 -0
  61. package/src/deepscientist/daemon/app.py +442 -15
  62. package/src/deepscientist/doctor.py +444 -0
  63. package/src/deepscientist/home.py +1 -0
  64. package/src/deepscientist/latex_runtime.py +17 -4
  65. package/src/deepscientist/lingzhu_support.py +182 -0
  66. package/src/deepscientist/mcp/server.py +49 -2
  67. package/src/deepscientist/prompts/builder.py +181 -58
  68. package/src/deepscientist/quest/layout.py +1 -0
  69. package/src/deepscientist/quest/service.py +63 -2
  70. package/src/deepscientist/quest/stage_views.py +19 -1
  71. package/src/deepscientist/runtime_tools/__init__.py +16 -0
  72. package/src/deepscientist/runtime_tools/builtins.py +19 -0
  73. package/src/deepscientist/runtime_tools/models.py +29 -0
  74. package/src/deepscientist/runtime_tools/registry.py +40 -0
  75. package/src/deepscientist/runtime_tools/service.py +59 -0
  76. package/src/deepscientist/runtime_tools/tinytex.py +25 -0
  77. package/src/deepscientist/tinytex.py +276 -0
  78. package/src/prompts/connectors/lingzhu.md +12 -0
  79. package/src/prompts/connectors/qq.md +121 -0
  80. package/src/prompts/system.md +177 -33
  81. package/src/skills/analysis-campaign/SKILL.md +22 -6
  82. package/src/skills/baseline/SKILL.md +5 -4
  83. package/src/skills/decision/SKILL.md +4 -3
  84. package/src/skills/experiment/SKILL.md +5 -4
  85. package/src/skills/finalize/SKILL.md +5 -4
  86. package/src/skills/idea/SKILL.md +5 -4
  87. package/src/skills/intake-audit/SKILL.md +277 -0
  88. package/src/skills/intake-audit/references/state-audit-template.md +41 -0
  89. package/src/skills/rebuttal/SKILL.md +407 -0
  90. package/src/skills/rebuttal/references/action-plan-template.md +63 -0
  91. package/src/skills/rebuttal/references/evidence-update-template.md +30 -0
  92. package/src/skills/rebuttal/references/response-letter-template.md +113 -0
  93. package/src/skills/rebuttal/references/review-matrix-template.md +55 -0
  94. package/src/skills/review/SKILL.md +293 -0
  95. package/src/skills/review/references/experiment-todo-template.md +29 -0
  96. package/src/skills/review/references/review-report-template.md +83 -0
  97. package/src/skills/review/references/revision-log-template.md +40 -0
  98. package/src/skills/scout/SKILL.md +5 -4
  99. package/src/skills/write/SKILL.md +7 -3
  100. package/src/tui/dist/components/WelcomePanel.js +17 -43
  101. package/src/tui/dist/components/messages/BashExecOperationMessage.js +3 -2
  102. package/src/tui/package.json +1 -1
  103. package/src/ui/dist/assets/{AiManusChatView-7v-dHngU.js → AiManusChatView-w5lF2Ttt.js} +109 -575
  104. package/src/ui/dist/assets/{AnalysisPlugin-B_Xmz-KE.js → AnalysisPlugin-DJOED79I.js} +1 -1
  105. package/src/ui/dist/assets/{AutoFigurePlugin-Cko-0tm1.js → AutoFigurePlugin-DaG61Y0M.js} +63 -8
  106. package/src/ui/dist/assets/{CliPlugin-BsU0ht7q.js → CliPlugin-CV4LqUB_.js} +43 -609
  107. package/src/ui/dist/assets/{CodeEditorPlugin-DcMMP0Rt.js → CodeEditorPlugin-DylfAea4.js} +8 -8
  108. package/src/ui/dist/assets/{CodeViewerPlugin-BqoQ5QyY.js → CodeViewerPlugin-F7saY0LM.js} +5 -5
  109. package/src/ui/dist/assets/{DocViewerPlugin-D7eHNhU6.js → DocViewerPlugin-COP0c7jf.js} +3 -3
  110. package/src/ui/dist/assets/{GitDiffViewerPlugin-DLJN42T5.js → GitDiffViewerPlugin-CAS05pT9.js} +1 -1
  111. package/src/ui/dist/assets/{ImageViewerPlugin-gJMV7MOu.js → ImageViewerPlugin-Bco1CN_w.js} +5 -6
  112. package/src/ui/dist/assets/{LabCopilotPanel-B857sfxP.js → LabCopilotPanel-CvMlCD99.js} +12 -15
  113. package/src/ui/dist/assets/LabPlugin-BYankkE4.js +2676 -0
  114. package/src/ui/dist/assets/LabPlugin-D9jVIo0A.css +2698 -0
  115. package/src/ui/dist/assets/{LatexPlugin-DWKEo-Wj.js → LatexPlugin-LDSMR-t-.js} +16 -16
  116. package/src/ui/dist/assets/{MarkdownViewerPlugin-DBzoEmhv.js → MarkdownViewerPlugin-B7o80jgm.js} +4 -4
  117. package/src/ui/dist/assets/{MarketplacePlugin-DoHc-8vo.js → MarketplacePlugin-CM6ZOcpC.js} +3 -3
  118. package/src/ui/dist/assets/{NotebookEditor-CKjKH-yS.js → NotebookEditor-Dc61cXmK.js} +3 -3
  119. package/src/ui/dist/assets/{PdfLoader-zFoL0VPo.js → PdfLoader-DWowuQwx.js} +1 -1
  120. package/src/ui/dist/assets/{PdfMarkdownPlugin-DXPaL9Nt.js → PdfMarkdownPlugin-BsJM1q_a.js} +3 -3
  121. package/src/ui/dist/assets/{PdfViewerPlugin-DhK8qCFp.js → PdfViewerPlugin-DB2eEEFQ.js} +10 -10
  122. package/src/ui/dist/assets/{SearchPlugin-CdSi6krf.js → SearchPlugin-CraThSvt.js} +1 -1
  123. package/src/ui/dist/assets/{Stepper-V-WiDQJl.js → Stepper-CgocRTPq.js} +1 -1
  124. package/src/ui/dist/assets/{TextViewerPlugin-hIs1Efiu.js → TextViewerPlugin-B1JGhKtd.js} +4 -4
  125. package/src/ui/dist/assets/{VNCViewer-DG8b0q2X.js → VNCViewer-CclFC7FM.js} +9 -10
  126. package/src/ui/dist/assets/{bibtex-HDac6fVW.js → bibtex-D3IKsMl7.js} +1 -1
  127. package/src/ui/dist/assets/{code-BnBeNxBc.js → code-BP37Xx0p.js} +1 -1
  128. package/src/ui/dist/assets/{file-content-IRQ3jHb8.js → file-content-BAJSu-9r.js} +1 -1
  129. package/src/ui/dist/assets/{file-diff-panel-DZoQ9I6r.js → file-diff-panel-DUGeCTuy.js} +1 -1
  130. package/src/ui/dist/assets/{file-socket-BMCdLc-P.js → file-socket-CXc1Ojf7.js} +1 -1
  131. package/src/ui/dist/assets/{file-utils-CltILB3w.js → file-utils-2J21jt7M.js} +1 -1
  132. package/src/ui/dist/assets/{image-Boe6ffhu.js → image-CMMmgvcn.js} +1 -1
  133. package/src/ui/dist/assets/{index-BlplpvE1.js → index-BaVumsQT.js} +2 -2
  134. package/src/ui/dist/assets/{index-DZqJ-qAM.js → index-CWgMgpow.js} +60 -2154
  135. package/src/ui/dist/assets/{index-DO43pFZP.js → index-DmwmJmbW.js} +6372 -8434
  136. package/src/ui/dist/assets/{index-Bq2bvfkl.css → index-KGt-z-dD.css} +225 -2920
  137. package/src/ui/dist/assets/{index-2Zf65FZt.js → index-s7aHnNQ4.js} +1 -1
  138. package/src/ui/dist/assets/{message-square-mUHn_Ssb.js → message-square-CQRfX0Am.js} +1 -1
  139. package/src/ui/dist/assets/{monaco-fe0arNEU.js → monaco-B4TbdsrF.js} +1 -1
  140. package/src/ui/dist/assets/{popover-D_7i19qU.js → popover-B8Rokodk.js} +1 -1
  141. package/src/ui/dist/assets/{project-sync-DyVGrU7H.js → project-sync-D_i96KH4.js} +2 -8
  142. package/src/ui/dist/assets/{sigma-BzazRyxQ.js → sigma-D12PnzCN.js} +1 -1
  143. package/src/ui/dist/assets/{tooltip-DN_yjHFH.js → tooltip-B6YrI4aJ.js} +1 -1
  144. package/src/ui/dist/assets/trash-Bc8jGp0V.js +32 -0
  145. package/src/ui/dist/assets/{useCliAccess-DV2L2Qxy.js → useCliAccess-mXVCYSZ-.js} +12 -42
  146. package/src/ui/dist/assets/{useFileDiffOverlay-DyTj-p_V.js → useFileDiffOverlay-Bg6b9H9K.js} +1 -1
  147. package/src/ui/dist/assets/{wrap-text-ozYHtUwq.js → wrap-text-Drh5GEnL.js} +1 -1
  148. package/src/ui/dist/assets/{zoom-out-BN9MUyCQ.js → zoom-out-CJj9DZLn.js} +1 -1
  149. package/src/ui/dist/index.html +2 -2
  150. package/assets/fonts/Inter-Variable.ttf +0 -0
  151. package/assets/fonts/NotoSerifSC-Regular-C94HN_ZN.ttf +0 -0
  152. package/assets/fonts/NunitoSans-Variable.ttf +0 -0
  153. package/assets/fonts/Satoshi-Medium-ByP-Zb-9.woff2 +0 -0
  154. package/assets/fonts/SourceSans3-Variable.ttf +0 -0
  155. package/assets/fonts/ds-fonts.css +0 -83
  156. package/src/ui/dist/assets/Inter-Variable-VF2RPR_K.ttf +0 -0
  157. package/src/ui/dist/assets/LabPlugin-bL7rpic8.js +0 -43
  158. package/src/ui/dist/assets/NotoSerifSC-Regular-C94HN_ZN-C94HN_ZN.ttf +0 -0
  159. package/src/ui/dist/assets/NunitoSans-Variable-B_ZymHAd.ttf +0 -0
  160. package/src/ui/dist/assets/Satoshi-Medium-ByP-Zb-9-GkA34YXu.woff2 +0 -0
  161. package/src/ui/dist/assets/SourceSans3-Variable-CD-WOsSK.ttf +0 -0
  162. package/src/ui/dist/assets/info-CcsK_htA.js +0 -18
  163. package/src/ui/dist/assets/user-plus-BusDx-hF.js +0 -79
@@ -0,0 +1,75 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ const IMAGE_CACHE_DIR = path.resolve(__dirname, "../../.cache/img");
7
+ const DEFAULT_MAX_AGE_HOURS = 24;
8
+ const CLEANUP_INTERVAL_MS = 6 * 60 * 60 * 1000;
9
+
10
+ let lastCleanupAt = 0;
11
+
12
+ export function getImageCacheDir(): string {
13
+ return IMAGE_CACHE_DIR;
14
+ }
15
+
16
+ export async function ensureImageCacheDir(): Promise<string> {
17
+ await fs.mkdir(IMAGE_CACHE_DIR, { recursive: true });
18
+ return IMAGE_CACHE_DIR;
19
+ }
20
+
21
+ export async function cleanupImageCache(maxAgeHours = DEFAULT_MAX_AGE_HOURS): Promise<{
22
+ removed: number;
23
+ kept: number;
24
+ }> {
25
+ const cacheDir = await ensureImageCacheDir();
26
+ const entries = await fs.readdir(cacheDir, { withFileTypes: true }).catch(() => []);
27
+ const now = Date.now();
28
+ const maxAgeMs = Math.max(1, maxAgeHours) * 60 * 60 * 1000;
29
+ let removed = 0;
30
+ let kept = 0;
31
+
32
+ for (const entry of entries) {
33
+ if (!entry.isFile()) {
34
+ continue;
35
+ }
36
+
37
+ const filePath = path.join(cacheDir, entry.name);
38
+ try {
39
+ const stat = await fs.stat(filePath);
40
+ if (now - stat.mtimeMs > maxAgeMs) {
41
+ await fs.unlink(filePath);
42
+ removed += 1;
43
+ } else {
44
+ kept += 1;
45
+ }
46
+ } catch {
47
+ // Ignore per-file cleanup failures.
48
+ }
49
+ }
50
+
51
+ lastCleanupAt = now;
52
+ return { removed, kept };
53
+ }
54
+
55
+ export async function cleanupImageCacheIfNeeded(maxAgeHours = DEFAULT_MAX_AGE_HOURS): Promise<void> {
56
+ const now = Date.now();
57
+ if (now - lastCleanupAt < CLEANUP_INTERVAL_MS) {
58
+ return;
59
+ }
60
+
61
+ await cleanupImageCache(maxAgeHours).catch(() => undefined);
62
+ }
63
+
64
+ export async function summarizeImageCache(): Promise<{
65
+ dir: string;
66
+ files: number;
67
+ }> {
68
+ const cacheDir = await ensureImageCacheDir();
69
+ const entries = await fs.readdir(cacheDir, { withFileTypes: true }).catch(() => []);
70
+ const files = entries.filter((entry) => entry.isFile()).length;
71
+ return {
72
+ dir: cacheDir,
73
+ files,
74
+ };
75
+ }
@@ -0,0 +1,246 @@
1
+ import type { LingzhuToolCall } from "./types.js";
2
+ import { lingzhuEventBus } from "./events.js";
3
+ import { parseToolCallFromAccumulated } from "./transform.js";
4
+
5
+ type ToolParameters = {
6
+ type: "object";
7
+ properties: Record<string, unknown>;
8
+ required?: string[];
9
+ };
10
+
11
+ type ToolExecuteResult = {
12
+ content: Array<{
13
+ type: "text";
14
+ text: string;
15
+ }>;
16
+ };
17
+
18
+ type LingzhuToolDefinition = {
19
+ name: string;
20
+ command: LingzhuToolCall["command"];
21
+ description: string;
22
+ parameters: ToolParameters;
23
+ experimental?: boolean;
24
+ statusText?: (params: Record<string, unknown>) => string;
25
+ };
26
+
27
+ const EMPTY_PARAMS: ToolParameters = {
28
+ type: "object",
29
+ properties: {},
30
+ required: [],
31
+ };
32
+
33
+ const TOOL_DEFINITIONS: LingzhuToolDefinition[] = [
34
+ {
35
+ name: "take_photo",
36
+ command: "take_photo",
37
+ description: "使用灵珠设备的摄像头拍照。当用户要求拍照、拍摄、照相时,必须调用此工具,或者有使用关于视觉能力(看一下这个东西,看一下我前面有什么)。",
38
+ parameters: EMPTY_PARAMS,
39
+ statusText: () => "正在通过灵珠设备拍照...",
40
+ },
41
+ {
42
+ name: "navigate",
43
+ command: "take_navigation",
44
+ description: "使用灵珠设备的导航功能,导航到指定地址或 POI。当用户要求导航、带路、去某地时,必须调用此工具。(注意不要回复,直接调用工具)",
45
+ parameters: {
46
+ type: "object",
47
+ properties: {
48
+ destination: { type: "string", description: "目标地址或 POI 名称" },
49
+ navi_type: {
50
+ type: "string",
51
+ enum: ["0", "1", "2"],
52
+ description: "导航类型:0=驾车,1=步行,2=骑行",
53
+ },
54
+ },
55
+ required: ["destination"],
56
+ },
57
+ statusText: (params) => {
58
+ const destination = typeof params.destination === "string" ? params.destination : "目标地点";
59
+ return `正在导航到 ${destination}...`;
60
+ },
61
+ },
62
+ {
63
+ name: "calendar",
64
+ command: "control_calendar",
65
+ description: "在灵珠设备上创建日程提醒。当用户要求添加日程、设置提醒、安排事项时,必须调用此工具。",
66
+ parameters: {
67
+ type: "object",
68
+ properties: {
69
+ title: { type: "string", description: "日程标题" },
70
+ start_time: { type: "string", description: "开始时间,格式:YYYY-MM-DD HH:mm" },
71
+ end_time: { type: "string", description: "结束时间,格式:YYYY-MM-DD HH:mm" },
72
+ },
73
+ required: ["title", "start_time"],
74
+ },
75
+ statusText: (params) => {
76
+ const title = typeof params.title === "string" ? params.title : "日程";
77
+ return `已创建日程:${title}`;
78
+ },
79
+ },
80
+ {
81
+ name: "exit_agent",
82
+ command: "notify_agent_off",
83
+ description: "退出当前智能体会话,返回灵珠主界面。当用户要求退出、结束对话时,必须调用此工具。",
84
+ parameters: EMPTY_PARAMS,
85
+ statusText: () => "正在退出智能体...",
86
+ },
87
+ {
88
+ name: "send_notification",
89
+ command: "send_notification",
90
+ description: "向眼镜发送通知,可选同步 TTS 播报。实验性原生动作。",
91
+ parameters: {
92
+ type: "object",
93
+ properties: {
94
+ content: { type: "string", description: "通知内容" },
95
+ play_tts: { type: "boolean", description: "是否同步播报 TTS" },
96
+ icon_type: { type: "string", description: "图标类型,默认 1" },
97
+ },
98
+ required: ["content"],
99
+ },
100
+ experimental: true,
101
+ statusText: () => "已向眼镜发送通知",
102
+ },
103
+ {
104
+ name: "send_toast",
105
+ command: "send_toast",
106
+ description: "向眼镜发送轻提示 Toast。实验性原生动作。",
107
+ parameters: {
108
+ type: "object",
109
+ properties: {
110
+ content: { type: "string", description: "Toast 内容" },
111
+ play_tts: { type: "boolean", description: "是否同步播报 TTS" },
112
+ icon_type: { type: "string", description: "图标类型,默认 1" },
113
+ },
114
+ required: ["content"],
115
+ },
116
+ experimental: true,
117
+ statusText: () => "已向眼镜发送提示",
118
+ },
119
+ {
120
+ name: "speak_tts",
121
+ command: "speak_tts",
122
+ description: "在眼镜端直接播报一段文本。实验性原生动作。",
123
+ parameters: {
124
+ type: "object",
125
+ properties: {
126
+ content: { type: "string", description: "播报内容" },
127
+ },
128
+ required: ["content"],
129
+ },
130
+ experimental: true,
131
+ statusText: () => "正在播报文本",
132
+ },
133
+ {
134
+ name: "start_video_record",
135
+ command: "start_video_record",
136
+ description: "开始眼镜录像。实验性原生动作。",
137
+ parameters: {
138
+ type: "object",
139
+ properties: {
140
+ duration_sec: { type: "number", description: "录像时长,单位秒" },
141
+ width: { type: "number", description: "录像宽度" },
142
+ height: { type: "number", description: "录像高度" },
143
+ quality: { type: "number", description: "画质或质量" },
144
+ },
145
+ required: [],
146
+ },
147
+ experimental: true,
148
+ statusText: () => "正在开始录像",
149
+ },
150
+ {
151
+ name: "stop_video_record",
152
+ command: "stop_video_record",
153
+ description: "停止眼镜录像。实验性原生动作。",
154
+ parameters: EMPTY_PARAMS,
155
+ experimental: true,
156
+ statusText: () => "正在停止录像",
157
+ },
158
+ {
159
+ name: "open_custom_view",
160
+ command: "open_custom_view",
161
+ description: "打开眼镜上的实验性自定义页面。实验性原生动作。",
162
+ parameters: {
163
+ type: "object",
164
+ properties: {
165
+ view_name: { type: "string", description: "页面名称" },
166
+ view_payload: { type: "string", description: "页面 JSON 或配置字符串" },
167
+ },
168
+ required: ["view_name"],
169
+ },
170
+ experimental: true,
171
+ statusText: () => "正在打开自定义页面",
172
+ },
173
+ ];
174
+
175
+ function getLingzhuToolDefinitions(enableExperimentalNativeActions: boolean): LingzhuToolDefinition[] {
176
+ return TOOL_DEFINITIONS.filter((tool) => enableExperimentalNativeActions || tool.experimental !== true);
177
+ }
178
+
179
+ function encodeMarkerParams(params: unknown): string {
180
+ return Buffer.from(JSON.stringify(params ?? {}), "utf8").toString("base64url");
181
+ }
182
+
183
+ function formatToolMarker(command: LingzhuToolCall["command"], params: unknown): string {
184
+ return `<LINGZHU_TOOL_CALL:${command}:${encodeMarkerParams(params)}>`;
185
+ }
186
+
187
+ export function createLingzhuToolSchemas(enableExperimentalNativeActions = false) {
188
+ return getLingzhuToolDefinitions(enableExperimentalNativeActions).map((tool) => ({
189
+ type: "function" as const,
190
+ function: {
191
+ name: tool.name,
192
+ description: tool.description,
193
+ parameters: tool.parameters,
194
+ },
195
+ }));
196
+ }
197
+
198
+ export function createLingzhuTools(enableExperimentalNativeActions = false) {
199
+ return getLingzhuToolDefinitions(enableExperimentalNativeActions).map((tool) => ({
200
+ name: tool.name,
201
+ description: tool.description,
202
+ parameters: tool.parameters,
203
+ async execute(_id: string, params: Record<string, unknown>, ctx?: any): Promise<ToolExecuteResult> {
204
+ console.log(`[Lingzhu:Native] Tool execute called for ${tool.name} with params:`, params);
205
+ console.log(`[Lingzhu:Native] Context (ctx) provided:`, ctx);
206
+
207
+ const marker = formatToolMarker(tool.command, params);
208
+ const statusText = tool.statusText?.(params) ?? "";
209
+
210
+ try {
211
+ const parsedToolCall = parseToolCallFromAccumulated(tool.name, JSON.stringify(params), {
212
+ enableExperimentalNativeActions
213
+ });
214
+
215
+ console.log(`[Lingzhu:Native] Parsed Tool Call:`, parsedToolCall);
216
+
217
+ if (parsedToolCall) {
218
+ const sessionKey = ctx?.user || ctx?.session?.user || ctx?.sessionKey || ctx?.sessionId;
219
+ const agentId = ctx?.agentId || ctx?.agent_id;
220
+
221
+ const emitPayload = {
222
+ sessionKey,
223
+ agentId,
224
+ tool_call: parsedToolCall
225
+ };
226
+ console.log(`[Lingzhu:Native] Emitting native_invoke with payload:`, emitPayload);
227
+
228
+ lingzhuEventBus.emit("native_invoke", emitPayload);
229
+ } else {
230
+ console.log(`[Lingzhu:Native] Failed to parse tool call from command ${tool.name}`);
231
+ }
232
+ } catch (err) {
233
+ console.error(`[Lingzhu:Native] Error during execute parsing:`, err);
234
+ }
235
+
236
+ return {
237
+ content: [
238
+ {
239
+ type: "text",
240
+ text: statusText ? `${marker} ${statusText}` : marker,
241
+ },
242
+ ],
243
+ };
244
+ },
245
+ }));
246
+ }