nolo-cli 0.1.10 → 0.1.12

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 (232) hide show
  1. package/README.md +0 -32
  2. package/agentRuntimeCommands.ts +1 -1
  3. package/client/compactDialog.ts +2 -5
  4. package/commandRegistry.ts +2 -2
  5. package/machineCommands.ts +28 -3
  6. package/package.json +5 -25
  7. package/ai/agent/_executeModel.ts +0 -118
  8. package/ai/agent/agentSlice.ts +0 -525
  9. package/ai/agent/appWorkingMemory.ts +0 -126
  10. package/ai/agent/avatarUtils.ts +0 -24
  11. package/ai/agent/buildEditingContext.ts +0 -373
  12. package/ai/agent/buildSystemPrompt.ts +0 -532
  13. package/ai/agent/cleanAgentMessages.ts +0 -140
  14. package/ai/agent/cliChatClient.ts +0 -119
  15. package/ai/agent/contextCompiler.ts +0 -107
  16. package/ai/agent/contextLayerContract.ts +0 -44
  17. package/ai/agent/createAgentSchema.ts +0 -234
  18. package/ai/agent/executeToolCall.ts +0 -58
  19. package/ai/agent/fetchAgentContexts.ts +0 -42
  20. package/ai/agent/generatePrompt.ts +0 -3
  21. package/ai/agent/getFullChatContextKeys.ts +0 -168
  22. package/ai/agent/hooks/fetchPublicAgents.ts +0 -133
  23. package/ai/agent/hooks/useAgentConfig.ts +0 -61
  24. package/ai/agent/hooks/useAgentDialog.ts +0 -35
  25. package/ai/agent/hooks/useAgentFormValidation.ts +0 -202
  26. package/ai/agent/hooks/usePublicAgents.ts +0 -473
  27. package/ai/agent/persistMessageWithFixedId.ts +0 -37
  28. package/ai/agent/planSlice.ts +0 -259
  29. package/ai/agent/referenceUtils.ts +0 -229
  30. package/ai/agent/runAgentBackground.ts +0 -238
  31. package/ai/agent/runAgentClientLoop.ts +0 -138
  32. package/ai/agent/runtimeGuidance.ts +0 -97
  33. package/ai/agent/runtimeServerBase.ts +0 -37
  34. package/ai/agent/server/fetchPublicAgents.ts +0 -128
  35. package/ai/agent/startParallelAgentStreams.ts +0 -424
  36. package/ai/agent/startupProtocol.ts +0 -53
  37. package/ai/agent/streamAgentChatTurn.ts +0 -1278
  38. package/ai/agent/streamAgentChatTurnUtils.ts +0 -738
  39. package/ai/agent/types.ts +0 -71
  40. package/ai/agent/utils/imageOutput.ts +0 -33
  41. package/ai/agent/utils/sortUtils.ts +0 -250
  42. package/ai/agent/web/referencePickerUtils.ts +0 -146
  43. package/ai/ai.locale.ts +0 -1079
  44. package/ai/chat/accumulateToolCallChunks.ts +0 -95
  45. package/ai/chat/fetchUtils.native.ts +0 -276
  46. package/ai/chat/fetchUtils.ts +0 -153
  47. package/ai/chat/parseApiError.ts +0 -64
  48. package/ai/chat/parseMultilineSSE.ts +0 -95
  49. package/ai/chat/sendOpenAICompletionsRequest.native.ts +0 -682
  50. package/ai/chat/sendOpenAICompletionsRequest.ts +0 -703
  51. package/ai/chat/sendOpenAIResponseRequest.ts +0 -491
  52. package/ai/chat/shouldUseServerProxy.ts +0 -18
  53. package/ai/chat/sseClient.native.ts +0 -91
  54. package/ai/chat/sseClient.ts +0 -67
  55. package/ai/chat/streamReader.native.ts +0 -31
  56. package/ai/chat/streamReader.ts +0 -62
  57. package/ai/chat/updateTotalUsage.ts +0 -72
  58. package/ai/context/buildReferenceContext.ts +0 -437
  59. package/ai/context/calculateContextUsage.ts +0 -133
  60. package/ai/context/retention.ts +0 -165
  61. package/ai/context/tokenUtils.ts +0 -78
  62. package/ai/index.ts +0 -1
  63. package/ai/llm/calculateGeminiImageTokens.ts +0 -57
  64. package/ai/llm/deepinfra.ts +0 -28
  65. package/ai/llm/fireworks.ts +0 -50
  66. package/ai/llm/generateRequestBody.ts +0 -165
  67. package/ai/llm/getModelContextWindow.ts +0 -84
  68. package/ai/llm/getNoloKey.ts +0 -31
  69. package/ai/llm/getPricing.ts +0 -199
  70. package/ai/llm/hooks/useModelPricing.ts +0 -75
  71. package/ai/llm/imagePricing.ts +0 -40
  72. package/ai/llm/isResponseAPIModel.ts +0 -13
  73. package/ai/llm/mimo.ts +0 -71
  74. package/ai/llm/mistral.ts +0 -22
  75. package/ai/llm/modelAvatar.ts +0 -427
  76. package/ai/llm/models.ts +0 -45
  77. package/ai/llm/openrouterModels.ts +0 -269
  78. package/ai/llm/providers.ts +0 -306
  79. package/ai/llm/reasoningModels.ts +0 -28
  80. package/ai/llm/types.ts +0 -59
  81. package/ai/llm/usageRequestOptions.ts +0 -59
  82. package/ai/memory/capture.ts +0 -148
  83. package/ai/memory/consolidate.ts +0 -104
  84. package/ai/memory/delete.ts +0 -147
  85. package/ai/memory/overlay.ts +0 -84
  86. package/ai/memory/query.ts +0 -38
  87. package/ai/memory/queryShared.ts +0 -160
  88. package/ai/memory/rank.ts +0 -105
  89. package/ai/memory/recentRelationshipRecap.ts +0 -249
  90. package/ai/memory/remember.ts +0 -167
  91. package/ai/memory/runtime.ts +0 -76
  92. package/ai/memory/store.ts +0 -20
  93. package/ai/memory/storeShared.ts +0 -76
  94. package/ai/memory/types.ts +0 -46
  95. package/ai/memory/understanding.ts +0 -349
  96. package/ai/memory/understandingGreeting.ts +0 -264
  97. package/ai/messages/type.ts +0 -20
  98. package/ai/policy/personalizationDialog.ts +0 -333
  99. package/ai/policy/runtimePolicy.ts +0 -440
  100. package/ai/policy/selfUpdateFields.ts +0 -48
  101. package/ai/policy/types.ts +0 -64
  102. package/ai/skills/referenceRuntime.ts +0 -274
  103. package/ai/skills/skillDiagnostics.ts +0 -251
  104. package/ai/skills/skillDocBuilder.ts +0 -139
  105. package/ai/skills/skillDocProtocol.ts +0 -434
  106. package/ai/skills/skillReferenceSummary.ts +0 -63
  107. package/ai/skills/skillSummaryMarker.ts +0 -26
  108. package/ai/token/calculatePrice.ts +0 -544
  109. package/ai/token/db.ts +0 -98
  110. package/ai/token/externalToolCost.ts +0 -330
  111. package/ai/token/hooks/useRecords.ts +0 -65
  112. package/ai/token/missingUsageEstimate.ts +0 -42
  113. package/ai/token/modelUsageQuery.ts +0 -252
  114. package/ai/token/normalizeUsage.ts +0 -84
  115. package/ai/token/openaiImageGenerationUsage.ts +0 -56
  116. package/ai/token/prepareTokenUsageData.ts +0 -88
  117. package/ai/token/query.ts +0 -88
  118. package/ai/token/queryUserTokens.ts +0 -59
  119. package/ai/token/resolveBillingTarget.ts +0 -52
  120. package/ai/token/saveTokenRecord.ts +0 -53
  121. package/ai/token/serverDialogProjection.ts +0 -78
  122. package/ai/token/serverTokenWriter.ts +0 -143
  123. package/ai/token/stats.ts +0 -21
  124. package/ai/token/tokenThunks.ts +0 -24
  125. package/ai/token/types.ts +0 -93
  126. package/ai/tools/agent/agentTools.ts +0 -176
  127. package/ai/tools/agent/agentUpdateShared.ts +0 -311
  128. package/ai/tools/agent/callAgentTool.ts +0 -139
  129. package/ai/tools/agent/createAgentTool.ts +0 -512
  130. package/ai/tools/agent/createDialogTool.ts +0 -69
  131. package/ai/tools/agent/createSkillAgentTool.ts +0 -62
  132. package/ai/tools/agent/parallelBudget.ts +0 -221
  133. package/ai/tools/agent/presets/appBuilderPreset.ts +0 -145
  134. package/ai/tools/agent/runLlmTool.ts +0 -96
  135. package/ai/tools/agent/runStreamingAgentTool.ts +0 -73
  136. package/ai/tools/agent/skillAgentArgs.ts +0 -106
  137. package/ai/tools/agent/skillAgentPreset.ts +0 -89
  138. package/ai/tools/agent/streamParallelAgentsTool.ts +0 -122
  139. package/ai/tools/agent/updateAgentTool.ts +0 -96
  140. package/ai/tools/agent/updateSelfTool.ts +0 -113
  141. package/ai/tools/amazonProductScraperTool.ts +0 -86
  142. package/ai/tools/apifyActorClient.ts +0 -45
  143. package/ai/tools/appEditGuard.ts +0 -372
  144. package/ai/tools/appReadSnapshot.ts +0 -153
  145. package/ai/tools/appTools.ts +0 -1549
  146. package/ai/tools/applyEditTool.ts +0 -256
  147. package/ai/tools/applyLineEditsTool.ts +0 -312
  148. package/ai/tools/browserTools/click.ts +0 -33
  149. package/ai/tools/browserTools/closeSession.ts +0 -29
  150. package/ai/tools/browserTools/common.ts +0 -27
  151. package/ai/tools/browserTools/openSession.ts +0 -48
  152. package/ai/tools/browserTools/readContent.ts +0 -38
  153. package/ai/tools/browserTools/selectOption.ts +0 -46
  154. package/ai/tools/browserTools/typeText.ts +0 -42
  155. package/ai/tools/category/createCategoryTool.ts +0 -66
  156. package/ai/tools/category/queryContentsByCategoryTool.ts +0 -69
  157. package/ai/tools/category/updateContentCategoryTool.ts +0 -75
  158. package/ai/tools/cfBrowserTools.ts +0 -319
  159. package/ai/tools/cfSpeechToTextTool.ts +0 -49
  160. package/ai/tools/checkEnvTool.ts +0 -65
  161. package/ai/tools/cloudflareCrawlTool.ts +0 -289
  162. package/ai/tools/codeSearchTool.ts +0 -111
  163. package/ai/tools/codeTools.ts +0 -101
  164. package/ai/tools/createDocTool.ts +0 -132
  165. package/ai/tools/createPlanTool.ts +0 -999
  166. package/ai/tools/createSkillDocTool.ts +0 -155
  167. package/ai/tools/createWorkflowTool.ts +0 -154
  168. package/ai/tools/deepseekOcrTool.ts +0 -34
  169. package/ai/tools/delayTool.ts +0 -31
  170. package/ai/tools/deleteSpacesTool.ts +0 -325
  171. package/ai/tools/deleteSpacesToolModel.ts +0 -159
  172. package/ai/tools/devReloadUtils.ts +0 -29
  173. package/ai/tools/dialogMessageSearch.ts +0 -137
  174. package/ai/tools/doctorSkillTool.ts +0 -72
  175. package/ai/tools/ecommerceScraperTool.ts +0 -86
  176. package/ai/tools/emailTools.ts +0 -549
  177. package/ai/tools/evalSkillTool.ts +0 -92
  178. package/ai/tools/exaSearchTool.ts +0 -64
  179. package/ai/tools/execBashTool.ts +0 -379
  180. package/ai/tools/executeSqlTool.ts +0 -192
  181. package/ai/tools/fetchWebpageSupport.ts +0 -309
  182. package/ai/tools/fetchWebpageTool.ts +0 -84
  183. package/ai/tools/geminiImagePreviewTool.ts +0 -361
  184. package/ai/tools/generateDocxTool.ts +0 -215
  185. package/ai/tools/googleSearchScraperTool.ts +0 -106
  186. package/ai/tools/importDataTool.ts +0 -133
  187. package/ai/tools/importSkillTool.ts +0 -162
  188. package/ai/tools/index.ts +0 -1858
  189. package/ai/tools/listFilesTool.ts +0 -82
  190. package/ai/tools/listUserSpacesTool.ts +0 -113
  191. package/ai/tools/modelUsageTools.ts +0 -142
  192. package/ai/tools/olmOcrTool.ts +0 -34
  193. package/ai/tools/openaiImageTool.ts +0 -218
  194. package/ai/tools/paddleOcrTool.ts +0 -34
  195. package/ai/tools/prepareTools.ts +0 -23
  196. package/ai/tools/readDocTool.ts +0 -84
  197. package/ai/tools/readFileTool.ts +0 -211
  198. package/ai/tools/readTool.ts +0 -163
  199. package/ai/tools/readXPostTool.ts +0 -233
  200. package/ai/tools/rememberMemoryTool.ts +0 -84
  201. package/ai/tools/remotionVideoTool.ts +0 -151
  202. package/ai/tools/searchDialogMessagesTool.ts +0 -222
  203. package/ai/tools/searchRepoTool.ts +0 -115
  204. package/ai/tools/searchWorkspaceTool.ts +0 -259
  205. package/ai/tools/skillFollowup.ts +0 -86
  206. package/ai/tools/surfWeatherTool.ts +0 -169
  207. package/ai/tools/table/addTableRowTool.ts +0 -217
  208. package/ai/tools/table/createTableTool.ts +0 -315
  209. package/ai/tools/table/rowTools.ts +0 -366
  210. package/ai/tools/table/schemaTools.ts +0 -244
  211. package/ai/tools/table/shareTableTool.ts +0 -148
  212. package/ai/tools/table/toolShared.ts +0 -129
  213. package/ai/tools/toolApiClient.ts +0 -198
  214. package/ai/tools/toolNameAliases.ts +0 -57
  215. package/ai/tools/toolResultError.ts +0 -42
  216. package/ai/tools/toolRunSlice.ts +0 -303
  217. package/ai/tools/toolSchemaCompatibility.ts +0 -53
  218. package/ai/tools/toolVisibility.ts +0 -4
  219. package/ai/tools/types.ts +0 -20
  220. package/ai/tools/uiAskChoiceTool.ts +0 -104
  221. package/ai/tools/updateContentTitleTool.ts +0 -84
  222. package/ai/tools/updateDocTool.ts +0 -105
  223. package/ai/tools/updateUserPreferenceProfileTool.ts +0 -145
  224. package/ai/tools/whisperTool.ts +0 -77
  225. package/ai/tools/writeFileTool.ts +0 -210
  226. package/ai/tools/youtubeScraperTool.ts +0 -116
  227. package/ai/tools/ziweiChartTool.ts +0 -678
  228. package/ai/types.ts +0 -55
  229. package/ai/workflow/workflowExecutor.ts +0 -323
  230. package/ai/workflow/workflowSlice.ts +0 -73
  231. package/ai/workflow/workflowTypes.ts +0 -106
  232. package/connector-experimental/index.ts +0 -5
