nolo-cli 0.1.13 → 0.1.15
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 +9 -2
- package/agent-runtime/hostAdapter.ts +53 -0
- package/agent-runtime/index.ts +28 -0
- package/agent-runtime/localLoop.ts +62 -0
- package/agent-runtime/runtimeDecision.ts +70 -0
- package/agent-runtime/types.ts +87 -0
- package/agentRunCommand.ts +104 -0
- package/agentRuntimeCommands.ts +139 -22
- package/agentRuntimeLocal.ts +7 -0
- package/ai/agent/_executeModel.ts +118 -0
- package/ai/agent/agentSlice.ts +544 -1
- package/ai/agent/appWorkingMemory.ts +126 -0
- package/ai/agent/avatarUtils.ts +24 -0
- package/ai/agent/buildEditingContext.ts +373 -0
- package/ai/agent/buildSystemPrompt.ts +532 -0
- package/ai/agent/cleanAgentMessages.ts +140 -0
- package/ai/agent/cliChatClient.ts +119 -0
- package/ai/agent/contextCompiler.ts +107 -0
- package/ai/agent/contextLayerContract.ts +44 -0
- package/ai/agent/createAgentSchema.ts +234 -0
- package/ai/agent/executeToolCall.ts +58 -0
- package/ai/agent/fetchAgentContexts.ts +42 -0
- package/ai/agent/generatePrompt.ts +3 -0
- package/ai/agent/getFullChatContextKeys.ts +168 -0
- package/ai/agent/hooks/fetchPublicAgents.ts +133 -0
- package/ai/agent/hooks/useAgentConfig.ts +61 -0
- package/ai/agent/hooks/useAgentDialog.ts +35 -0
- package/ai/agent/hooks/useAgentFormValidation.ts +202 -0
- package/ai/agent/hooks/usePublicAgents.ts +473 -0
- package/ai/agent/persistMessageWithFixedId.ts +37 -0
- package/ai/agent/planSlice.ts +259 -0
- package/ai/agent/referenceUtils.ts +229 -0
- package/ai/agent/runAgentBackground.ts +238 -0
- package/ai/agent/runAgentClientLoop.ts +138 -0
- package/ai/agent/runtimeGuidance.ts +97 -0
- package/ai/agent/runtimeServerBase.ts +37 -0
- package/ai/agent/server/fetchPublicAgents.ts +128 -0
- package/ai/agent/startParallelAgentStreams.ts +424 -0
- package/ai/agent/startupProtocol.ts +53 -0
- package/ai/agent/streamAgentChatTurn.ts +1299 -0
- package/ai/agent/streamAgentChatTurnUtils.ts +738 -0
- package/ai/agent/types.ts +71 -0
- package/ai/agent/utils/imageOutput.ts +39 -0
- package/ai/agent/utils/publicImageAgentMode.ts +26 -0
- package/ai/agent/utils/sortUtils.ts +250 -0
- package/ai/agent/web/referencePickerUtils.ts +146 -0
- package/ai/ai.locale.ts +1083 -0
- package/ai/chat/accumulateToolCallChunks.ts +95 -0
- package/ai/chat/fetchUtils.native.ts +276 -0
- package/ai/chat/fetchUtils.ts +153 -0
- package/ai/chat/inlineImageUrlsForCustomProvider.ts +117 -0
- package/ai/chat/parseApiError.ts +64 -0
- package/ai/chat/parseMultilineSSE.ts +95 -0
- package/ai/chat/sendOpenAICompletionsRequest.native.ts +682 -0
- package/ai/chat/sendOpenAICompletionsRequest.ts +712 -0
- package/ai/chat/sendOpenAIResponseRequest.ts +512 -0
- package/ai/chat/shouldUseServerProxy.ts +18 -0
- package/ai/chat/sseClient.native.ts +91 -0
- package/ai/chat/sseClient.ts +67 -0
- package/ai/chat/streamReader.native.ts +31 -0
- package/ai/chat/streamReader.ts +62 -0
- package/ai/chat/updateTotalUsage.ts +72 -0
- package/ai/context/buildReferenceContext.ts +437 -0
- package/ai/context/calculateContextUsage.ts +133 -0
- package/ai/context/retention.ts +165 -0
- package/ai/context/tokenUtils.ts +78 -0
- package/ai/index.ts +1 -1
- package/ai/llm/agentCapabilities.ts +74 -0
- package/ai/llm/calculateGeminiImageTokens.ts +57 -0
- package/ai/llm/deepinfra.ts +28 -0
- package/ai/llm/fireworks.ts +68 -0
- package/ai/llm/generateRequestBody.ts +165 -0
- package/ai/llm/getModelContextWindow.ts +84 -0
- package/ai/llm/getNoloKey.ts +37 -0
- package/ai/llm/getPricing.ts +232 -0
- package/ai/llm/hooks/useModelPricing.ts +75 -0
- package/ai/llm/imagePricing.ts +66 -0
- package/ai/llm/isResponseAPIModel.ts +13 -0
- package/ai/llm/kimi.ts +18 -0
- package/ai/llm/mimo.ts +71 -0
- package/ai/llm/mistral.ts +22 -0
- package/ai/llm/modelAvatar.ts +427 -0
- package/ai/llm/models.ts +45 -0
- package/ai/llm/openrouterModels.ts +141 -0
- package/ai/llm/providers.ts +307 -0
- package/ai/llm/reasoningModels.ts +28 -0
- package/ai/llm/types.ts +59 -0
- package/ai/llm/usageRequestOptions.ts +59 -0
- package/ai/memory/capture.ts +148 -0
- package/ai/memory/consolidate.ts +104 -0
- package/ai/memory/delete.ts +147 -0
- package/ai/memory/overlay.ts +84 -0
- package/ai/memory/query.ts +38 -0
- package/ai/memory/queryShared.ts +160 -0
- package/ai/memory/rank.ts +105 -0
- package/ai/memory/recentRelationshipRecap.ts +247 -0
- package/ai/memory/remember.ts +167 -0
- package/ai/memory/runtime.ts +76 -0
- package/ai/memory/store.ts +20 -0
- package/ai/memory/storeShared.ts +76 -0
- package/ai/memory/types.ts +46 -0
- package/ai/memory/understanding.ts +349 -0
- package/ai/memory/understandingGreeting.ts +264 -0
- package/ai/messages/type.ts +20 -0
- package/ai/policy/personalizationDialog.ts +333 -0
- package/ai/policy/runtimePolicy.ts +440 -0
- package/ai/policy/selfUpdateFields.ts +48 -0
- package/ai/policy/types.ts +64 -0
- package/ai/skills/referenceRuntime.ts +274 -0
- package/ai/skills/skillDiagnostics.ts +251 -0
- package/ai/skills/skillDocBuilder.ts +139 -0
- package/ai/skills/skillDocProtocol.ts +434 -0
- package/ai/skills/skillReferenceSummary.ts +63 -0
- package/ai/skills/skillSummaryMarker.ts +26 -0
- package/ai/token/calculatePrice.ts +546 -0
- package/ai/token/db.ts +98 -0
- package/ai/token/externalToolCost.ts +321 -0
- package/ai/token/hooks/useRecords.ts +65 -0
- package/ai/token/missingUsageEstimate.ts +42 -0
- package/ai/token/modelUsageQuery.ts +252 -0
- package/ai/token/normalizeUsage.ts +84 -0
- package/ai/token/openaiImageGenerationUsage.ts +56 -0
- package/ai/token/prepareTokenUsageData.ts +88 -0
- package/ai/token/query.ts +88 -0
- package/ai/token/queryUserTokens.ts +59 -0
- package/ai/token/resolveBillingTarget.ts +52 -0
- package/ai/token/saveTokenRecord.ts +53 -0
- package/ai/token/serverDialogProjection.ts +78 -0
- package/ai/token/serverTokenWriter.ts +143 -0
- package/ai/token/stats.ts +21 -0
- package/ai/token/tokenThunks.ts +24 -0
- package/ai/token/types.ts +93 -0
- package/ai/tools/agent/agentTools.ts +176 -0
- package/ai/tools/agent/agentUpdateShared.ts +311 -0
- package/ai/tools/agent/callAgentTool.ts +139 -0
- package/ai/tools/agent/createAgentTool.ts +512 -0
- package/ai/tools/agent/createDialogTool.ts +69 -0
- package/ai/tools/agent/createSkillAgentTool.ts +62 -0
- package/ai/tools/agent/parallelBudget.ts +221 -0
- package/ai/tools/agent/presets/appBuilderPreset.ts +147 -0
- package/ai/tools/agent/runLlmTool.ts +96 -0
- package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
- package/ai/tools/agent/skillAgentArgs.ts +106 -0
- package/ai/tools/agent/skillAgentPreset.ts +89 -0
- package/ai/tools/agent/streamParallelAgentsTool.ts +122 -0
- package/ai/tools/agent/updateAgentTool.ts +96 -0
- package/ai/tools/agent/updateSelfTool.ts +113 -0
- package/ai/tools/amazonProductScraperTool.ts +86 -0
- package/ai/tools/apifyActorClient.ts +45 -0
- package/ai/tools/appEditGuard.ts +372 -0
- package/ai/tools/appReadSnapshot.ts +153 -0
- package/ai/tools/appTools.ts +1549 -0
- package/ai/tools/applyEditTool.ts +256 -0
- package/ai/tools/applyLineEditsTool.ts +312 -0
- package/ai/tools/browserTools/click.ts +33 -0
- package/ai/tools/browserTools/closeSession.ts +29 -0
- package/ai/tools/browserTools/common.ts +27 -0
- package/ai/tools/browserTools/openSession.ts +48 -0
- package/ai/tools/browserTools/readContent.ts +38 -0
- package/ai/tools/browserTools/selectOption.ts +46 -0
- package/ai/tools/browserTools/typeText.ts +42 -0
- package/ai/tools/category/createCategoryTool.ts +66 -0
- package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
- package/ai/tools/category/updateContentCategoryTool.ts +75 -0
- package/ai/tools/cfBrowserTools.ts +319 -0
- package/ai/tools/cfSpeechToTextTool.ts +49 -0
- package/ai/tools/checkEnvTool.ts +65 -0
- package/ai/tools/cloudflareCrawlTool.ts +289 -0
- package/ai/tools/codeSearchTool.ts +111 -0
- package/ai/tools/codeTools.ts +101 -0
- package/ai/tools/createDocTool.ts +132 -0
- package/ai/tools/createPlanTool.ts +999 -0
- package/ai/tools/createSkillDocTool.ts +155 -0
- package/ai/tools/createWorkflowTool.ts +154 -0
- package/ai/tools/deepseekOcrTool.ts +34 -0
- package/ai/tools/delayTool.ts +31 -0
- package/ai/tools/deleteSpacesTool.ts +325 -0
- package/ai/tools/deleteSpacesToolModel.ts +159 -0
- package/ai/tools/devReloadUtils.ts +29 -0
- package/ai/tools/dialogMessageSearch.ts +137 -0
- package/ai/tools/doctorSkillTool.ts +72 -0
- package/ai/tools/ecommerceScraperTool.ts +86 -0
- package/ai/tools/emailTools.ts +549 -0
- package/ai/tools/evalSkillTool.ts +92 -0
- package/ai/tools/exaSearchTool.ts +64 -0
- package/ai/tools/execBashTool.ts +379 -0
- package/ai/tools/executeSqlTool.ts +192 -0
- package/ai/tools/fetchWebpageSupport.ts +309 -0
- package/ai/tools/fetchWebpageTool.ts +84 -0
- package/ai/tools/geminiImagePreviewTool.ts +361 -0
- package/ai/tools/generateDocxTool.ts +215 -0
- package/ai/tools/googleSearchScraperTool.ts +106 -0
- package/ai/tools/importDataTool.ts +133 -0
- package/ai/tools/importSkillTool.ts +162 -0
- package/ai/tools/index.ts +1927 -0
- package/ai/tools/listFilesTool.ts +82 -0
- package/ai/tools/listUserSpacesTool.ts +113 -0
- package/ai/tools/modelUsageTools.ts +199 -0
- package/ai/tools/olmOcrTool.ts +34 -0
- package/ai/tools/openaiImageTool.ts +267 -0
- package/ai/tools/prepareTools.ts +23 -0
- package/ai/tools/readDocTool.ts +84 -0
- package/ai/tools/readFileTool.ts +211 -0
- package/ai/tools/readTool.ts +163 -0
- package/ai/tools/readXPostTool.ts +233 -0
- package/ai/tools/rememberMemoryTool.ts +84 -0
- package/ai/tools/remotionVideoTool.ts +151 -0
- package/ai/tools/searchDialogMessagesTool.ts +222 -0
- package/ai/tools/searchRepoTool.ts +115 -0
- package/ai/tools/searchWorkspaceTool.ts +259 -0
- package/ai/tools/skillFollowup.ts +86 -0
- package/ai/tools/surfWeatherTool.ts +169 -0
- package/ai/tools/table/addTableRowTool.ts +217 -0
- package/ai/tools/table/createTableTool.ts +315 -0
- package/ai/tools/table/rowTools.ts +366 -0
- package/ai/tools/table/schemaTools.ts +244 -0
- package/ai/tools/table/shareTableTool.ts +148 -0
- package/ai/tools/table/toolShared.ts +129 -0
- package/ai/tools/toolApiClient.ts +198 -0
- package/ai/tools/toolNameAliases.ts +57 -0
- package/ai/tools/toolResultError.ts +42 -0
- package/ai/tools/toolRunSlice.ts +303 -0
- package/ai/tools/toolSchemaCompatibility.ts +53 -0
- package/ai/tools/toolVisibility.ts +4 -0
- package/ai/tools/types.ts +20 -0
- package/ai/tools/uiAskChoiceTool.ts +104 -0
- package/ai/tools/updateContentTitleTool.ts +84 -0
- package/ai/tools/updateDocTool.ts +105 -0
- package/ai/tools/updateUserPreferenceProfileTool.ts +145 -0
- package/ai/tools/whisperTool.ts +77 -0
- package/ai/tools/writeFileTool.ts +210 -0
- package/ai/tools/youtubeScraperTool.ts +116 -0
- package/ai/tools/ziweiChartTool.ts +678 -0
- package/ai/types.ts +55 -0
- package/ai/workflow/workflowExecutor.ts +323 -0
- package/ai/workflow/workflowSlice.ts +73 -0
- package/ai/workflow/workflowTypes.ts +106 -0
- package/client/agentRun.test.ts +240 -0
- package/client/agentRun.ts +182 -19
- package/client/compactDialog.test.ts +238 -0
- package/client/localRuntimeAdapter.test.ts +135 -0
- package/client/localRuntimeAdapter.ts +244 -0
- package/client/profileConfig.test.ts +40 -0
- package/client/streamingOutput.test.ts +22 -0
- package/client/streamingOutput.ts +38 -0
- package/commandRegistry.ts +11 -2
- package/connector-experimental/index.ts +5 -0
- package/database/actions/cacheMergedUserData.ts +64 -0
- package/database/actions/common.ts +242 -0
- package/database/actions/deleteFile.ts +40 -0
- package/database/actions/fetchUserData.ts +16 -0
- package/database/actions/fileContent.ts +125 -0
- package/database/actions/patch.ts +155 -0
- package/database/actions/read.ts +337 -0
- package/database/actions/readAndWait.ts +224 -0
- package/database/actions/readRequestManager.ts +120 -0
- package/database/actions/remove.ts +94 -0
- package/database/actions/replication.ts +366 -0
- package/database/actions/upload.ts +174 -0
- package/database/actions/upsert.ts +56 -0
- package/database/actions/write.ts +126 -0
- package/database/client/db.native.ts +73 -0
- package/database/client/db.ts +51 -0
- package/database/client/fetchUserData.ts +61 -0
- package/database/client/handleError.ts +19 -0
- package/database/client/queryRequest.ts +21 -0
- package/database/config.ts +21 -0
- package/database/dbActionThunks.ts +1 -0
- package/database/dbSlice.ts +149 -0
- package/database/email.ts +42 -0
- package/database/fileRing.ts +51 -0
- package/database/fileSharding.ts +70 -0
- package/database/fileStorage.native.ts +92 -0
- package/database/fileStorage.ts +232 -0
- package/database/fileUrl.ts +34 -0
- package/database/hooks/useUserData.ts +489 -0
- package/database/index.ts +1 -0
- package/database/keys.ts +765 -0
- package/database/queryPrefixes.ts +14 -0
- package/database/requests.ts +443 -0
- package/database/runtimeServerContext.ts +35 -0
- package/database/server/MemoryDB.ts +76 -0
- package/database/server/actorAccess.ts +76 -0
- package/database/server/agentDelegation.ts +124 -0
- package/database/server/coreDataOwnership.ts +13 -0
- package/database/server/coreDataProxy.ts +76 -0
- package/database/server/cybotReadonly.ts +18 -0
- package/database/server/dataHandlers.ts +111 -0
- package/database/server/db.ts +118 -0
- package/database/server/dbPath.ts +20 -0
- package/database/server/delete.ts +499 -0
- package/database/server/emailRepository.ts +1480 -0
- package/database/server/ensureDbOpen.ts +12 -0
- package/database/server/fileRead.ts +337 -0
- package/database/server/fileService.ts +436 -0
- package/database/server/handleTransaction.ts +86 -0
- package/database/server/patch.ts +282 -0
- package/database/server/query.ts +138 -0
- package/database/server/read.ts +325 -0
- package/database/server/resourceAccess.ts +211 -0
- package/database/server/routes.ts +110 -0
- package/database/server/spaceMemberAuthority.ts +67 -0
- package/database/server/upload.ts +159 -0
- package/database/server/write.ts +494 -0
- package/database/server/writeAuthority.ts +133 -0
- package/database/sqliteDb.ts +46 -0
- package/database/table/deleteTable.ts +120 -0
- package/database/tenantPlacement.ts +57 -0
- package/database/tombstones.ts +52 -0
- package/database/userDataLoadDecision.ts +17 -0
- package/database/userDataMerge.ts +95 -0
- package/database/userPreferenceRegister.ts +108 -0
- package/database/utils/dbPath.ts +47 -0
- package/database/utils/ulid.native.ts +6 -0
- package/database/utils/ulid.ts +1 -0
- package/index.ts +37 -19
- package/localRuntimeDb.ts +28 -0
- package/package.json +17 -4
- package/runtimeModeArgs.ts +33 -0
- package/tui/readlineWorkspace.ts +1 -0
- package/tui/session.ts +22 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { CreateAgentToolArgs } from "./createAgentTool";
|
|
2
|
+
|
|
3
|
+
export type SkillAgentMode = "creator" | "evaluator" | "creator_evaluator";
|
|
4
|
+
|
|
5
|
+
export interface CreateSkillAgentToolArgs {
|
|
6
|
+
mode?: SkillAgentMode;
|
|
7
|
+
name?: string;
|
|
8
|
+
model?: string;
|
|
9
|
+
provider?: string;
|
|
10
|
+
isPublic?: boolean;
|
|
11
|
+
references?: CreateAgentToolArgs["references"];
|
|
12
|
+
linkedSpaces?: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DEFAULT_PROVIDER = "openrouter";
|
|
16
|
+
const DEFAULT_MODEL = "xiaomi/mimo-v2.5-pro";
|
|
17
|
+
|
|
18
|
+
const buildPreset = (mode: SkillAgentMode) => {
|
|
19
|
+
const commonTools = [
|
|
20
|
+
"createSkillDoc",
|
|
21
|
+
"importSkill",
|
|
22
|
+
"doctorSkill",
|
|
23
|
+
"evalSkill",
|
|
24
|
+
"readDoc",
|
|
25
|
+
"updateDoc",
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
if (mode === "creator") {
|
|
29
|
+
return {
|
|
30
|
+
defaultName: "Skill Creator",
|
|
31
|
+
tools: commonTools,
|
|
32
|
+
introduction: "帮你设计、创建和完善 skill 文档协议的助手。",
|
|
33
|
+
greeting:
|
|
34
|
+
"你好,我是 Skill Creator。\n\n告诉我你想做什么能力,我会帮你把它整理成可导入、可诊断、可评估的 skill 文档。",
|
|
35
|
+
prompt: `你是一个 skill creator。你的任务是把用户的能力需求沉淀成 skill 文档,而不是泛泛给建议。
|
|
36
|
+
|
|
37
|
+
核心原则:
|
|
38
|
+
- Agent 是第一公民;只有切换 Agent 成本更高时,才优先补 skill
|
|
39
|
+
- skill 以普通 doc 为存储底座,使用隐藏的 skill-config / eval-config 协议块
|
|
40
|
+
- 优先用 createSkillDoc 创建;已有文档则用 updateDoc 定点补齐协议
|
|
41
|
+
- 创建后立刻运行 doctorSkill;必要时再运行 evalSkill
|
|
42
|
+
- 默认做最小可用协议,不要过早发明复杂 DSL
|
|
43
|
+
- 对外部技能导入,优先保留文本流程,再谨慎映射工具`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (mode === "evaluator") {
|
|
48
|
+
return {
|
|
49
|
+
defaultName: "Skill Evaluator",
|
|
50
|
+
tools: [...commonTools, "runLlm"],
|
|
51
|
+
introduction: "帮你诊断 skill 文档质量、协议完整性与评估结果的助手。",
|
|
52
|
+
greeting:
|
|
53
|
+
"你好,我是 Skill Evaluator。\n\n把一个 skill 文档给我,我会检查协议、工具绑定、评估用例和潜在风险。",
|
|
54
|
+
prompt: `你是一个 skill evaluator。你的任务是审查 skill 是否真的可用,而不是替用户写新功能。
|
|
55
|
+
|
|
56
|
+
工作顺序:
|
|
57
|
+
1. 先 doctorSkill 看协议和明显问题
|
|
58
|
+
2. 再 evalSkill 看 eval-config 是否通过
|
|
59
|
+
3. 如发现问题,指出最小修复点
|
|
60
|
+
4. 除非用户要求,不主动大改 skill
|
|
61
|
+
|
|
62
|
+
审查重点:
|
|
63
|
+
- 工具名是否有效、是否需要 canonicalize
|
|
64
|
+
- requiredSkills / recommendedSkills 是否表达准确
|
|
65
|
+
- eval-config 是否覆盖关键成功路径
|
|
66
|
+
- 是否存在过期命令、环境前提、登录态依赖等隐患`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
defaultName: "Skill Builder",
|
|
72
|
+
tools: [...commonTools, "runLlm", "createAgent", "updateAgent"],
|
|
73
|
+
introduction: "既能创建也能评估 skill 文档协议,还能帮助你沉淀 skill 工作流助手。",
|
|
74
|
+
greeting:
|
|
75
|
+
"你好,我是 Skill Builder。\n\n我可以帮你把能力做成 skill、导入外部 skill、诊断质量、补评估,并继续迭代相关 agent。",
|
|
76
|
+
prompt: `你是一个 skill creator + evaluator。
|
|
77
|
+
|
|
78
|
+
原则:
|
|
79
|
+
- 先判断该问题是否更适合换 Agent;只有没必要切 Agent 或切 Agent 成本更高时,才补 skill
|
|
80
|
+
- skill 负责动态能力编排;knowledge 负责内容;dispatch 负责任务分派
|
|
81
|
+
- 创建或更新 skill 后,必须至少做一次 doctorSkill;如果有 eval-config,再跑 evalSkill
|
|
82
|
+
- 不把 recommendedSkills 当硬加载;requiredSkills 才是硬依赖
|
|
83
|
+
- 尽量帮助用户形成“创建 -> 诊断 -> 评估 -> 迭代”的闭环`,
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const buildCreateSkillAgentArgs = (
|
|
88
|
+
args: CreateSkillAgentToolArgs
|
|
89
|
+
): CreateAgentToolArgs => {
|
|
90
|
+
const mode = args.mode ?? "creator_evaluator";
|
|
91
|
+
const preset = buildPreset(mode);
|
|
92
|
+
return {
|
|
93
|
+
name: (args.name ?? "").trim() || preset.defaultName,
|
|
94
|
+
model: (args.model ?? "").trim() || DEFAULT_MODEL,
|
|
95
|
+
provider: (args.provider ?? "").trim() || DEFAULT_PROVIDER,
|
|
96
|
+
introduction: preset.introduction,
|
|
97
|
+
greeting: preset.greeting,
|
|
98
|
+
prompt: preset.prompt,
|
|
99
|
+
isPublic: args.isPublic ?? false,
|
|
100
|
+
tools: preset.tools,
|
|
101
|
+
references: args.references ?? [],
|
|
102
|
+
linkedSpaces: args.linkedSpaces ?? [],
|
|
103
|
+
temperature: 0.3,
|
|
104
|
+
reasoning_effort: "medium",
|
|
105
|
+
};
|
|
106
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Agent } from "app/types";
|
|
2
|
+
import { DataType } from "create/types";
|
|
3
|
+
import { createAgentKey } from "database/keys";
|
|
4
|
+
import { ulid } from "ulid";
|
|
5
|
+
import {
|
|
6
|
+
normalizeReferences,
|
|
7
|
+
type FormData as AgentFormData,
|
|
8
|
+
} from "ai/agent/createAgentSchema";
|
|
9
|
+
import { ALL_MODELS, type ModelWithProvider } from "ai/llm/models";
|
|
10
|
+
import { getModelPricing } from "ai/llm/getPricing";
|
|
11
|
+
import {
|
|
12
|
+
buildCreateSkillAgentArgs,
|
|
13
|
+
type CreateSkillAgentToolArgs,
|
|
14
|
+
} from "./skillAgentArgs";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
buildCreateSkillAgentArgs,
|
|
18
|
+
type CreateSkillAgentToolArgs,
|
|
19
|
+
type SkillAgentMode,
|
|
20
|
+
} from "./skillAgentArgs";
|
|
21
|
+
|
|
22
|
+
const findModelConfig = (
|
|
23
|
+
modelName: string,
|
|
24
|
+
provider?: string
|
|
25
|
+
): ModelWithProvider | null => {
|
|
26
|
+
const name = (modelName ?? "").trim();
|
|
27
|
+
const prov = (provider ?? "").trim();
|
|
28
|
+
if (!name) return null;
|
|
29
|
+
if (prov) {
|
|
30
|
+
const exact = ALL_MODELS.find((m) => m.name === name && m.provider === prov);
|
|
31
|
+
if (exact) return exact;
|
|
32
|
+
}
|
|
33
|
+
const matches = ALL_MODELS.filter((m) => m.name === name);
|
|
34
|
+
return matches.length === 1 ? matches[0] : null;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const buildSkillAgentRecord = (options: {
|
|
38
|
+
userId: string;
|
|
39
|
+
currentSpaceId?: string;
|
|
40
|
+
args: CreateSkillAgentToolArgs;
|
|
41
|
+
}): Agent & { dbKey: string; publicDbKey: string } => {
|
|
42
|
+
const createArgs = buildCreateSkillAgentArgs(options.args);
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
const id = ulid();
|
|
45
|
+
const dbKey = createAgentKey.private(options.userId, id);
|
|
46
|
+
const publicDbKey = createAgentKey.public(id);
|
|
47
|
+
const modelConfig = findModelConfig(createArgs.model, createArgs.provider);
|
|
48
|
+
const pricing = getModelPricing(
|
|
49
|
+
modelConfig?.provider || createArgs.provider,
|
|
50
|
+
createArgs.model
|
|
51
|
+
);
|
|
52
|
+
const references = normalizeReferences((createArgs.references as any) ?? []);
|
|
53
|
+
const tags = ["skill", "builder", options.args.mode ?? "creator_evaluator"];
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
id,
|
|
57
|
+
dbKey,
|
|
58
|
+
type: DataType.AGENT,
|
|
59
|
+
userId: options.userId,
|
|
60
|
+
name: createArgs.name,
|
|
61
|
+
model: createArgs.model,
|
|
62
|
+
provider: modelConfig?.provider || createArgs.provider,
|
|
63
|
+
apiSource: "platform",
|
|
64
|
+
useServerProxy: true,
|
|
65
|
+
hasVision: Boolean(modelConfig?.hasVision),
|
|
66
|
+
prompt: createArgs.prompt ?? "",
|
|
67
|
+
introduction: createArgs.introduction ?? "",
|
|
68
|
+
greeting: createArgs.greeting,
|
|
69
|
+
isPublic: !!createArgs.isPublic,
|
|
70
|
+
tags,
|
|
71
|
+
tools: createArgs.tools ?? [],
|
|
72
|
+
references,
|
|
73
|
+
linkedSpaces: createArgs.linkedSpaces ?? [],
|
|
74
|
+
customProviderUrl: "",
|
|
75
|
+
apiKey: "",
|
|
76
|
+
whitelist: [],
|
|
77
|
+
inputPrice: pricing?.inputPrice ?? 0,
|
|
78
|
+
outputPrice: pricing?.outputPrice ?? 0,
|
|
79
|
+
temperature: createArgs.temperature,
|
|
80
|
+
reasoning_effort: createArgs.reasoning_effort,
|
|
81
|
+
createdAt: now,
|
|
82
|
+
updatedAt: now,
|
|
83
|
+
dialogCount: 0,
|
|
84
|
+
messageCount: 0,
|
|
85
|
+
tokenCount: 0,
|
|
86
|
+
spaceId: options.currentSpaceId,
|
|
87
|
+
publicDbKey,
|
|
88
|
+
} as unknown as Agent & { dbKey: string; publicDbKey: string };
|
|
89
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export const streamParallelAgentsFunctionSchema = {
|
|
2
|
+
name: "streamParallelAgents",
|
|
3
|
+
description:
|
|
4
|
+
"并行调用多个 Agent,让它们分别以流式方式输出观点。适合多模型发散、评审团式讨论和多视角分析。",
|
|
5
|
+
parameters: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
task: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "要并行交给多个 Agent 的任务描述。",
|
|
11
|
+
},
|
|
12
|
+
agents: {
|
|
13
|
+
type: "array",
|
|
14
|
+
description: "需要并行调用的 Agent 列表。",
|
|
15
|
+
items: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
agentKey: {
|
|
19
|
+
type: "string",
|
|
20
|
+
description: "目标 Agent 的 dbKey。",
|
|
21
|
+
},
|
|
22
|
+
label: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "可选:分支展示名称。",
|
|
25
|
+
},
|
|
26
|
+
branchId: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "可选:分支稳定标识。",
|
|
29
|
+
},
|
|
30
|
+
serverBase: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description:
|
|
33
|
+
"可选:该 Agent 所在的 nolo server origin,例如 Windows 机器通过 Cloudflare 暴露的 https://win.example.com。" +
|
|
34
|
+
"跨域目标必须由服务端 AGENT_TOOL_ALLOWED_SERVER_BASES 明确放行。" +
|
|
35
|
+
"如果目标 Agent 记录声明了 delegation.serverBase / runtimeServerBase,服务端会在未显式传入时自动路由。",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
required: ["agentKey"],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
serverBase: {
|
|
42
|
+
type: "string",
|
|
43
|
+
description:
|
|
44
|
+
"可选:默认目标 nolo server origin。agents[*].serverBase 会覆盖此值;目标 Agent 记录的 runtime 元数据可在未传值时自动补齐。",
|
|
45
|
+
},
|
|
46
|
+
timeoutMs: {
|
|
47
|
+
type: "number",
|
|
48
|
+
description: "可选:单个分支的超时时间(毫秒)。",
|
|
49
|
+
},
|
|
50
|
+
budgetCredits: {
|
|
51
|
+
type: "number",
|
|
52
|
+
description:
|
|
53
|
+
"可选:本轮并行调用可消耗的剩余预算(单位:积分 / credits)。结果会返回 spentCredits / remainingCredits / exhausted,供父 Agent 决定是否继续下一轮。",
|
|
54
|
+
},
|
|
55
|
+
returnMode: {
|
|
56
|
+
type: "string",
|
|
57
|
+
enum: ["handoff", "continue"],
|
|
58
|
+
description:
|
|
59
|
+
'可选:handoff 表示并行结果直接结束本轮并交给用户;continue 表示把分支结果留在上下文里,父 Agent 继续思考。',
|
|
60
|
+
},
|
|
61
|
+
displayMode: {
|
|
62
|
+
type: "string",
|
|
63
|
+
enum: ["folded", "inline"],
|
|
64
|
+
description:
|
|
65
|
+
'可选:inline 表示把完整分支回答直接作为当前对话里的普通消息展开。folded 已废弃,运行时会自动按 inline 处理。',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
required: ["task", "agents", "returnMode"],
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export async function streamParallelAgentsFunc(args: {
|
|
73
|
+
task: string;
|
|
74
|
+
agents: Array<{ agentKey: string; label?: string; branchId?: string; serverBase?: string }>;
|
|
75
|
+
serverBase?: string;
|
|
76
|
+
timeoutMs?: number;
|
|
77
|
+
budgetCredits?: number;
|
|
78
|
+
returnMode?: "handoff" | "continue";
|
|
79
|
+
displayMode?: "folded" | "inline";
|
|
80
|
+
}) {
|
|
81
|
+
const task = typeof args.task === "string" ? args.task.trim() : "";
|
|
82
|
+
const agents = Array.isArray(args.agents) ? args.agents : [];
|
|
83
|
+
const timeoutMs =
|
|
84
|
+
typeof args.timeoutMs === "number" && Number.isFinite(args.timeoutMs) && args.timeoutMs > 0
|
|
85
|
+
? args.timeoutMs
|
|
86
|
+
: undefined;
|
|
87
|
+
const budgetCredits =
|
|
88
|
+
typeof args.budgetCredits === "number" &&
|
|
89
|
+
Number.isFinite(args.budgetCredits) &&
|
|
90
|
+
args.budgetCredits > 0
|
|
91
|
+
? Number(args.budgetCredits.toFixed(6))
|
|
92
|
+
: undefined;
|
|
93
|
+
const returnMode = args.returnMode === "continue" ? "continue" : "handoff";
|
|
94
|
+
const displayMode = "inline";
|
|
95
|
+
const serverBase =
|
|
96
|
+
typeof args.serverBase === "string" && args.serverBase.trim()
|
|
97
|
+
? args.serverBase.trim()
|
|
98
|
+
: undefined;
|
|
99
|
+
|
|
100
|
+
if (!task) {
|
|
101
|
+
throw new Error("streamParallelAgents: 缺少 task。");
|
|
102
|
+
}
|
|
103
|
+
if (agents.length === 0) {
|
|
104
|
+
throw new Error("streamParallelAgents: 缺少 agents。");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
rawData: {
|
|
109
|
+
task,
|
|
110
|
+
agents,
|
|
111
|
+
...(serverBase ? { serverBase } : {}),
|
|
112
|
+
...(timeoutMs ? { timeoutMs } : {}),
|
|
113
|
+
...(budgetCredits ? { budgetCredits } : {}),
|
|
114
|
+
returnMode,
|
|
115
|
+
displayMode,
|
|
116
|
+
},
|
|
117
|
+
displayData:
|
|
118
|
+
returnMode === "continue"
|
|
119
|
+
? `将并行调用 ${agents.length} 个 Agent,并把结果返回给父 Agent 继续会商${budgetCredits ? `(预算 ${budgetCredits} 积分)` : ""}`
|
|
120
|
+
: `将并行调用 ${agents.length} 个 Agent${budgetCredits ? `(预算 ${budgetCredits} 积分)` : ""}`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// ai/tools/agent/updateAgentTool.ts
|
|
2
|
+
|
|
3
|
+
import type { RootState } from "app/store";
|
|
4
|
+
import type { Agent } from "app/types";
|
|
5
|
+
import { updateAgent } from "ai/agent/agentSlice";
|
|
6
|
+
import { selectUserId } from "auth/authSlice";
|
|
7
|
+
import {
|
|
8
|
+
type UpdateAgentToolArgs,
|
|
9
|
+
agentUpdateFieldSchemaProperties,
|
|
10
|
+
assertAgentUpdateConfirmation,
|
|
11
|
+
buildPatch,
|
|
12
|
+
buildRawDataWithUpdateInfo,
|
|
13
|
+
buildUpdateThunkPreviousAgent,
|
|
14
|
+
extractAgentId,
|
|
15
|
+
fetchAgentByDbKey,
|
|
16
|
+
formatUpdatedAgentOutput,
|
|
17
|
+
listRequestedFields,
|
|
18
|
+
validateUpdateArgs,
|
|
19
|
+
} from "./agentUpdateShared";
|
|
20
|
+
|
|
21
|
+
export const updateAgentToolFunctionSchema = {
|
|
22
|
+
name: "updateAgent",
|
|
23
|
+
description:
|
|
24
|
+
"根据给定配置更新一个指定的 Agent。该工具用于通用高权限维护,默认需要用户确认后才会执行。",
|
|
25
|
+
parameters: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
agentId: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "要更新的 Agent 的 dbKey,格式为 agent-{userId}-{id}。",
|
|
31
|
+
},
|
|
32
|
+
...agentUpdateFieldSchemaProperties,
|
|
33
|
+
},
|
|
34
|
+
required: ["agentId"],
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// --- Executor ---
|
|
39
|
+
|
|
40
|
+
export async function updateAgentToolFunc(
|
|
41
|
+
args: UpdateAgentToolArgs,
|
|
42
|
+
thunkApi: any
|
|
43
|
+
): Promise<{ rawData: Agent; displayData: string }> {
|
|
44
|
+
const state = thunkApi.getState() as RootState;
|
|
45
|
+
const userId = selectUserId(state);
|
|
46
|
+
const db = (thunkApi.extra as any)?.db;
|
|
47
|
+
|
|
48
|
+
validateUpdateArgs(userId, { requireAgentId: true, agentId: args.agentId });
|
|
49
|
+
|
|
50
|
+
const dbKey = args.agentId.trim();
|
|
51
|
+
const previousAgent = await fetchAgentByDbKey(dbKey, db);
|
|
52
|
+
|
|
53
|
+
if (!previousAgent) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`未找到 dbKey 为 "${dbKey}" 的 Agent。\n` +
|
|
56
|
+
`如果您尝试更新旧版助手 (Cybot),请新建一个 Agent 或在 UI 界面上手动迁移。`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const agentId = extractAgentId(dbKey);
|
|
61
|
+
const formData = buildPatch(args);
|
|
62
|
+
const requestedFields = listRequestedFields(args);
|
|
63
|
+
|
|
64
|
+
assertAgentUpdateConfirmation({
|
|
65
|
+
scope: "generic",
|
|
66
|
+
requestedFields,
|
|
67
|
+
confirmed: args.__confirmedSelfEvolution === true,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const previousAgentForUpdate = buildUpdateThunkPreviousAgent(previousAgent, userId!);
|
|
71
|
+
|
|
72
|
+
const agent = await thunkApi
|
|
73
|
+
.dispatch(updateAgent({
|
|
74
|
+
userId: userId!,
|
|
75
|
+
agentId,
|
|
76
|
+
formData,
|
|
77
|
+
previousAgent: previousAgentForUpdate,
|
|
78
|
+
}))
|
|
79
|
+
.unwrap()
|
|
80
|
+
.catch((e: any) => {
|
|
81
|
+
throw new Error(`更新 Agent 失败:${e?.message ?? "未知错误"}`);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const rawDataWithUpdateInfo = buildRawDataWithUpdateInfo(
|
|
85
|
+
agent,
|
|
86
|
+
previousAgentForUpdate,
|
|
87
|
+
requestedFields,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// TODO: Add a richer generic-agent-update preview/audit view before enabling any
|
|
91
|
+
// field-level auto-approval for updateAgent. For now this tool stays confirmation-first.
|
|
92
|
+
return {
|
|
93
|
+
rawData: rawDataWithUpdateInfo as any,
|
|
94
|
+
displayData: formatUpdatedAgentOutput(agent),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { RootState } from "app/store";
|
|
2
|
+
import type { Agent } from "app/types";
|
|
3
|
+
import { updateAgent } from "ai/agent/agentSlice";
|
|
4
|
+
import {
|
|
5
|
+
selectAutoApproveSelfUpdateFields,
|
|
6
|
+
} from "app/settings/settingSlice";
|
|
7
|
+
import { selectUserId } from "auth/authSlice";
|
|
8
|
+
import { selectCurrentDialogConfig } from "chat/dialog/dialogSlice";
|
|
9
|
+
import { resolveMessageAgentKey } from "chat/messages/messageAgent";
|
|
10
|
+
import { selectMsgById } from "chat/messages/messageSlice";
|
|
11
|
+
import {
|
|
12
|
+
type UpdateSelfToolArgs,
|
|
13
|
+
agentUpdateFieldSchemaProperties,
|
|
14
|
+
assertAgentUpdateConfirmation,
|
|
15
|
+
buildPatch,
|
|
16
|
+
buildRawDataWithUpdateInfo,
|
|
17
|
+
buildUpdateThunkPreviousAgent,
|
|
18
|
+
extractAgentId,
|
|
19
|
+
fetchAgentByDbKey,
|
|
20
|
+
formatUpdatedAgentOutput,
|
|
21
|
+
listRequestedFields,
|
|
22
|
+
validateUpdateArgs,
|
|
23
|
+
} from "./agentUpdateShared";
|
|
24
|
+
|
|
25
|
+
export const updateSelfToolFunctionSchema = {
|
|
26
|
+
name: "updateSelf",
|
|
27
|
+
description:
|
|
28
|
+
"更新当前正在运行的 Agent 自己。低风险字段可直接更新,其他字段会先向用户确认。",
|
|
29
|
+
parameters: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: agentUpdateFieldSchemaProperties,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const resolveCurrentAgentKey = (
|
|
36
|
+
state: RootState,
|
|
37
|
+
parentMessageId?: string,
|
|
38
|
+
): string | undefined => {
|
|
39
|
+
const parentMessage = parentMessageId
|
|
40
|
+
? selectMsgById(state, parentMessageId)
|
|
41
|
+
: undefined;
|
|
42
|
+
const parentAgentKey = resolveMessageAgentKey(parentMessage);
|
|
43
|
+
if (parentAgentKey) {
|
|
44
|
+
return parentAgentKey;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const currentDialog = selectCurrentDialogConfig(state);
|
|
48
|
+
const firstAgentKey = Array.isArray(currentDialog?.cybots)
|
|
49
|
+
? currentDialog.cybots.find(
|
|
50
|
+
(item): item is string =>
|
|
51
|
+
typeof item === "string" && item.trim().length > 0,
|
|
52
|
+
)
|
|
53
|
+
: undefined;
|
|
54
|
+
return firstAgentKey?.trim();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export async function updateSelfToolFunc(
|
|
58
|
+
args: UpdateSelfToolArgs,
|
|
59
|
+
thunkApi: any,
|
|
60
|
+
runtime?: { parentMessageId?: string },
|
|
61
|
+
): Promise<{ rawData: Agent; displayData: string }> {
|
|
62
|
+
const state = thunkApi.getState() as RootState;
|
|
63
|
+
const userId = selectUserId(state);
|
|
64
|
+
const db = (thunkApi.extra as any)?.db;
|
|
65
|
+
|
|
66
|
+
validateUpdateArgs(userId);
|
|
67
|
+
|
|
68
|
+
const currentAgentKey = resolveCurrentAgentKey(state, runtime?.parentMessageId);
|
|
69
|
+
if (!currentAgentKey) {
|
|
70
|
+
throw new Error("updateSelf 失败:无法识别当前正在运行的 Agent。");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const previousAgent = await fetchAgentByDbKey(currentAgentKey, db);
|
|
74
|
+
if (!previousAgent) {
|
|
75
|
+
throw new Error(`updateSelf 失败:未找到当前 Agent(${currentAgentKey})。`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const requestedFields = listRequestedFields(args);
|
|
79
|
+
const autoApprovedFields = selectAutoApproveSelfUpdateFields(state);
|
|
80
|
+
|
|
81
|
+
assertAgentUpdateConfirmation({
|
|
82
|
+
scope: "self",
|
|
83
|
+
requestedFields,
|
|
84
|
+
confirmed: args.__confirmedSelfEvolution === true,
|
|
85
|
+
autoApprovedFields,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const previousAgentForUpdate = buildUpdateThunkPreviousAgent(previousAgent, userId!);
|
|
89
|
+
const agent = await thunkApi
|
|
90
|
+
.dispatch(
|
|
91
|
+
updateAgent({
|
|
92
|
+
userId: userId!,
|
|
93
|
+
agentId: extractAgentId(currentAgentKey),
|
|
94
|
+
formData: buildPatch(args),
|
|
95
|
+
previousAgent: previousAgentForUpdate,
|
|
96
|
+
}),
|
|
97
|
+
)
|
|
98
|
+
.unwrap()
|
|
99
|
+
.catch((e: any) => {
|
|
100
|
+
throw new Error(`updateSelf 失败:${e?.message ?? "未知错误"}`);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// TODO: Future automation should prefer memory/doc capture before high-impact self
|
|
104
|
+
// mutations, and add audit history for rollback. Keep this tool focused on execution.
|
|
105
|
+
return {
|
|
106
|
+
rawData: buildRawDataWithUpdateInfo(
|
|
107
|
+
agent,
|
|
108
|
+
previousAgentForUpdate,
|
|
109
|
+
requestedFields,
|
|
110
|
+
) as any,
|
|
111
|
+
displayData: formatUpdatedAgentOutput(agent),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// /ai/tools/amazonProductScraperTool.ts
|
|
2
|
+
|
|
3
|
+
import { callApifyActor } from "./apifyActorClient";
|
|
4
|
+
|
|
5
|
+
export const amazonProductScraperFunctionSchema = {
|
|
6
|
+
name: "amazonProductScraper",
|
|
7
|
+
description:
|
|
8
|
+
"使用 Apify Amazon Product Scraper 抓取亚马逊产品数据(类目页或商品详情页 URL)。",
|
|
9
|
+
parameters: {
|
|
10
|
+
type: "object",
|
|
11
|
+
properties: {
|
|
12
|
+
urls: {
|
|
13
|
+
type: "array",
|
|
14
|
+
description:
|
|
15
|
+
"一个或多个 Amazon 类目或商品 URL,对应 categoryOrProductUrls。",
|
|
16
|
+
items: { type: "string" },
|
|
17
|
+
},
|
|
18
|
+
maxItemsPerStartUrl: {
|
|
19
|
+
type: "integer",
|
|
20
|
+
minimum: 0,
|
|
21
|
+
description: "每个起始 URL 最大产品数。",
|
|
22
|
+
},
|
|
23
|
+
language: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "页面语言,如 en, de, fr 等。",
|
|
26
|
+
},
|
|
27
|
+
proxyCountry: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "代理国家,默认 AUTO_SELECT_PROXY_COUNTRY。",
|
|
30
|
+
},
|
|
31
|
+
maxSearchPagesPerStartUrl: {
|
|
32
|
+
type: "integer",
|
|
33
|
+
minimum: 1,
|
|
34
|
+
},
|
|
35
|
+
extraInput: {
|
|
36
|
+
type: "object",
|
|
37
|
+
description: "可选。透传给 Apify 的其他 input 字段。",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
required: ["urls"],
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export async function amazonProductScraperFunc(
|
|
45
|
+
args: {
|
|
46
|
+
urls: string[];
|
|
47
|
+
maxItemsPerStartUrl?: number;
|
|
48
|
+
language?: string;
|
|
49
|
+
proxyCountry?: string;
|
|
50
|
+
maxSearchPagesPerStartUrl?: number;
|
|
51
|
+
extraInput?: Record<string, any>;
|
|
52
|
+
},
|
|
53
|
+
thunkApi: any
|
|
54
|
+
) {
|
|
55
|
+
const {
|
|
56
|
+
urls,
|
|
57
|
+
maxItemsPerStartUrl,
|
|
58
|
+
language,
|
|
59
|
+
proxyCountry,
|
|
60
|
+
maxSearchPagesPerStartUrl,
|
|
61
|
+
extraInput = {},
|
|
62
|
+
} = args;
|
|
63
|
+
|
|
64
|
+
if (!urls || !urls.length) {
|
|
65
|
+
throw new Error("Amazon Product Scraper:urls 不能为空。");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const input: any = {
|
|
69
|
+
categoryOrProductUrls: urls.map((url) => ({ url })),
|
|
70
|
+
...extraInput,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (typeof maxItemsPerStartUrl === "number")
|
|
74
|
+
input.maxItemsPerStartUrl = maxItemsPerStartUrl;
|
|
75
|
+
if (typeof language === "string") input.language = language;
|
|
76
|
+
if (typeof proxyCountry === "string") input.proxyCountry = proxyCountry;
|
|
77
|
+
if (typeof maxSearchPagesPerStartUrl === "number")
|
|
78
|
+
input.maxSearchPagesPerStartUrl = maxSearchPagesPerStartUrl;
|
|
79
|
+
|
|
80
|
+
return callApifyActor(thunkApi, {
|
|
81
|
+
actorId: "junglee~Amazon-crawler",
|
|
82
|
+
input,
|
|
83
|
+
resultType: "datasetItems",
|
|
84
|
+
displayName: "Amazon Product Scraper",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// 文件路径: ai/tools/apifyActorClient.ts
|
|
2
|
+
|
|
3
|
+
import { callToolApi } from "./toolApiClient";
|
|
4
|
+
|
|
5
|
+
export type ApifyResultType = "datasetItems" | "run" | "kvOutput";
|
|
6
|
+
|
|
7
|
+
export interface CallApifyActorParams {
|
|
8
|
+
actorId: string; // 如 "apify~website-content-crawler"
|
|
9
|
+
input: any; // 直接给 Apify 的 inputSchema
|
|
10
|
+
resultType?: ApifyResultType; // 默认 "datasetItems"
|
|
11
|
+
displayName?: string; // 用于 UI 提示用的名字,如 "YouTube Scraper"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 通用的 Apify Actor 调用封装。
|
|
16
|
+
* 所有具体 scraping 工具都通过它调用后端 /api/apify-actor。
|
|
17
|
+
*/
|
|
18
|
+
export async function callApifyActor(
|
|
19
|
+
thunkApi: any,
|
|
20
|
+
params: CallApifyActorParams
|
|
21
|
+
): Promise<{ rawData: any; displayData: string }> {
|
|
22
|
+
const { actorId, input, resultType = "datasetItems", displayName } = params;
|
|
23
|
+
|
|
24
|
+
const data = await callToolApi(
|
|
25
|
+
thunkApi,
|
|
26
|
+
"/api/apify-actor",
|
|
27
|
+
{ actorId, input, resultType },
|
|
28
|
+
{ withAuth: true }
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const isArray = Array.isArray(data);
|
|
32
|
+
const count = isArray ? data.length : undefined;
|
|
33
|
+
|
|
34
|
+
const title = displayName || actorId;
|
|
35
|
+
const preview =
|
|
36
|
+
typeof data === "string"
|
|
37
|
+
? data.slice(0, 400)
|
|
38
|
+
: JSON.stringify(isArray ? data[0] : data, null, 2).slice(0, 800);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
rawData: data,
|
|
42
|
+
displayData: `✅ ${title} 调用成功${typeof count === "number" ? `,返回 ${count} 条记录` : ""
|
|
43
|
+
}\n\n**结果预览:**\n${preview}`,
|
|
44
|
+
};
|
|
45
|
+
}
|