nolo-cli 0.1.10 → 0.1.11
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.
- package/README.md +0 -32
- package/agentRuntimeCommands.ts +3 -3
- package/commandRegistry.ts +2 -2
- package/machineCommands.ts +31 -6
- package/package.json +6 -22
- package/ai/agent/_executeModel.ts +0 -118
- package/ai/agent/agentSlice.ts +0 -525
- package/ai/agent/appWorkingMemory.ts +0 -126
- package/ai/agent/avatarUtils.ts +0 -24
- package/ai/agent/buildEditingContext.ts +0 -373
- package/ai/agent/buildSystemPrompt.ts +0 -532
- package/ai/agent/cleanAgentMessages.ts +0 -140
- package/ai/agent/cliChatClient.ts +0 -119
- package/ai/agent/cliExecutor.ts +0 -733
- package/ai/agent/cliPrompt.ts +0 -10
- package/ai/agent/contextCompiler.ts +0 -107
- package/ai/agent/contextLayerContract.ts +0 -44
- package/ai/agent/createAgentSchema.ts +0 -234
- package/ai/agent/executeToolCall.ts +0 -58
- package/ai/agent/fetchAgentContexts.ts +0 -42
- package/ai/agent/generatePrompt.ts +0 -3
- package/ai/agent/getFullChatContextKeys.ts +0 -168
- package/ai/agent/hooks/fetchPublicAgents.ts +0 -133
- package/ai/agent/hooks/useAgentConfig.ts +0 -61
- package/ai/agent/hooks/useAgentDialog.ts +0 -35
- package/ai/agent/hooks/useAgentFormValidation.ts +0 -202
- package/ai/agent/hooks/usePublicAgents.ts +0 -473
- package/ai/agent/machineRunPermissions.ts +0 -95
- package/ai/agent/persistMessageWithFixedId.ts +0 -37
- package/ai/agent/planSlice.ts +0 -259
- package/ai/agent/referenceUtils.ts +0 -229
- package/ai/agent/runAgentBackground.ts +0 -238
- package/ai/agent/runAgentClientLoop.ts +0 -138
- package/ai/agent/runtimeGuidance.ts +0 -97
- package/ai/agent/runtimeServerBase.ts +0 -37
- package/ai/agent/server/fetchPublicAgents.ts +0 -128
- package/ai/agent/startParallelAgentStreams.ts +0 -424
- package/ai/agent/startupProtocol.ts +0 -53
- package/ai/agent/streamAgentChatTurn.ts +0 -1278
- package/ai/agent/streamAgentChatTurnUtils.ts +0 -738
- package/ai/agent/types.ts +0 -71
- package/ai/agent/utils/imageOutput.ts +0 -33
- package/ai/agent/utils/sortUtils.ts +0 -250
- package/ai/agent/web/referencePickerUtils.ts +0 -146
- package/ai/ai.locale.ts +0 -1079
- package/ai/chat/accumulateToolCallChunks.ts +0 -95
- package/ai/chat/fetchUtils.native.ts +0 -276
- package/ai/chat/fetchUtils.ts +0 -153
- package/ai/chat/parseApiError.ts +0 -64
- package/ai/chat/parseMultilineSSE.ts +0 -95
- package/ai/chat/sendOpenAICompletionsRequest.native.ts +0 -682
- package/ai/chat/sendOpenAICompletionsRequest.ts +0 -703
- package/ai/chat/sendOpenAIResponseRequest.ts +0 -491
- package/ai/chat/shouldUseServerProxy.ts +0 -18
- package/ai/chat/sseClient.native.ts +0 -91
- package/ai/chat/sseClient.ts +0 -67
- package/ai/chat/streamReader.native.ts +0 -31
- package/ai/chat/streamReader.ts +0 -62
- package/ai/chat/updateTotalUsage.ts +0 -72
- package/ai/context/buildReferenceContext.ts +0 -437
- package/ai/context/calculateContextUsage.ts +0 -133
- package/ai/context/retention.ts +0 -165
- package/ai/context/tokenUtils.ts +0 -78
- package/ai/index.ts +0 -1
- package/ai/llm/calculateGeminiImageTokens.ts +0 -57
- package/ai/llm/deepinfra.ts +0 -28
- package/ai/llm/fireworks.ts +0 -50
- package/ai/llm/generateRequestBody.ts +0 -165
- package/ai/llm/getModelContextWindow.ts +0 -84
- package/ai/llm/getNoloKey.ts +0 -31
- package/ai/llm/getPricing.ts +0 -199
- package/ai/llm/hooks/useModelPricing.ts +0 -75
- package/ai/llm/imagePricing.ts +0 -40
- package/ai/llm/isResponseAPIModel.ts +0 -13
- package/ai/llm/mimo.ts +0 -71
- package/ai/llm/mistral.ts +0 -22
- package/ai/llm/modelAvatar.ts +0 -427
- package/ai/llm/models.ts +0 -45
- package/ai/llm/openrouterModels.ts +0 -269
- package/ai/llm/providers.ts +0 -306
- package/ai/llm/reasoningModels.ts +0 -28
- package/ai/llm/types.ts +0 -59
- package/ai/llm/usageRequestOptions.ts +0 -59
- package/ai/memory/capture.ts +0 -148
- package/ai/memory/consolidate.ts +0 -104
- package/ai/memory/delete.ts +0 -147
- package/ai/memory/overlay.ts +0 -84
- package/ai/memory/query.ts +0 -38
- package/ai/memory/queryShared.ts +0 -160
- package/ai/memory/rank.ts +0 -105
- package/ai/memory/recentRelationshipRecap.ts +0 -249
- package/ai/memory/remember.ts +0 -167
- package/ai/memory/runtime.ts +0 -76
- package/ai/memory/store.ts +0 -20
- package/ai/memory/storeShared.ts +0 -76
- package/ai/memory/types.ts +0 -46
- package/ai/memory/understanding.ts +0 -349
- package/ai/memory/understandingGreeting.ts +0 -264
- package/ai/messages/type.ts +0 -20
- package/ai/policy/personalizationDialog.ts +0 -333
- package/ai/policy/runtimePolicy.ts +0 -440
- package/ai/policy/selfUpdateFields.ts +0 -48
- package/ai/policy/types.ts +0 -64
- package/ai/skills/referenceRuntime.ts +0 -274
- package/ai/skills/skillDiagnostics.ts +0 -251
- package/ai/skills/skillDocBuilder.ts +0 -139
- package/ai/skills/skillDocProtocol.ts +0 -434
- package/ai/skills/skillReferenceSummary.ts +0 -63
- package/ai/skills/skillSummaryMarker.ts +0 -26
- package/ai/token/calculatePrice.ts +0 -544
- package/ai/token/db.ts +0 -98
- package/ai/token/externalToolCost.ts +0 -330
- package/ai/token/hooks/useRecords.ts +0 -65
- package/ai/token/missingUsageEstimate.ts +0 -42
- package/ai/token/modelUsageQuery.ts +0 -252
- package/ai/token/normalizeUsage.ts +0 -84
- package/ai/token/openaiImageGenerationUsage.ts +0 -56
- package/ai/token/prepareTokenUsageData.ts +0 -88
- package/ai/token/query.ts +0 -88
- package/ai/token/queryUserTokens.ts +0 -59
- package/ai/token/resolveBillingTarget.ts +0 -52
- package/ai/token/saveTokenRecord.ts +0 -53
- package/ai/token/serverDialogProjection.ts +0 -78
- package/ai/token/serverTokenWriter.ts +0 -143
- package/ai/token/stats.ts +0 -21
- package/ai/token/tokenThunks.ts +0 -24
- package/ai/token/types.ts +0 -93
- package/ai/tools/agent/agentTools.ts +0 -176
- package/ai/tools/agent/agentUpdateShared.ts +0 -311
- package/ai/tools/agent/callAgentTool.ts +0 -139
- package/ai/tools/agent/createAgentTool.ts +0 -512
- package/ai/tools/agent/createDialogTool.ts +0 -69
- package/ai/tools/agent/createSkillAgentTool.ts +0 -62
- package/ai/tools/agent/parallelBudget.ts +0 -221
- package/ai/tools/agent/presets/appBuilderPreset.ts +0 -145
- package/ai/tools/agent/runLlmTool.ts +0 -96
- package/ai/tools/agent/runStreamingAgentTool.ts +0 -73
- package/ai/tools/agent/skillAgentArgs.ts +0 -106
- package/ai/tools/agent/skillAgentPreset.ts +0 -89
- package/ai/tools/agent/streamParallelAgentsTool.ts +0 -122
- package/ai/tools/agent/updateAgentTool.ts +0 -96
- package/ai/tools/agent/updateSelfTool.ts +0 -113
- package/ai/tools/amazonProductScraperTool.ts +0 -86
- package/ai/tools/apifyActorClient.ts +0 -45
- package/ai/tools/appEditGuard.ts +0 -372
- package/ai/tools/appReadSnapshot.ts +0 -153
- package/ai/tools/appTools.ts +0 -1549
- package/ai/tools/applyEditTool.ts +0 -256
- package/ai/tools/applyLineEditsTool.ts +0 -312
- package/ai/tools/browserTools/click.ts +0 -33
- package/ai/tools/browserTools/closeSession.ts +0 -29
- package/ai/tools/browserTools/common.ts +0 -27
- package/ai/tools/browserTools/openSession.ts +0 -48
- package/ai/tools/browserTools/readContent.ts +0 -38
- package/ai/tools/browserTools/selectOption.ts +0 -46
- package/ai/tools/browserTools/typeText.ts +0 -42
- package/ai/tools/category/createCategoryTool.ts +0 -66
- package/ai/tools/category/queryContentsByCategoryTool.ts +0 -69
- package/ai/tools/category/updateContentCategoryTool.ts +0 -75
- package/ai/tools/cfBrowserTools.ts +0 -319
- package/ai/tools/cfSpeechToTextTool.ts +0 -49
- package/ai/tools/checkEnvTool.ts +0 -65
- package/ai/tools/cloudflareCrawlTool.ts +0 -289
- package/ai/tools/codeSearchTool.ts +0 -111
- package/ai/tools/codeTools.ts +0 -101
- package/ai/tools/createDocTool.ts +0 -132
- package/ai/tools/createPlanTool.ts +0 -999
- package/ai/tools/createSkillDocTool.ts +0 -155
- package/ai/tools/createWorkflowTool.ts +0 -154
- package/ai/tools/deepseekOcrTool.ts +0 -34
- package/ai/tools/delayTool.ts +0 -31
- package/ai/tools/deleteSpacesTool.ts +0 -325
- package/ai/tools/deleteSpacesToolModel.ts +0 -159
- package/ai/tools/devReloadUtils.ts +0 -29
- package/ai/tools/dialogMessageSearch.ts +0 -137
- package/ai/tools/doctorSkillTool.ts +0 -72
- package/ai/tools/ecommerceScraperTool.ts +0 -86
- package/ai/tools/emailTools.ts +0 -549
- package/ai/tools/evalSkillTool.ts +0 -92
- package/ai/tools/exaSearchTool.ts +0 -64
- package/ai/tools/execBashTool.ts +0 -379
- package/ai/tools/executeSqlTool.ts +0 -192
- package/ai/tools/fetchWebpageSupport.ts +0 -309
- package/ai/tools/fetchWebpageTool.ts +0 -84
- package/ai/tools/geminiImagePreviewTool.ts +0 -361
- package/ai/tools/generateDocxTool.ts +0 -215
- package/ai/tools/googleSearchScraperTool.ts +0 -106
- package/ai/tools/importDataTool.ts +0 -133
- package/ai/tools/importSkillTool.ts +0 -162
- package/ai/tools/index.ts +0 -1858
- package/ai/tools/listFilesTool.ts +0 -82
- package/ai/tools/listUserSpacesTool.ts +0 -113
- package/ai/tools/modelUsageTools.ts +0 -142
- package/ai/tools/olmOcrTool.ts +0 -34
- package/ai/tools/openaiImageTool.ts +0 -218
- package/ai/tools/paddleOcrTool.ts +0 -34
- package/ai/tools/prepareTools.ts +0 -23
- package/ai/tools/readDocTool.ts +0 -84
- package/ai/tools/readFileTool.ts +0 -211
- package/ai/tools/readTool.ts +0 -163
- package/ai/tools/readXPostTool.ts +0 -233
- package/ai/tools/rememberMemoryTool.ts +0 -84
- package/ai/tools/remotionVideoTool.ts +0 -151
- package/ai/tools/searchDialogMessagesTool.ts +0 -222
- package/ai/tools/searchRepoTool.ts +0 -115
- package/ai/tools/searchWorkspaceTool.ts +0 -259
- package/ai/tools/skillFollowup.ts +0 -86
- package/ai/tools/surfWeatherTool.ts +0 -169
- package/ai/tools/table/addTableRowTool.ts +0 -217
- package/ai/tools/table/createTableTool.ts +0 -315
- package/ai/tools/table/rowTools.ts +0 -366
- package/ai/tools/table/schemaTools.ts +0 -244
- package/ai/tools/table/shareTableTool.ts +0 -148
- package/ai/tools/table/toolShared.ts +0 -129
- package/ai/tools/toolApiClient.ts +0 -198
- package/ai/tools/toolNameAliases.ts +0 -57
- package/ai/tools/toolResultError.ts +0 -42
- package/ai/tools/toolRunSlice.ts +0 -303
- package/ai/tools/toolSchemaCompatibility.ts +0 -53
- package/ai/tools/toolVisibility.ts +0 -4
- package/ai/tools/types.ts +0 -20
- package/ai/tools/uiAskChoiceTool.ts +0 -104
- package/ai/tools/updateContentTitleTool.ts +0 -84
- package/ai/tools/updateDocTool.ts +0 -105
- package/ai/tools/updateUserPreferenceProfileTool.ts +0 -145
- package/ai/tools/whisperTool.ts +0 -77
- package/ai/tools/writeFileTool.ts +0 -210
- package/ai/tools/youtubeScraperTool.ts +0 -116
- package/ai/tools/ziweiChartTool.ts +0 -678
- package/ai/types.ts +0 -55
- package/ai/workflow/workflowExecutor.ts +0 -323
- package/ai/workflow/workflowSlice.ts +0 -73
- package/ai/workflow/workflowTypes.ts +0 -106
- package/client/compactDialog.ts +0 -222
- package/connector-experimental/capabilities.ts +0 -73
- package/connector-experimental/codexBinary.ts +0 -41
- package/connector-experimental/heartbeatLoop.ts +0 -22
- package/connector-experimental/index.ts +0 -5
- package/connector-experimental/machineInfo.ts +0 -46
- package/connector-experimental/protocol.ts +0 -54
|
@@ -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
|
-
}
|