@@ -1,84 +0,0 @@
1
- import { selectCurrentSpaceId } from "create/space/spaceSlice";
2
- import { callToolApi } from "./toolApiClient";
3
- import type { RememberMemoryScope } from "ai/memory/remember";
4
- import type { MemoryKind } from "ai/memory/types";
5
-
6
- export interface RememberMemoryToolArgs {
7
- content: string;
8
- scope?: RememberMemoryScope;
9
- kind?: MemoryKind;
10
- }
11
-
12
- export const rememberMemoryFunctionSchema = {
13
- name: "rememberMemory",
14
- description: [
15
- "当你判断某条用户偏好、纠正、决策习惯或当前 Space 共识值得被长期记住时,调用本工具写入一条 memory。",
16
- "默认先记原始事件,不要把一次性临时要求、当前任务进度或明显短期信息写进去。",
17
- "只有重复出现的可执行流程/排障步骤才传 kind=procedural;一般偏好和事实保持默认 episodic。",
18
- "只有当当前 dialog 明确绑定了一个 Space,且这条内容确实属于共享协作共识时,才应该传 scope=space。",
19
- "优先写成一句简洁、未来仍可理解的话;如无必要,不要频繁调用。",
20
- ].join("\n"),
21
- parameters: {
22
- type: "object",
23
- properties: {
24
- content: {
25
- type: "string",
26
- description:
27
- "要记住的内容。请写成一句未来仍然可理解的简洁描述,例如“这个用户在复杂问题里更喜欢先看结论”。",
28
- },
29
- scope: {
30
- type: "string",
31
- enum: ["auto", "user", "space"],
32
- description:
33
- "记忆范围。默认 auto:优先记到当前用户;若没有用户上下文再退到当前 space。只有当前 dialog 明确绑定了 space,且你明确想写共享协作记忆时才传 space;否则保持 auto。",
34
- },
35
- kind: {
36
- type: "string",
37
- enum: ["episodic", "semantic", "procedural"],
38
- description:
39
- "记忆类型。默认 episodic。只有重复出现的可执行流程、排障步骤或稳定 runbook 才使用 procedural。",
40
- },
41
- },
42
- required: ["content"],
43
- } as const,
44
- };
45
-
46
- export async function rememberMemoryFunc(
47
- args: RememberMemoryToolArgs,
48
- thunkApi: any
49
- ): Promise<{ rawData: unknown; displayData: string }> {
50
- const state = thunkApi.getState();
51
- const spaceId = selectCurrentSpaceId(state) || undefined;
52
- const content = String(args.content ?? "").trim();
53
- const scope = args.scope ?? "auto";
54
- const kind = args.kind ?? "episodic";
55
-
56
- if (!content) {
57
- throw new Error("rememberMemory 需要非空 content。");
58
- }
59
-
60
- const result = await callToolApi<{
61
- success: boolean;
62
- content: string;
63
- requestedScope: RememberMemoryScope;
64
- resolvedScopes: Array<{ ownerType: string; ownerId: string }>;
65
- }>(
66
- thunkApi,
67
- "/api/memory/remember",
68
- {
69
- content,
70
- scope,
71
- kind,
72
- spaceId,
73
- },
74
- { withAuth: true }
75
- );
76
-
77
- const scopeLabel =
78
- result.resolvedScopes?.[0]?.ownerType === "space" ? "当前空间" : "当前用户";
79
-
80
- return {
81
- rawData: result,
82
- displayData: `已记住这条${scopeLabel}记忆。`,
83
- };
84
- }
@@ -1,151 +0,0 @@
1
- import { ContentType } from "app/types";
2
- import { addContentAction } from "create/space/content/addContentAction";
3
- import { selectCurrentSpaceId } from "create/space/spaceSlice";
4
- import { buildDatabaseFileContentUrl } from "database/fileUrl";
5
- import { fileKey } from "database/keys";
6
- import { selectCurrentServer } from "app/settings/settingSlice";
7
- import { selectUserId } from "auth/authSlice";
8
- import { callToolApi } from "./toolApiClient";
9
-
10
- type RemotionRenderVideoArgs = {
11
- template?: "mobile-product" | "landscape-product" | "nolo-mobile-product" | "nolo-landscape-product";
12
- brand?: string;
13
- hook?: string;
14
- headline?: string;
15
- subline?: string;
16
- prompt?: string;
17
- cta?: string;
18
- outputName?: string;
19
- };
20
-
21
- export const remotionRenderVideoFunctionSchema = {
22
- name: "remotionRenderVideo",
23
- description: [
24
- "使用平台内 Remotion 模板渲染产品视频,并保存为可复用 MP4 文件。",
25
- "",
26
- "适用场景:",
27
- "- 用户要生成手机传播视频、产品介绍视频、欢迎页短片、Agent/AI 工作流演示视频。",
28
- "- 需要把文案、标题、输入框示例等参数化后产出 MP4。",
29
- "",
30
- "当前模板:",
31
- "- mobile-product: 9:16 竖版,适合手机传播。",
32
- "- landscape-product: 16:9 横版,适合官网/演示页。",
33
- "- 兼容旧别名 nolo-mobile-product / nolo-landscape-product。",
34
- ].join("\n"),
35
- parameters: {
36
- type: "object",
37
- properties: {
38
- template: {
39
- type: "string",
40
- enum: ["mobile-product", "landscape-product", "nolo-mobile-product", "nolo-landscape-product"],
41
- description: "视频模板。默认 mobile-product。",
42
- },
43
- brand: {
44
- type: "string",
45
- description: "品牌名,例如 Nolo.Chat、你的产品名、店铺名或活动名。",
46
- },
47
- hook: {
48
- type: "string",
49
- description: "竖版视频首屏钩子标题,例如“把一句想法,推进成结果”。",
50
- },
51
- headline: {
52
- type: "string",
53
- description: "横版视频主标题;竖版缺少 hook 时也会作为 hook 使用。",
54
- },
55
- subline: {
56
- type: "string",
57
- description: "横版视频副标题。",
58
- },
59
- prompt: {
60
- type: "string",
61
- description: "手机输入框里逐字打出的示例需求。",
62
- },
63
- cta: {
64
- type: "string",
65
- description: "结尾行动号召,例如“开始体验”。",
66
- },
67
- outputName: {
68
- type: "string",
69
- description: "输出文件名,建议以 .mp4 结尾。",
70
- },
71
- },
72
- },
73
- };
74
-
75
- export const remotionRenderVideoFunc = async (
76
- args: RemotionRenderVideoArgs,
77
- thunkApi: any
78
- ): Promise<{ rawData: any; displayData: string; llmContext?: string }> => {
79
- const result: any = await callToolApi(
80
- thunkApi,
81
- "/api/remotion/render",
82
- {
83
- template: args.template || "mobile-product",
84
- brand: args.brand,
85
- hook: args.hook,
86
- headline: args.headline,
87
- subline: args.subline,
88
- prompt: args.prompt,
89
- cta: args.cta,
90
- outputName: args.outputName,
91
- },
92
- { withAuth: true }
93
- );
94
-
95
- const state = thunkApi.getState();
96
- const userId = selectUserId(state);
97
- const spaceId = selectCurrentSpaceId(state);
98
- const currentServer = selectCurrentServer(state);
99
- const fileId = result?.fileId;
100
- const metadata = result?.metadata || {};
101
- const fileDbKey = userId && fileId ? fileKey.single(userId, fileId) : "";
102
- const url = buildDatabaseFileContentUrl(currentServer, fileDbKey || fileId);
103
-
104
- if (spaceId && fileDbKey) {
105
- try {
106
- await addContentAction(
107
- {
108
- spaceId,
109
- contentKey: fileDbKey,
110
- title: metadata.originalName || "Remotion video.mp4",
111
- type: ContentType.FILE,
112
- fileCategory: "video",
113
- } as any,
114
- { dispatch: thunkApi.dispatch, getState: thunkApi.getState }
115
- );
116
- } catch (error) {
117
- console.warn("[remotionRenderVideoFunc] Failed to add video to space:", error);
118
- }
119
- }
120
-
121
- const displayLines = [
122
- result?.text || "已使用 Remotion 生成视频。",
123
- fileId ? `- fileId: ${fileId}` : "",
124
- fileDbKey ? `- fileDbKey: ${fileDbKey}` : "",
125
- url ? `- url: ${url}` : "",
126
- metadata?.size ? `- size: ${metadata.size} bytes` : "",
127
- result?.template ? `- template: ${result.template}` : "",
128
- ].filter(Boolean);
129
-
130
- const llmContext = [
131
- "The Remotion video tool produced a reusable video file.",
132
- "Reuse these exact references when mentioning or embedding the video:",
133
- fileId ? `- fileId: ${fileId}` : "",
134
- fileDbKey ? `- fileDbKey: ${fileDbKey}` : "",
135
- url ? `- url: ${url}` : "",
136
- metadata?.originalName ? `- name: ${metadata.originalName}` : "",
137
- result?.template ? `- template: ${result.template}` : "",
138
- ]
139
- .filter(Boolean)
140
- .join("\n");
141
-
142
- return {
143
- rawData: {
144
- ...result,
145
- fileDbKey,
146
- url,
147
- },
148
- displayData: displayLines.join("\n"),
149
- llmContext,
150
- };
151
- };
@@ -1,222 +0,0 @@
1
- import { extractCustomId } from "core/prefix";
2
- import { selectRuntimeSnapshot } from "app/stateViews/runtime";
3
- import {
4
- buildDialogMessageSearchResults,
5
- clampDialogSearchNumber,
6
- formatDialogMessageSearchDisplay,
7
- normalizeDialogSearchText,
8
- type DialogMessageSearchRecord,
9
- } from "./dialogMessageSearch";
10
-
11
- type SearchDialogMessagesArgs = {
12
- dialogKey: string;
13
- query: string;
14
- limit?: number;
15
- scanLimit?: number;
16
- contextMessages?: number;
17
- role?: "user" | "assistant" | "tool" | "system";
18
- includeTools?: boolean;
19
- };
20
-
21
- const MAX_LIMIT = 10;
22
- const MAX_CONTEXT_MESSAGES = 3;
23
- const MAX_CONTENT_CHARS = 1800;
24
- const CONTEXT_CONTENT_CHARS = 600;
25
- const SERVER_SCAN_LIMIT = 500;
26
-
27
- const getMessageSortValue = (message: DialogMessageSearchRecord) => {
28
- const createdAt = message.createdAt;
29
- if (typeof createdAt === "number") return createdAt;
30
- if (typeof createdAt === "string") {
31
- const parsed = Date.parse(createdAt);
32
- if (Number.isFinite(parsed)) return parsed;
33
- }
34
- const id = normalizeDialogSearchText(message.id);
35
- return id ? id : normalizeDialogSearchText(message.dbKey);
36
- };
37
-
38
- async function collectDialogMessages(db: any, dialogId: string): Promise<DialogMessageSearchRecord[]> {
39
- if (!db?.iterator) return [];
40
- const prefix = `dialog-${dialogId}-msg-`;
41
- let iterator = db.iterator({
42
- gte: prefix,
43
- lte: `${prefix}\uffff`,
44
- });
45
- if (iterator && typeof iterator.then === "function") {
46
- iterator = await iterator;
47
- }
48
-
49
- const messages: DialogMessageSearchRecord[] = [];
50
- for await (const [key, value] of iterator) {
51
- if (!value || typeof value !== "object") continue;
52
- messages.push({
53
- ...(value as DialogMessageSearchRecord),
54
- dbKey: (value as DialogMessageSearchRecord).dbKey || String(key),
55
- });
56
- }
57
-
58
- return messages.sort((a, b) => {
59
- const left = getMessageSortValue(a);
60
- const right = getMessageSortValue(b);
61
- if (typeof left === "number" && typeof right === "number") return left - right;
62
- return String(left).localeCompare(String(right));
63
- });
64
- }
65
-
66
- async function fetchDialogMessagesFromServer(args: {
67
- serverBase: string;
68
- token?: string;
69
- dialogId: string;
70
- limit: number;
71
- }): Promise<DialogMessageSearchRecord[]> {
72
- const serverBase = args.serverBase.replace(/\/+$/, "");
73
- if (!serverBase || !args.token) return [];
74
-
75
- const response = await fetch(`${serverBase}/rpc/getConvMsgs`, {
76
- method: "POST",
77
- headers: {
78
- Authorization: `Bearer ${args.token}`,
79
- "Content-Type": "application/json",
80
- },
81
- body: JSON.stringify({ dialogId: args.dialogId, limit: args.limit }),
82
- });
83
- if (!response.ok) return [];
84
-
85
- const newestFirst = await response.json();
86
- if (!Array.isArray(newestFirst)) return [];
87
- return [...newestFirst].reverse().map((message) => ({
88
- ...(message as DialogMessageSearchRecord),
89
- dbKey: (message as DialogMessageSearchRecord).dbKey,
90
- }));
91
- }
92
-
93
- async function collectBestAvailableDialogMessages(
94
- db: any,
95
- dialogId: string,
96
- thunkApi: any,
97
- scanLimit: number,
98
- ): Promise<DialogMessageSearchRecord[]> {
99
- const localMessages = await collectDialogMessages(db, dialogId);
100
- const state = thunkApi?.getState?.();
101
- const runtime = state ? selectRuntimeSnapshot(state) : null;
102
- const serverBases = Array.from(new Set([
103
- runtime?.localRuntimeOrigin,
104
- runtime?.currentServer,
105
- ...(Array.isArray(runtime?.syncServers) ? runtime.syncServers : []),
106
- ].filter((base): base is string => typeof base === "string" && base.trim().length > 0)));
107
-
108
- let bestMessages = localMessages;
109
- for (const serverBase of serverBases) {
110
- const serverMessages = await fetchDialogMessagesFromServer({
111
- serverBase,
112
- token: runtime?.currentToken,
113
- dialogId,
114
- limit: scanLimit,
115
- }).catch(() => []);
116
- if (serverMessages.length > bestMessages.length) {
117
- bestMessages = serverMessages;
118
- }
119
- }
120
-
121
- return bestMessages;
122
- }
123
-
124
- export const searchDialogMessagesFunctionSchema = {
125
- name: "searchDialogMessages",
126
- description: [
127
- "Search original messages inside a specific dialog by exact or fuzzy text.",
128
- "Use this when a user asks for an exact old message, original wording, who said what, why a decision was made, early-history detail, failed attempts, files or tool evidence, or comparison with prior work from an attached conversation.",
129
- "Prefer this over answering from a lossy dialog summary when the user needs evidence, provenance, or a specific prior detail.",
130
- "Returns matching message ids, roles, clipped original content, and nearby context without loading the full dialog into the model context.",
131
- ].join(" "),
132
- parameters: {
133
- type: "object",
134
- properties: {
135
- dialogKey: {
136
- type: "string",
137
- description: "Dialog dbKey, for example dialog-userId-01ABC...",
138
- },
139
- query: {
140
- type: "string",
141
- description: "Text to search for in original message content.",
142
- },
143
- limit: {
144
- type: "number",
145
- description: `Maximum matches to return. Capped at ${MAX_LIMIT}.`,
146
- },
147
- scanLimit: {
148
- type: "number",
149
- description: `Maximum messages to scan when fetching from a server. Capped at ${SERVER_SCAN_LIMIT}.`,
150
- },
151
- contextMessages: {
152
- type: "number",
153
- description: `Number of neighboring messages before/after each match. Capped at ${MAX_CONTEXT_MESSAGES}.`,
154
- },
155
- role: {
156
- type: "string",
157
- enum: ["user", "assistant", "tool", "system"],
158
- description: "Optional role filter.",
159
- },
160
- includeTools: {
161
- type: "boolean",
162
- description: "Whether tool messages may match. Defaults to true.",
163
- },
164
- },
165
- required: ["dialogKey", "query"],
166
- },
167
- };
168
-
169
- export async function searchDialogMessagesFunc(
170
- args: SearchDialogMessagesArgs,
171
- _thunkApi: any,
172
- context?: { db?: any }
173
- ) {
174
- const dialogKey = normalizeDialogSearchText(args?.dialogKey);
175
- const query = normalizeDialogSearchText(args?.query);
176
- if (!dialogKey.startsWith("dialog-")) {
177
- throw new Error("searchDialogMessages requires a dialog-* dbKey.");
178
- }
179
- if (!query) {
180
- throw new Error("searchDialogMessages requires a non-empty query.");
181
- }
182
-
183
- const db = context?.db ?? _thunkApi?.extra?.db;
184
- if (!db) {
185
- throw new Error("searchDialogMessages cannot access the local message database.");
186
- }
187
-
188
- const dialogId = extractCustomId(dialogKey) || dialogKey.split("-").at(-1) || "";
189
- const scanLimit = clampDialogSearchNumber(
190
- args.scanLimit,
191
- SERVER_SCAN_LIMIT,
192
- 1,
193
- SERVER_SCAN_LIMIT,
194
- );
195
- const messages = await collectBestAvailableDialogMessages(db, dialogId, _thunkApi, scanLimit);
196
- const limit = clampDialogSearchNumber(args.limit, 5, 1, MAX_LIMIT);
197
- const contextMessages = clampDialogSearchNumber(args.contextMessages, 1, 0, MAX_CONTEXT_MESSAGES);
198
-
199
- const results = buildDialogMessageSearchResults({
200
- messages,
201
- query,
202
- limit,
203
- contextMessages,
204
- role: args.role,
205
- includeTools: args.includeTools,
206
- contentClipChars: MAX_CONTENT_CHARS,
207
- contextClipChars: CONTEXT_CONTENT_CHARS,
208
- });
209
-
210
- const displayData = formatDialogMessageSearchDisplay({ dialogKey, query, results });
211
-
212
- return {
213
- rawData: {
214
- success: true,
215
- dialogKey,
216
- query,
217
- scannedMessages: messages.length,
218
- matches: results,
219
- },
220
- displayData,
221
- };
222
- }
@@ -1,115 +0,0 @@
1
- // 文件路径: packages/ai/tools/searchRepoTool.ts
2
-
3
- import { getToolBaseUrl } from "./toolApiClient";
4
-
5
- // ---- Types ----
6
-
7
- export type SearchRepoArgs = {
8
- query: string;
9
- pathScope?: string;
10
- maxResults?: number;
11
- contextLines?: number;
12
- };
13
-
14
- // ---- 工具 Schema ----
15
-
16
- export const searchRepoFunctionSchema = {
17
- name: "search_repo",
18
- description: [
19
- "在项目的源代码中进行全量文本搜索。",
20
- "当你不知道某个特定的字符串、类名、变量或逻辑在哪个文件中时,请使用此工具。",
21
- "它会返回匹配的文件路径、行号以及代码预览。",
22
- "",
23
- "参数建议:",
24
- "- query: 要搜索的文本(不区分大小写)。",
25
- "- pathScope: 可选,缩小搜索范围(如 'packages/server')。",
26
- "- maxResults: 默认 20。",
27
- ].join("\n"),
28
- parameters: {
29
- type: "object",
30
- properties: {
31
- query: {
32
- type: "string",
33
- description: "要搜索的文本字符串。",
34
- },
35
- pathScope: {
36
- type: "string",
37
- description: "可选:限制搜索在特定目录下,例如 'packages/ai'。",
38
- },
39
- maxResults: {
40
- type: "number",
41
- description: "返回的最大匹配项数量 (默认 20)。",
42
- },
43
- contextLines: {
44
- type: "number",
45
- description: "可选:匹配行前后显示的上下文行数。",
46
- },
47
- },
48
- required: ["query"],
49
- },
50
- };
51
-
52
- function buildSearchRepoDisplayData(
53
- query: string,
54
- hits: Array<{ path?: string; line?: number; preview?: string }>,
55
- totalHits: number | string | undefined,
56
- ): string {
57
- if (!Array.isArray(hits) || hits.length === 0) {
58
- return `🔍 搜索 "${query}": 未找到匹配项`;
59
- }
60
-
61
- const lines = hits.slice(0, 8).map((hit, index) => {
62
- const path = hit.path || "unknown";
63
- const line = typeof hit.line === "number" ? `:${hit.line}` : "";
64
- const preview = typeof hit.preview === "string" && hit.preview.trim()
65
- ? ` — ${hit.preview.trim()}`
66
- : "";
67
- return `${index + 1}. ${path}${line}${preview}`;
68
- });
69
-
70
- const omitted = hits.length > 8 ? `\n… 其余 ${hits.length - 8} 条已省略` : "";
71
- return `🔍 搜索 "${query}": 找到 ${totalHits ?? hits.length} 个匹配项\n${lines.join("\n")}${omitted}`;
72
- }
73
-
74
- // ---- 执行函数 ----
75
-
76
- export async function searchRepoFunc(
77
- args: SearchRepoArgs,
78
- thunkApi: any,
79
- context?: { signal?: AbortSignal }
80
- ): Promise<{ rawData: any; displayData?: string }> {
81
- const { query, pathScope, maxResults, contextLines } = args;
82
-
83
- try {
84
- const baseUrl = getToolBaseUrl(thunkApi);
85
- const apiUrl = `${baseUrl}/api/search-repo`;
86
-
87
- const response = await fetch(apiUrl, {
88
- method: "POST",
89
- headers: { "Content-Type": "application/json" },
90
- signal: context?.signal,
91
- body: JSON.stringify({ query, pathScope, maxResults, contextLines }),
92
- });
93
-
94
- const data = (await response.json()) as { ok?: boolean; error?: string; hits?: any[]; totalHits?: number | string };
95
-
96
- if (!response.ok || data?.error) {
97
- throw new Error(data?.error || `搜索请求失败: ${response.status}`);
98
- }
99
-
100
- const hits = data.hits || [];
101
- const displayData = buildSearchRepoDisplayData(query, hits, data.totalHits);
102
-
103
- return {
104
- rawData: {
105
- ok: true,
106
- query,
107
- hits,
108
- totalHits: data.totalHits,
109
- },
110
- displayData,
111
- };
112
- } catch (error: any) {
113
- throw new Error(`全局搜索 (${query}) 失败:${error?.message || String(error)}`);
114
- }
115
- }