nolo-cli 0.1.39 → 0.1.41

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 (438) hide show
  1. package/README.md +4 -4
  2. package/agent-runtime/dialogWritePlan.ts +39 -0
  3. package/agent-runtime/hostAdapter.ts +4 -0
  4. package/agent-runtime/hybridRecordStore.ts +5 -3
  5. package/agent-runtime/index.ts +15 -0
  6. package/agent-runtime/localLoop.ts +87 -7
  7. package/agent-runtime/localToolPolicy.ts +2 -13
  8. package/agent-runtime/localWorkspaceTools.ts +42 -110
  9. package/agent-runtime/runtimeToolPolicy.ts +2 -11
  10. package/agent-runtime/runtimeToolSurface.ts +198 -0
  11. package/agent-runtime/types.ts +1 -0
  12. package/agentAliases.ts +2 -1
  13. package/agentRunCommand.ts +10 -32
  14. package/agentRuntimeLocal.ts +1 -0
  15. package/ai/agent/_executeModel.ts +146 -0
  16. package/ai/agent/agentSlice.ts +556 -1
  17. package/ai/agent/appWorkingMemory.ts +126 -0
  18. package/ai/agent/buildEditingContext.ts +378 -0
  19. package/ai/agent/buildSystemPrompt.ts +585 -0
  20. package/ai/agent/canvasEditingContext.ts +49 -0
  21. package/ai/agent/cleanAgentMessages.ts +140 -0
  22. package/ai/agent/cliChatClient.ts +153 -0
  23. package/ai/agent/cliExecutor.ts +314 -40
  24. package/ai/agent/contextCompiler.ts +107 -0
  25. package/ai/agent/contextLayerContract.ts +44 -0
  26. package/ai/agent/createAgentSchema.ts +272 -0
  27. package/ai/agent/currentTimeContext.ts +65 -0
  28. package/ai/agent/executeToolCall.ts +58 -0
  29. package/ai/agent/fetchAgentContexts.ts +42 -0
  30. package/ai/agent/generatePrompt.ts +3 -0
  31. package/ai/agent/getFullChatContextKeys.ts +168 -0
  32. package/ai/agent/guidedCreation/capabilities.ts +84 -0
  33. package/ai/agent/guidedCreation/types.ts +38 -0
  34. package/ai/agent/isLiveAudioOnlyAgent.ts +26 -0
  35. package/ai/agent/liveAudioModel.ts +2 -0
  36. package/ai/agent/pageBuilderHandoffRules.ts +75 -0
  37. package/ai/agent/persistMessageWithFixedId.ts +37 -0
  38. package/ai/agent/planSlice.ts +259 -0
  39. package/ai/agent/referenceUtils.ts +229 -0
  40. package/ai/agent/runAgentBackground.ts +310 -0
  41. package/ai/agent/runAgentClientLoop.ts +164 -0
  42. package/ai/agent/runtimeGuidance.ts +116 -0
  43. package/ai/agent/serverOrigin.ts +7 -0
  44. package/ai/agent/startParallelAgentStreams.ts +424 -0
  45. package/ai/agent/startupProtocol.ts +53 -0
  46. package/ai/agent/streamAgentChatTurn.ts +2001 -0
  47. package/ai/agent/streamAgentChatTurnUtils.ts +860 -0
  48. package/ai/agent/toolFailureGuard.ts +99 -0
  49. package/ai/agent/types.ts +73 -0
  50. package/ai/agent/utils/imageOutput.ts +37 -0
  51. package/ai/agent/utils/publicImageAgentMode.ts +26 -0
  52. package/ai/ai.locale.ts +1095 -0
  53. package/ai/chat/accumulateToolCallChunks.ts +126 -0
  54. package/ai/chat/fetchUtils.ts +143 -0
  55. package/ai/chat/inlineImageUrlsForCustomProvider.ts +117 -0
  56. package/ai/chat/parseApiError.ts +67 -0
  57. package/ai/chat/parseMultilineSSE.ts +95 -0
  58. package/ai/chat/sendOpenAICompletionsRequest.ts +897 -0
  59. package/ai/chat/sendOpenAIResponseRequest.ts +720 -0
  60. package/ai/chat/serverProxyRetry.ts +102 -0
  61. package/ai/chat/shouldUseServerProxy.ts +18 -0
  62. package/ai/chat/streamRetry.ts +46 -0
  63. package/ai/chat/updateTotalUsage.ts +89 -0
  64. package/ai/context/buildReferenceContext.ts +437 -0
  65. package/ai/context/retention.ts +165 -0
  66. package/ai/context/tokenUtils.ts +78 -0
  67. package/ai/llm/agentCapabilities.ts +74 -0
  68. package/ai/llm/deepinfra.ts +79 -0
  69. package/ai/llm/fireworks.ts +68 -0
  70. package/ai/llm/generateRequestBody.ts +165 -0
  71. package/ai/llm/getModelContextWindow.ts +93 -0
  72. package/ai/llm/getPricing.ts +252 -0
  73. package/ai/llm/imagePricing.ts +66 -0
  74. package/ai/llm/isResponseAPIModel.ts +13 -0
  75. package/ai/llm/kimi.ts +23 -0
  76. package/ai/llm/mimo.ts +99 -0
  77. package/ai/llm/mistral.ts +21 -0
  78. package/ai/llm/models.ts +45 -0
  79. package/ai/llm/openrouterModels.ts +6 -0
  80. package/ai/llm/providers.ts +313 -0
  81. package/ai/llm/reasoningModels.ts +27 -0
  82. package/ai/llm/types.ts +82 -0
  83. package/ai/llm/usageRequestOptions.ts +59 -0
  84. package/ai/memory/queryShared.ts +161 -0
  85. package/ai/memory/recentRelationshipRecap.ts +247 -0
  86. package/ai/memory/remember.ts +167 -0
  87. package/ai/memory/store.ts +20 -0
  88. package/ai/memory/storeShared.ts +76 -0
  89. package/ai/memory/types.ts +46 -0
  90. package/ai/memory/understanding.ts +349 -0
  91. package/ai/memory/understandingGreeting.ts +264 -0
  92. package/ai/policy/personalizationDialog.ts +333 -0
  93. package/ai/policy/runtimePolicy.ts +454 -0
  94. package/ai/policy/selfUpdateFields.ts +48 -0
  95. package/ai/policy/types.ts +64 -0
  96. package/ai/skills/referenceRuntime.ts +274 -0
  97. package/ai/skills/skillDiagnostics.ts +251 -0
  98. package/ai/skills/skillDocBuilder.ts +139 -0
  99. package/ai/skills/skillSummaryMarker.ts +26 -0
  100. package/ai/token/calculatePrice.ts +576 -0
  101. package/ai/token/missingUsageEstimate.ts +42 -0
  102. package/ai/token/normalizeUsage.ts +124 -0
  103. package/ai/token/openaiImageGenerationUsage.ts +56 -0
  104. package/ai/token/prepareTokenUsageData.ts +93 -0
  105. package/ai/token/resolveBillingTarget.ts +52 -0
  106. package/ai/token/saveTokenRecord.ts +53 -0
  107. package/ai/token/types.ts +103 -0
  108. package/ai/tools/agent/agentTools.ts +235 -0
  109. package/ai/tools/agent/agentUpdateShared.ts +311 -0
  110. package/ai/tools/agent/callAgentTool.ts +139 -0
  111. package/ai/tools/agent/createAgentTool.ts +512 -0
  112. package/ai/tools/agent/createDialogTool.ts +69 -0
  113. package/ai/tools/agent/createSkillAgentTool.ts +62 -0
  114. package/ai/tools/agent/parallelBudget.ts +221 -0
  115. package/ai/tools/agent/prepareAgentDraftTool.ts +159 -0
  116. package/ai/tools/agent/presets/appBuilderPreset.ts +154 -0
  117. package/ai/tools/agent/runLlmTool.ts +96 -0
  118. package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
  119. package/ai/tools/agent/skillAgentArgs.ts +106 -0
  120. package/ai/tools/agent/startAgentDialogTool.ts +53 -0
  121. package/ai/tools/agent/streamParallelAgentsTool.ts +123 -0
  122. package/ai/tools/agent/updateAgentTool.ts +96 -0
  123. package/ai/tools/agent/updateSelfTool.ts +113 -0
  124. package/ai/tools/amazonProductScraperTool.ts +86 -0
  125. package/ai/tools/apifyActorClient.ts +45 -0
  126. package/ai/tools/appEditGuard.ts +372 -0
  127. package/ai/tools/appReadSnapshot.ts +153 -0
  128. package/ai/tools/appTools.ts +1549 -0
  129. package/ai/tools/applyEditTool.ts +259 -0
  130. package/ai/tools/applyLineEditsTool.ts +315 -0
  131. package/ai/tools/browserTools/click.ts +33 -0
  132. package/ai/tools/browserTools/closeSession.ts +29 -0
  133. package/ai/tools/browserTools/common.ts +27 -0
  134. package/ai/tools/browserTools/openSession.ts +48 -0
  135. package/ai/tools/browserTools/readContent.ts +38 -0
  136. package/ai/tools/browserTools/selectOption.ts +46 -0
  137. package/ai/tools/browserTools/typeText.ts +42 -0
  138. package/ai/tools/category/createCategoryTool.ts +66 -0
  139. package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
  140. package/ai/tools/category/updateContentCategoryTool.ts +75 -0
  141. package/ai/tools/cfBrowserTools.ts +319 -0
  142. package/ai/tools/cfSpeechToTextTool.ts +49 -0
  143. package/ai/tools/checkEnvTool.ts +102 -0
  144. package/ai/tools/cloudflareCrawlTool.ts +289 -0
  145. package/ai/tools/codeSearchTool.ts +123 -0
  146. package/ai/tools/codeTools.ts +101 -0
  147. package/ai/tools/convertMarxistsBookTool.ts +103 -0
  148. package/ai/tools/createDocTool.ts +132 -0
  149. package/ai/tools/createSkillDocTool.ts +155 -0
  150. package/ai/tools/createWorkflowTool.ts +154 -0
  151. package/ai/tools/delayTool.ts +31 -0
  152. package/ai/tools/deleteSpacesTool.ts +325 -0
  153. package/ai/tools/deleteSpacesToolModel.ts +159 -0
  154. package/ai/tools/devReloadUtils.ts +29 -0
  155. package/ai/tools/dialogMessageSearch.ts +137 -0
  156. package/ai/tools/doctorSkillTool.ts +72 -0
  157. package/ai/tools/ecommerceScraperTool.ts +86 -0
  158. package/ai/tools/emailTools.ts +549 -0
  159. package/ai/tools/evalSkillTool.ts +92 -0
  160. package/ai/tools/exaSearchTool.ts +63 -0
  161. package/ai/tools/execShellTool.ts +266 -0
  162. package/ai/tools/executeSqlTool.ts +192 -0
  163. package/ai/tools/fetchWebpageSupport.ts +333 -0
  164. package/ai/tools/fetchWebpageTool.ts +97 -0
  165. package/ai/tools/geminiImagePreviewTool.ts +386 -0
  166. package/ai/tools/generateDocxTool.ts +215 -0
  167. package/ai/tools/googleSearchScraperTool.ts +106 -0
  168. package/ai/tools/importDataTool.ts +133 -0
  169. package/ai/tools/importSkillTool.ts +162 -0
  170. package/ai/tools/index.ts +2308 -0
  171. package/ai/tools/jdProductScraperTool.ts +821 -0
  172. package/ai/tools/listUserSpacesTool.ts +113 -0
  173. package/ai/tools/localFilesTool.ts +276 -0
  174. package/ai/tools/marxistsOfflineBook.ts +253 -0
  175. package/ai/tools/modelUsageTools.ts +206 -0
  176. package/ai/tools/noloWorkspaceReadTools.ts +467 -0
  177. package/ai/tools/olmOcrTool.ts +33 -0
  178. package/ai/tools/openaiImageTool.ts +267 -0
  179. package/ai/tools/prepareTools.ts +23 -0
  180. package/ai/tools/readDocTool.ts +88 -0
  181. package/ai/tools/readFileTool.ts +214 -0
  182. package/ai/tools/readTool.ts +194 -0
  183. package/ai/tools/readXPostTool.ts +229 -0
  184. package/ai/tools/readXhsProfileTool.ts +627 -0
  185. package/ai/tools/rememberMemoryTool.ts +84 -0
  186. package/ai/tools/remotionVideoTool.ts +151 -0
  187. package/ai/tools/searchDialogMessagesTool.ts +222 -0
  188. package/ai/tools/searchWorkspaceTool.ts +259 -0
  189. package/ai/tools/skillFollowup.ts +86 -0
  190. package/ai/tools/surfWeatherTool.ts +169 -0
  191. package/ai/tools/table/addTableRowTool.ts +217 -0
  192. package/ai/tools/table/createTableTool.ts +315 -0
  193. package/ai/tools/table/rowTools.ts +386 -0
  194. package/ai/tools/table/schemaTools.ts +244 -0
  195. package/ai/tools/table/shareTableTool.ts +148 -0
  196. package/ai/tools/table/toolShared.ts +129 -0
  197. package/ai/tools/taobaoTmallProductScraperTool.ts +49 -0
  198. package/ai/tools/toolApiClient.ts +279 -0
  199. package/ai/tools/toolResultError.ts +42 -0
  200. package/ai/tools/toolRunSlice.ts +303 -0
  201. package/ai/tools/toolSchemaCompatibility.ts +53 -0
  202. package/ai/tools/uiAskChoiceTool.ts +104 -0
  203. package/ai/tools/updateContentTitleTool.ts +84 -0
  204. package/ai/tools/updateDocTool.ts +105 -0
  205. package/ai/tools/updateUserPreferenceProfileTool.ts +153 -0
  206. package/ai/tools/wereadGatewayTool.ts +152 -0
  207. package/ai/tools/whisperTool.ts +76 -0
  208. package/ai/tools/writeFileTool.ts +213 -0
  209. package/ai/tools/youtubeScraperTool.ts +116 -0
  210. package/ai/tools/ziweiChartTool.ts +678 -0
  211. package/ai/types.ts +55 -0
  212. package/ai/workflow/workflowExecutor.ts +323 -0
  213. package/ai/workflow/workflowSlice.ts +73 -0
  214. package/ai/workflow/workflowTypes.ts +106 -0
  215. package/app/actions/syncAppRecord.ts +73 -0
  216. package/app/constants/animationSets.ts +21 -0
  217. package/app/constants/appEditor.ts +99 -0
  218. package/app/favorite/favoriteSlice.ts +690 -0
  219. package/app/favorite/type.ts +43 -0
  220. package/app/hooks/deleteDbKey.ts +233 -0
  221. package/app/i18n/client.ts +13 -0
  222. package/app/i18n/i18n.base.ts +14 -0
  223. package/app/i18n/i18n.config.ts +77 -0
  224. package/app/i18n/index.ts +15 -0
  225. package/app/i18n/mapLanguage.ts +11 -0
  226. package/app/i18n/translations/appBuilder.locale.ts +453 -0
  227. package/app/i18n/translations/error.locale.ts +246 -0
  228. package/app/i18n/translations/interface.locale.ts +2174 -0
  229. package/app/i18n/translations/pricing.locale.ts +397 -0
  230. package/app/i18n/translations/privacy.locale.ts +168 -0
  231. package/app/i18n/translations/seo.locale.ts +129 -0
  232. package/app/i18n/translations/terms.locale.ts +124 -0
  233. package/app/i18n/types.ts +6 -0
  234. package/app/notifications/model.ts +77 -0
  235. package/app/notifications/notificationSlice.ts +141 -0
  236. package/app/reducer.ts +36 -0
  237. package/app/settings/dbActionThunks.ts +34 -0
  238. package/app/settings/defaultSpacePreference.ts +87 -0
  239. package/app/settings/settingSlice.tsx +1212 -0
  240. package/app/settings/settingsRecord.ts +8 -0
  241. package/app/stateViews/runtime.ts +90 -0
  242. package/app/store.ts +55 -0
  243. package/app/theme/colors.ts +280 -0
  244. package/app/theme/fontPreference.ts +77 -0
  245. package/app/theme/theme.config.ts +120 -0
  246. package/app/theme/themeModeBootstrap.ts +123 -0
  247. package/app/types/appSummary.ts +114 -0
  248. package/app/types.ts +358 -0
  249. package/app/utils/appKeys.ts +55 -0
  250. package/app/utils/async.ts +28 -0
  251. package/app/utils/desktopAgentRuntimeTurnClient.ts +73 -0
  252. package/app/utils/env.ts +17 -0
  253. package/app/utils/fileUtils.ts +229 -0
  254. package/app/utils/imageUtils.ts +274 -0
  255. package/app/utils/myContentItems.ts +289 -0
  256. package/app/utils/retryAfter.ts +36 -0
  257. package/app/utils/retryFetch.ts +61 -0
  258. package/app/utils/toast.ts +3 -0
  259. package/auth/action/signUpAction.ts +227 -0
  260. package/auth/adminPermissions.ts +18 -0
  261. package/auth/authSlice.ts +531 -0
  262. package/auth/client/loginRequest.ts +14 -0
  263. package/auth/resetAuthScopedClientState.ts +27 -0
  264. package/auth/routes.ts +178 -0
  265. package/auth/token.ts +63 -0
  266. package/auth/types.ts +40 -0
  267. package/chat/chat.locale.ts +813 -0
  268. package/chat/dialog/actions/addCybotAction.ts +52 -0
  269. package/chat/dialog/actions/addReferenceKeysAction.ts +62 -0
  270. package/chat/dialog/actions/builtinDialogLlm.ts +35 -0
  271. package/chat/dialog/actions/cleanupCliSession.ts +40 -0
  272. package/chat/dialog/actions/createDialogAction.ts +379 -0
  273. package/chat/dialog/actions/createScheduledTaskAction.ts +78 -0
  274. package/chat/dialog/actions/handleSendMessageAction.ts +197 -0
  275. package/chat/dialog/actions/handleSendMessageResolver.ts +27 -0
  276. package/chat/dialog/actions/removeCybotAction.ts +6 -0
  277. package/chat/dialog/actions/removeDialogAgentAction.ts +44 -0
  278. package/chat/dialog/actions/replacePrimaryCybotAction.ts +6 -0
  279. package/chat/dialog/actions/setPrimaryDialogAgentAction.ts +52 -0
  280. package/chat/dialog/actions/updateDialogSummaryAction.ts +430 -0
  281. package/chat/dialog/actions/updateDialogTitleAction.ts +151 -0
  282. package/chat/dialog/actions/updateDialogTitlePolicy.ts +30 -0
  283. package/chat/dialog/actions/updateTokensAction.ts +233 -0
  284. package/chat/dialog/dialogAgents.ts +72 -0
  285. package/chat/dialog/dialogSlice.ts +872 -0
  286. package/chat/dialog/dialogTitle.ts +81 -0
  287. package/chat/dialog/dialogTokenStats.ts +12 -0
  288. package/chat/dialog/dialogUrl.ts +6 -0
  289. package/chat/dialog/goal.ts +108 -0
  290. package/chat/dialog/objectAssistantRegistry.ts +286 -0
  291. package/chat/dialog/schedule.ts +17 -0
  292. package/chat/messages/fetchAndCacheMessages.ts +119 -0
  293. package/chat/messages/fetchConvMsgs.ts +51 -0
  294. package/chat/messages/fileUrl.ts +13 -0
  295. package/chat/messages/messageAgent.ts +8 -0
  296. package/chat/messages/messageContent.ts +199 -0
  297. package/chat/messages/messageContract.ts +88 -0
  298. package/chat/messages/messageSlice.ts +1367 -0
  299. package/chat/messages/toolThunks.ts +625 -0
  300. package/cli/agentAliases.ts +2 -1
  301. package/cli/agentRunCommand.ts +10 -32
  302. package/cli/agentRuntimeLocal.ts +1 -0
  303. package/cli/client/agentRun.ts +67 -95
  304. package/cli/client/localRuntimeAdapter.ts +323 -54
  305. package/cli/commandRegistry.ts +2 -2
  306. package/cli/machineWsRunDispatch.ts +51 -6
  307. package/cli/offlineMarxistsAgentCommand.ts +6 -4
  308. package/client/agentConfigResolver.test.ts +2 -2
  309. package/client/agentRun.test.ts +175 -57
  310. package/client/agentRun.ts +67 -95
  311. package/client/localRuntimeAdapter.test.ts +682 -37
  312. package/client/localRuntimeAdapter.ts +323 -54
  313. package/client/localRuntimeDryRun.test.ts +23 -9
  314. package/client/localToolPolicy.test.ts +4 -4
  315. package/commandRegistry.ts +2 -2
  316. package/core/builtinAgents.ts +209 -0
  317. package/core/config.ts +15 -0
  318. package/core/crypto.ts +51 -0
  319. package/core/generateKeyPairFromSeedV1.ts +15 -0
  320. package/core/generateMainKey.ts +22 -0
  321. package/core/init.ts +41 -0
  322. package/core/localOrigins.ts +8 -0
  323. package/core/password.ts +13 -0
  324. package/core/prefix.ts +23 -0
  325. package/create/editor/transforms/fromMarkdown/index.ts +260 -0
  326. package/create/editor/transforms/fromMarkdown/inline.ts +285 -0
  327. package/create/editor/transforms/fromMarkdown/table.ts +130 -0
  328. package/create/editor/transforms/markdownToSlate.ts +24 -0
  329. package/create/editor/transforms/slateToRenderMarkdown.ts +218 -0
  330. package/create/editor/transforms/slateToSimplifiedMarkdown.ts +224 -0
  331. package/create/editor/transforms/slateToText.ts +33 -0
  332. package/create/editor/utils/slateUtils.ts +233 -0
  333. package/create/space/addSpaceAction.ts +193 -0
  334. package/create/space/category/categoryActions.ts +427 -0
  335. package/create/space/changeSpaceAction.ts +36 -0
  336. package/create/space/constants.ts +8 -0
  337. package/create/space/content/addContentAction.ts +116 -0
  338. package/create/space/content/contentThunks.ts +90 -0
  339. package/create/space/content/deleteContentFromSpaceAction.ts +187 -0
  340. package/create/space/content/deleteMultipleContentAction.ts +112 -0
  341. package/create/space/content/moveContentAction.ts +285 -0
  342. package/create/space/content/updateContentCategoryAction.ts +154 -0
  343. package/create/space/content/updateContentTitleAction.ts +151 -0
  344. package/create/space/content/uploadAndAddFileToSpaceAction.ts +98 -0
  345. package/create/space/contentKeyUtils.ts +117 -0
  346. package/create/space/deleteSpaceAction.ts +276 -0
  347. package/create/space/fetchSpaceAction.ts +70 -0
  348. package/create/space/fetchSpaceSidebarStateAction.ts +26 -0
  349. package/create/space/loadDefaultSpaceAction.ts +57 -0
  350. package/create/space/member/addMemberAction.ts +79 -0
  351. package/create/space/member/fetchUserSpaceMembershipsAction.ts +386 -0
  352. package/create/space/member/memberThunks.ts +47 -0
  353. package/create/space/member/removeMemberAction.ts +67 -0
  354. package/create/space/resolvePreferredSpaceId.ts +113 -0
  355. package/create/space/sidebarVisibleTypes.ts +241 -0
  356. package/create/space/space.locale.ts +1087 -0
  357. package/create/space/spaceAccess.ts +182 -0
  358. package/create/space/spaceCollapsedState.ts +54 -0
  359. package/create/space/spaceKeys.ts +65 -0
  360. package/create/space/spaceSlice.ts +328 -0
  361. package/create/space/spaceThunks.ts +410 -0
  362. package/create/space/types.ts +27 -0
  363. package/create/space/updateSpaceAction.ts +107 -0
  364. package/create/space/utils/permissions.ts +47 -0
  365. package/create/types.ts +21 -0
  366. package/database/actions/agentReadResolution.ts +33 -0
  367. package/database/actions/common.ts +243 -0
  368. package/database/actions/deleteFile.ts +40 -0
  369. package/database/actions/fileContent.ts +125 -0
  370. package/database/actions/patch.ts +155 -0
  371. package/database/actions/read.ts +358 -0
  372. package/database/actions/readAndWait.ts +260 -0
  373. package/database/actions/readRequestManager.ts +120 -0
  374. package/database/actions/readResolution.ts +125 -0
  375. package/database/actions/remove.ts +94 -0
  376. package/database/actions/replication.ts +477 -0
  377. package/database/actions/upload.ts +186 -0
  378. package/database/actions/upsert.ts +56 -0
  379. package/database/actions/write.ts +146 -0
  380. package/database/authority/ownerKey.ts +80 -0
  381. package/database/authority/recordAuthority.ts +67 -0
  382. package/database/authority/userAuthorityRegistry.ts +54 -0
  383. package/database/client/fetchUserData.ts +61 -0
  384. package/database/dbActionThunks.ts +1 -0
  385. package/database/dbSlice.ts +149 -0
  386. package/database/fileRing.ts +51 -0
  387. package/database/fileStorage.ts +232 -0
  388. package/database/fileUrl.ts +34 -0
  389. package/database/keys.ts +767 -0
  390. package/database/queryPrefixes.ts +14 -0
  391. package/database/requests.ts +443 -0
  392. package/database/runtimeServerContext.ts +54 -0
  393. package/database/server/levelAuthorityStore.ts +20 -1
  394. package/database/tenantPlacement.ts +57 -0
  395. package/database/userPreferenceRegister.ts +131 -0
  396. package/database/utils/ulid.ts +1 -0
  397. package/integrations/anthropic/anthropicModels.ts +47 -0
  398. package/integrations/deepseek/models.ts +37 -0
  399. package/integrations/google/models.ts +341 -0
  400. package/integrations/openai/chatCompletionStreamMode.ts +10 -0
  401. package/integrations/openai/filterAndCleanMessages.ts +284 -0
  402. package/integrations/openai/flexTier.ts +102 -0
  403. package/integrations/openai/generateOpenAIRequestBody.ts +274 -0
  404. package/integrations/openai/generateResponseRequestBody.ts +77 -0
  405. package/integrations/openai/models.ts +271 -0
  406. package/integrations/openai/providerBodyCompatibility.ts +23 -0
  407. package/integrations/openai/responsesHelpers.ts +297 -0
  408. package/integrations/x-reader/types.ts +109 -0
  409. package/integrations/xai/models.ts +13 -0
  410. package/integrations/xhs-reader/analyze/profileAnalyzer.ts +205 -0
  411. package/integrations/xhs-reader/backends/playwrightProfileCollector.ts +624 -0
  412. package/integrations/xhs-reader/bridge/readXhsProfileWithBridge.ts +227 -0
  413. package/integrations/xhs-reader/client/xhsWebApiClient.ts +229 -0
  414. package/integrations/xhs-reader/normalize.ts +390 -0
  415. package/integrations/xhs-reader/orchestrator.ts +178 -0
  416. package/integrations/xhs-reader/redaction.ts +68 -0
  417. package/integrations/xhs-reader/types.ts +244 -0
  418. package/integrations/xhs-reader/url.ts +57 -0
  419. package/machineWsRunDispatch.ts +51 -6
  420. package/offlineMarxistsAgentCommand.ts +6 -4
  421. package/package.json +430 -3
  422. package/render/page/createPageAction.ts +183 -0
  423. package/render/page/docSlice.ts +468 -0
  424. package/render/page/types.ts +17 -0
  425. package/render/table/createTableAction.ts +270 -0
  426. package/render/table/deleteTableAction.ts +193 -0
  427. package/render/table/fetchAndCacheTableRows.ts +174 -0
  428. package/render/table/tableSlice.ts +1106 -0
  429. package/render/table/toolValueUtils.ts +363 -0
  430. package/render/table/types.ts +252 -0
  431. package/render/table/utils/tableSerialization.ts +50 -0
  432. package/server/handlers/agentRun/types.ts +104 -0
  433. package/share/action.ts +225 -0
  434. package/share/helpers.ts +302 -0
  435. package/share/keys.ts +243 -0
  436. package/share/publicSharePolicy.ts +27 -0
  437. package/share/shareSlice.ts +53 -0
  438. package/share/types.ts +100 -0
@@ -0,0 +1,627 @@
1
+ /**
2
+ * read_xhs_profile Tool
3
+ *
4
+ * Read-only tool for collecting XHS (Xiaohongshu) profile data:
5
+ * profile info, public notes, note details, and top-level comments.
6
+ *
7
+ * Desktop-first: uses Playwright persistent context for login state reuse.
8
+ * No write actions (no like/comment/follow/collect/post/delete).
9
+ * Cookies and xsecToken are never exposed in output.
10
+ * Conservative by default: reads the initially loaded profile state only.
11
+ * Extra scrolling, detail enrichment, and comments require explicit user intent.
12
+ * The tool clamps extended collection unless extendedCollectionConsent is true.
13
+ */
14
+
15
+ import { createXhsFailure } from "../../integrations/xhs-reader/types";
16
+ import type {
17
+ XhsReadResult,
18
+ XhsProfileCollection,
19
+ XhsCollectionStatus,
20
+ } from "../../integrations/xhs-reader/types";
21
+ import { parseXhsProfileUrl } from "../../integrations/xhs-reader/url";
22
+ import { getRequestConfig, ToolApiError } from "./toolApiClient";
23
+
24
+ export const readXhsProfileFunctionSchema = {
25
+ name: "read_xhs_profile",
26
+ description:
27
+ "读取小红书用户主页的公开信息。默认只读取页面初始加载出的资料和笔记列表,不自动翻页、不默认抓评论或批量详情。只有当用户明确要求更多笔记、评论或互动明细时,才应显式设置对应参数。默认通过桌面本地 Playwright 持久 profile 读取,不要求用户粘贴 cookie。",
28
+ parameters: {
29
+ type: "object",
30
+ properties: {
31
+ url: {
32
+ type: "string",
33
+ description:
34
+ "小红书用户主页 URL,例如 https://www.xiaohongshu.com/user/profile/5d2be8720000000010007556。",
35
+ },
36
+ maxScrollPages: {
37
+ type: "number",
38
+ description:
39
+ "最大滚动翻页数。默认 0,即只读取页面初始加载状态;只有用户明确要求更多笔记且 extendedCollectionConsent=true 时才设置为 1 或更高。",
40
+ default: 0,
41
+ },
42
+ includeComments: {
43
+ type: "boolean",
44
+ description:
45
+ "是否收集笔记的顶层评论。默认 false;只有用户明确要求评论且 extendedCollectionConsent=true 时才设为 true。",
46
+ default: false,
47
+ },
48
+ maxCommentPagesPerNote: {
49
+ type: "number",
50
+ description:
51
+ "每篇笔记最多收集几页评论(仅当 includeComments=true 时生效)。默认 1。",
52
+ default: 1,
53
+ },
54
+ minLikesForDetail: {
55
+ type: "number",
56
+ description:
57
+ "仅收集点赞数 >= 此值的笔记详情(可选)。只有 extendedCollectionConsent=true 时生效。",
58
+ },
59
+ minCommentsForCollect: {
60
+ type: "number",
61
+ description:
62
+ "仅收集评论数 >= 此值的笔记的评论(可选,仅当 includeComments=true 且 extendedCollectionConsent=true 时生效)。",
63
+ },
64
+ extendedCollectionConsent: {
65
+ type: "boolean",
66
+ description:
67
+ "扩展采集确认开关。只有用户在本轮明确要求更多笔记、翻页、评论或互动明细时才可设为 true;否则必须省略或为 false。",
68
+ default: false,
69
+ },
70
+ collectionMode: {
71
+ type: "string",
72
+ enum: ["conservative", "assisted"],
73
+ description:
74
+ "采集模式。默认 conservative;assisted 需要 extendedCollectionConsent=true。",
75
+ default: "conservative",
76
+ },
77
+ assistedAction: {
78
+ type: "string",
79
+ enum: ["snapshot", "read_more_notes", "read_comments"],
80
+ description:
81
+ "assisted 模式下的具体动作:snapshot 只读快照,read_more_notes 翻页读更多笔记,read_comments 读评论。",
82
+ default: "snapshot",
83
+ },
84
+ maxAssistedSteps: {
85
+ type: "number",
86
+ description:
87
+ "assisted 模式最大步数(1..3)。默认 1,用于约束滚动页数或评论翻页数。",
88
+ default: 1,
89
+ minimum: 1,
90
+ maximum: 3,
91
+ },
92
+ profileDir: {
93
+ type: "string",
94
+ description:
95
+ "桌面端本地 Playwright 持久 profile 目录,用于复用小红书登录态。不要传入用户日常 Chrome profile。默认使用专用缓存目录。",
96
+ },
97
+ headless: {
98
+ type: "boolean",
99
+ description:
100
+ "是否用 headless 模式启动浏览器。首次登录小红书时需设为 false 并配合 keepOpen。",
101
+ default: true,
102
+ },
103
+ keepOpen: {
104
+ type: "boolean",
105
+ description:
106
+ "调试时是否保持浏览器上下文打开(方便手动登录)。默认 false。",
107
+ default: false,
108
+ },
109
+ },
110
+ required: ["url"],
111
+ },
112
+ };
113
+
114
+ type ReadXhsProfileToolContext = {
115
+ reader?: (
116
+ options: ReadXhsProfileArgs,
117
+ ) => Promise<XhsReadResult<XhsProfileCollection>>;
118
+ };
119
+
120
+ export interface ReadXhsProfileArgs {
121
+ url: string;
122
+ maxScrollPages?: number;
123
+ includeComments?: boolean;
124
+ maxCommentPagesPerNote?: number;
125
+ minLikesForDetail?: number;
126
+ minCommentsForCollect?: number;
127
+ extendedCollectionConsent?: boolean;
128
+ profileDir?: string;
129
+ headless?: boolean;
130
+ keepOpen?: boolean;
131
+ collectionMode?: "conservative" | "assisted";
132
+ assistedAction?: "snapshot" | "read_more_notes" | "read_comments";
133
+ maxAssistedSteps?: number;
134
+ }
135
+
136
+ export function normalizeXhsProfileReadArgs(
137
+ args: ReadXhsProfileArgs,
138
+ ): ReadXhsProfileArgs {
139
+ const consent = args.extendedCollectionConsent === true;
140
+
141
+ if (!consent) {
142
+ // No consent → force conservative behavior
143
+ return {
144
+ ...args,
145
+ maxScrollPages: 0,
146
+ includeComments: false,
147
+ maxCommentPagesPerNote: 1,
148
+ minLikesForDetail: undefined,
149
+ minCommentsForCollect: undefined,
150
+ extendedCollectionConsent: false,
151
+ collectionMode: "conservative",
152
+ assistedAction: "snapshot",
153
+ maxAssistedSteps: 1,
154
+ };
155
+ }
156
+
157
+ // Consent granted → determine mode
158
+ const mode = args.collectionMode === "assisted" ? "assisted" : "conservative";
159
+ const action = args.assistedAction ?? "snapshot";
160
+ const steps = clamp(args.maxAssistedSteps ?? 1, 1, 3);
161
+
162
+ if (mode === "conservative") {
163
+ // Consent alone is not enough for extended collection. The model must
164
+ // explicitly select assisted mode so status labels match actual behavior.
165
+ return {
166
+ ...args,
167
+ maxScrollPages: 0,
168
+ includeComments: false,
169
+ maxCommentPagesPerNote: 1,
170
+ minLikesForDetail: undefined,
171
+ minCommentsForCollect: undefined,
172
+ extendedCollectionConsent: true,
173
+ collectionMode: "conservative",
174
+ assistedAction: "snapshot",
175
+ maxAssistedSteps: steps,
176
+ };
177
+ }
178
+
179
+ // Assisted mode with consent: clamp based on action
180
+ let maxScrollPages = args.maxScrollPages;
181
+ let includeComments = args.includeComments;
182
+ let maxCommentPagesPerNote = args.maxCommentPagesPerNote;
183
+
184
+ if (action === "read_more_notes") {
185
+ maxScrollPages = clamp(maxScrollPages ?? steps, 1, steps);
186
+ includeComments = false;
187
+ } else if (action === "read_comments") {
188
+ includeComments = true;
189
+ maxCommentPagesPerNote = clamp(maxCommentPagesPerNote ?? steps, 1, steps);
190
+ maxScrollPages = 0;
191
+ } else {
192
+ // snapshot: no scrolling, no comments
193
+ maxScrollPages = 0;
194
+ includeComments = false;
195
+ maxCommentPagesPerNote = 1;
196
+ }
197
+
198
+ return {
199
+ ...args,
200
+ maxScrollPages,
201
+ includeComments,
202
+ maxCommentPagesPerNote,
203
+ minLikesForDetail: args.minLikesForDetail,
204
+ minCommentsForCollect: args.minCommentsForCollect,
205
+ extendedCollectionConsent: true,
206
+ collectionMode: mode,
207
+ assistedAction: action,
208
+ maxAssistedSteps: steps,
209
+ };
210
+ }
211
+
212
+ function clamp(value: number, min: number, max: number): number {
213
+ return Math.min(Math.max(value, min), max);
214
+ }
215
+
216
+ function assertXhsProfileUrl(url: string) {
217
+ // Reuse parseXhsProfileUrl for validation
218
+ try {
219
+ parseXhsProfileUrl(url);
220
+ } catch {
221
+ throw new Error(
222
+ "read_xhs_profile 需要一个有效的小红书用户主页 URL(xiaohongshu.com/user/profile/<24位hexID>)。",
223
+ );
224
+ }
225
+ }
226
+
227
+ async function callLocalReadXhsProfileApi(
228
+ thunkApi: any,
229
+ body: object,
230
+ ): Promise<XhsReadResult<XhsProfileCollection>> {
231
+ const { currentServer, token } = getRequestConfig(thunkApi);
232
+ const browserOrigin = (globalThis as any).window?.location?.origin;
233
+ const baseUrl =
234
+ typeof browserOrigin === "string" && browserOrigin
235
+ ? browserOrigin
236
+ : currentServer.replace(/\/+$/, "");
237
+ const headers: Record<string, string> = {
238
+ "Content-Type": "application/json",
239
+ };
240
+ if (token) headers.Authorization = `Bearer ${token}`;
241
+
242
+ const response = await fetch(`${baseUrl}/api/read-xhs-profile`, {
243
+ method: "POST",
244
+ headers,
245
+ body: JSON.stringify(body),
246
+ });
247
+ const text = await response.text();
248
+ let data: any = null;
249
+ try {
250
+ data = text ? JSON.parse(text) : null;
251
+ } catch {
252
+ data = null;
253
+ }
254
+ if (!response.ok) {
255
+ throw new ToolApiError(
256
+ data?.error?.message ??
257
+ `read_xhs_profile API 请求失败,状态码: ${response.status}`,
258
+ {
259
+ status: response.status,
260
+ code: data?.error?.code,
261
+ details: data,
262
+ },
263
+ );
264
+ }
265
+ return data as XhsReadResult<XhsProfileCollection>;
266
+ }
267
+
268
+ async function callDesktopReadXhsProfileApi(
269
+ thunkApi: any,
270
+ body: object,
271
+ ): Promise<XhsReadResult<XhsProfileCollection>> {
272
+ const { token } = getRequestConfig(thunkApi);
273
+ const port = Number(process.env.NOLO_DESKTOP_SERVER_PORT ?? 3233);
274
+ const headers: Record<string, string> = {
275
+ "Content-Type": "application/json",
276
+ };
277
+ if (token) headers.Authorization = `Bearer ${token}`;
278
+
279
+ const response = await fetch(
280
+ `http://127.0.0.1:${port}/api/read-xhs-profile`,
281
+ {
282
+ method: "POST",
283
+ headers,
284
+ body: JSON.stringify(body),
285
+ },
286
+ );
287
+ const text = await response.text();
288
+ let data: any = null;
289
+ try {
290
+ data = text ? JSON.parse(text) : null;
291
+ } catch {
292
+ data = null;
293
+ }
294
+ if (!response.ok) {
295
+ throw new ToolApiError(
296
+ data?.error?.message ??
297
+ `desktop read_xhs_profile API 请求失败,状态码: ${response.status}`,
298
+ {
299
+ status: response.status,
300
+ code: data?.error?.code,
301
+ details: data,
302
+ },
303
+ );
304
+ }
305
+ return data as XhsReadResult<XhsProfileCollection>;
306
+ }
307
+
308
+ async function readWithDefaultBridge(
309
+ args: ReadXhsProfileArgs,
310
+ thunkApi?: any,
311
+ ): Promise<XhsReadResult<XhsProfileCollection>> {
312
+ if (process.env.PLATFORM === "web") {
313
+ if (thunkApi?.getState) {
314
+ return callLocalReadXhsProfileApi(thunkApi, args);
315
+ }
316
+
317
+ if (typeof window !== "undefined" && (window as any).__NOLO_DESKTOP__) {
318
+ try {
319
+ const res = await fetch("/api/read-xhs-profile", {
320
+ method: "POST",
321
+ headers: { "Content-Type": "application/json" },
322
+ body: JSON.stringify(args),
323
+ });
324
+ const data = await res.json().catch(() => null);
325
+ if (res.ok && data) {
326
+ return data as XhsReadResult<XhsProfileCollection>;
327
+ }
328
+ return createXhsFailure({
329
+ code: "network_error",
330
+ message: `desktop read_xhs_profile endpoint failed: HTTP ${res.status}`,
331
+ });
332
+ } catch (error) {
333
+ return createXhsFailure({
334
+ code: "network_error",
335
+ message:
336
+ error instanceof Error
337
+ ? error.message
338
+ : "desktop read_xhs_profile endpoint request failed",
339
+ });
340
+ }
341
+ }
342
+
343
+ return createXhsFailure({
344
+ code: "network_error",
345
+ message:
346
+ "read_xhs_profile 需要通过服务器或桌面本地 bridge 执行,不能在普通浏览器 bundle 内直接启动 Playwright。",
347
+ });
348
+ }
349
+
350
+ if (process.env.NOLO_DESKTOP === "1" && thunkApi?.getState) {
351
+ return callDesktopReadXhsProfileApi(thunkApi, args);
352
+ }
353
+
354
+ // Server-side: use bridge directly
355
+ const importBridge = new Function("specifier", "return import(specifier)") as <
356
+ T = any,
357
+ >(
358
+ specifier: string,
359
+ ) => Promise<T>;
360
+ const { readXhsProfileWithBridge } = await importBridge<{
361
+ readXhsProfileWithBridge: (
362
+ options: ReadXhsProfileArgs,
363
+ ) => Promise<XhsReadResult<XhsProfileCollection>>;
364
+ }>("../../integrations/xhs-reader/bridge/readXhsProfileWithBridge.ts");
365
+ return readXhsProfileWithBridge(args);
366
+ }
367
+
368
+ function formatDisplay(result: XhsReadResult<XhsProfileCollection>) {
369
+ if (!result.ok) {
370
+ const hints: string[] = [];
371
+ if (result.code === "login_required") {
372
+ hints.push(
373
+ "需要先登录小红书。请在桌面端用 headless=false + keepOpen=true 运行一次,手动完成登录后再次调用即可。",
374
+ );
375
+ } else if (result.code === "blocked") {
376
+ hints.push(
377
+ "页面被验证码或安全检查拦截。请稍后重试或在桌面端手动处理验证后重试。",
378
+ );
379
+ } else if (result.code === "empty_profile_state") {
380
+ hints.push(
381
+ "页面加载但未获取到笔记数据。建议:确认该用户有公开笔记;用本地持久 profile 重试;增加 timeoutMs。",
382
+ );
383
+ }
384
+ return [
385
+ `读取小红书用户主页失败:${result.message}`,
386
+ `失败代码:${result.code}`,
387
+ "",
388
+ "可能的解决步骤:",
389
+ "- 确认 URL 是有效的小红书用户主页链接",
390
+ "- 如果是登录问题,请用 headless=false + keepOpen=true 手动登录一次",
391
+ "- 如果是服务端(headless)环境,确保有有效的已登录 profile 目录",
392
+ "- 检查 Playwright chromium 是否已安装",
393
+ ...hints,
394
+ ]
395
+ .filter(Boolean)
396
+ .join("\n");
397
+ }
398
+
399
+ const { profile, notes, noteDetails, analysis } = result.data;
400
+
401
+ const parts: string[] = [];
402
+
403
+ // Profile summary
404
+ parts.push(`小红书用户: ${profile.nickname || "未命名"}`);
405
+ if (profile.redId) parts.push(`小红书号: ${profile.redId}`);
406
+ if (profile.ipLocation) parts.push(`IP 属地: ${profile.ipLocation}`);
407
+ if (profile.desc) parts.push(`简介: ${profile.desc}`);
408
+
409
+ // Interaction counts
410
+ const ic = profile.interactionCounts;
411
+ if (ic) {
412
+ const counts: string[] = [];
413
+ if (ic.follows != null) counts.push(`关注 ${ic.follows}`);
414
+ if (ic.fans != null) counts.push(`粉丝 ${ic.fans}`);
415
+ if (ic.likesAndCollects != null)
416
+ counts.push(`获赞与收藏 ${ic.likesAndCollects}`);
417
+ if (counts.length > 0) parts.push(`互动: ${counts.join(" / ")}`);
418
+ }
419
+
420
+ parts.push("");
421
+
422
+ // Notes summary
423
+ parts.push(`笔记数量: ${analysis.totalNotes}`);
424
+ if (noteDetails.length > 0) {
425
+ parts.push(`已获取详情: ${noteDetails.length} 篇`);
426
+ }
427
+
428
+ // Top notes
429
+ if (analysis.highestLikedNote) {
430
+ const n = analysis.highestLikedNote;
431
+ parts.push(
432
+ `最高点赞: ${n.title ?? n.noteId}(${n.count} 赞)`,
433
+ );
434
+ }
435
+ if (analysis.highestCommentedNote) {
436
+ const n = analysis.highestCommentedNote;
437
+ parts.push(
438
+ `最高评论: ${n.title ?? n.noteId}(${n.count} 评论)`,
439
+ );
440
+ }
441
+ if (analysis.highestCollectedNote) {
442
+ const n = analysis.highestCollectedNote;
443
+ parts.push(
444
+ `最高收藏: ${n.title ?? n.noteId}(${n.count} 收藏)`,
445
+ );
446
+ }
447
+ if (analysis.highestSharedNote) {
448
+ const n = analysis.highestSharedNote;
449
+ parts.push(
450
+ `最高分享: ${n.title ?? n.noteId}(${n.count} 分享)`,
451
+ );
452
+ }
453
+
454
+ // Comment buckets
455
+ if (analysis.commentBuckets.length > 0) {
456
+ parts.push("");
457
+ parts.push("评论主题分布:");
458
+ for (const bucket of analysis.commentBuckets) {
459
+ parts.push(` - ${bucket.label}: ${bucket.count} 条`);
460
+ }
461
+ }
462
+
463
+ // Diagnostic info (when profile succeeded but notes collection had issues)
464
+ if (result.data.diagnostic) {
465
+ const diag = result.data.diagnostic;
466
+ parts.push("");
467
+ parts.push(`⚠ 采集诊断:${diag.code}`);
468
+ parts.push(` ${diag.message}`);
469
+ if (diag.loginDetected) parts.push(" 检测到登录提示");
470
+ }
471
+
472
+ // Collection status display
473
+ if (result.data.collectionStatus) {
474
+ const cs = result.data.collectionStatus;
475
+ parts.push("");
476
+ const modeLabel = cs.mode === "assisted" ? "辅助采集" : "保守模式";
477
+ const actionLabels: Record<string, string> = {
478
+ snapshot: "快照",
479
+ read_more_notes: "读取更多笔记",
480
+ read_comments: "读取评论",
481
+ };
482
+ parts.push(`采集模式: ${modeLabel}`);
483
+ parts.push(`采集动作: ${actionLabels[cs.action] ?? cs.action}`);
484
+ if (cs.mode === "assisted") {
485
+ parts.push(
486
+ `步数: ${cs.assistedStepCount}/${cs.limits.maxAssistedSteps}`,
487
+ );
488
+ }
489
+ if (cs.nextSuggestedAction) {
490
+ parts.push(
491
+ `建议: ${cs.nextSuggestedAction.label} - ${cs.nextSuggestedAction.reason}`,
492
+ );
493
+ }
494
+ }
495
+
496
+ return parts.join("\n");
497
+ }
498
+
499
+ export async function readXhsProfileFunc(
500
+ args: ReadXhsProfileArgs,
501
+ thunkApi: any,
502
+ context: ReadXhsProfileToolContext = {},
503
+ ): Promise<{
504
+ rawData: XhsReadResult<XhsProfileCollection>;
505
+ displayData: string;
506
+ }> {
507
+ const url = String(args?.url ?? "").trim();
508
+ assertXhsProfileUrl(url);
509
+
510
+ const readerArgs: ReadXhsProfileArgs = normalizeXhsProfileReadArgs({
511
+ url,
512
+ maxScrollPages: args.maxScrollPages,
513
+ includeComments: args.includeComments,
514
+ maxCommentPagesPerNote: args.maxCommentPagesPerNote,
515
+ minLikesForDetail: args.minLikesForDetail,
516
+ minCommentsForCollect: args.minCommentsForCollect,
517
+ extendedCollectionConsent: args.extendedCollectionConsent,
518
+ profileDir: args.profileDir?.trim() || undefined,
519
+ headless: args.headless,
520
+ keepOpen: args.keepOpen,
521
+ collectionMode: args.collectionMode,
522
+ assistedAction: args.assistedAction,
523
+ maxAssistedSteps: args.maxAssistedSteps,
524
+ });
525
+
526
+ const rawData =
527
+ (await context.reader?.(readerArgs)) ??
528
+ (await readWithDefaultBridge(readerArgs, thunkApi));
529
+
530
+ // Build and attach collectionStatus
531
+ if (rawData.ok) {
532
+ rawData.data.collectionStatus = buildCollectionStatus(
533
+ readerArgs,
534
+ rawData.data,
535
+ );
536
+ }
537
+
538
+ return {
539
+ rawData,
540
+ displayData: formatDisplay(rawData),
541
+ };
542
+ }
543
+
544
+ function buildCollectionStatus(
545
+ args: ReadXhsProfileArgs,
546
+ data: XhsProfileCollection,
547
+ ): XhsCollectionStatus {
548
+ const mode = args.collectionMode ?? "conservative";
549
+ const action = args.assistedAction ?? "snapshot";
550
+ const consent = args.extendedCollectionConsent === true;
551
+ const steps = args.maxAssistedSteps ?? 1;
552
+
553
+ const status: XhsCollectionStatus = {
554
+ mode,
555
+ action,
556
+ extendedCollectionConsent: consent,
557
+ assistedStepCount: consent && mode === "assisted" ? steps : 0,
558
+ limits: {
559
+ maxAssistedSteps: steps,
560
+ maxScrollPages: args.maxScrollPages ?? 0,
561
+ maxCommentPagesPerNote: args.maxCommentPagesPerNote ?? 1,
562
+ includeComments: args.includeComments ?? false,
563
+ },
564
+ };
565
+
566
+ // Determine next suggested action
567
+ status.nextSuggestedAction = computeNextSuggestedAction(args, data);
568
+
569
+ return status;
570
+ }
571
+
572
+ function computeNextSuggestedAction(
573
+ args: ReadXhsProfileArgs,
574
+ data: XhsProfileCollection,
575
+ ): XhsCollectionStatus["nextSuggestedAction"] {
576
+ const { diagnostic, notes, analysis, commentsByNote } = data;
577
+ const action = args.assistedAction ?? "snapshot";
578
+
579
+ // Login wall or empty state → suggest manual login
580
+ if (diagnostic?.loginDetected || diagnostic?.code === "login_required") {
581
+ return {
582
+ action: "manual_login",
583
+ label: "手动登录",
584
+ reason: "检测到登录提示,请先手动登录小红书",
585
+ };
586
+ }
587
+
588
+ // Few notes and was a snapshot → suggest reading more notes
589
+ if (notes.length < 5 && action === "snapshot") {
590
+ return {
591
+ action: "read_more_notes",
592
+ label: "读取更多笔记",
593
+ reason: `当前仅读取 ${notes.length} 篇笔记,可尝试翻页获取更多`,
594
+ };
595
+ }
596
+
597
+ // Notes with high comment counts but no comments collected
598
+ const hasHighCommentNotes = notes.some((n) => {
599
+ // Check noteDetails for comment counts
600
+ const detail = data.noteDetails.find((d) => d.noteId === n.noteId);
601
+ return detail && detail.metrics.commentCount > 5;
602
+ });
603
+ const hasComments = Object.keys(commentsByNote).length > 0;
604
+
605
+ if (
606
+ (action === "snapshot" || action === "read_more_notes") &&
607
+ hasHighCommentNotes &&
608
+ !hasComments
609
+ ) {
610
+ return {
611
+ action: "read_comments",
612
+ label: "读取评论",
613
+ reason: "部分笔记评论较多,可以读取评论内容",
614
+ };
615
+ }
616
+
617
+ // Analysis exists and has data → suggest saving to table
618
+ if (analysis.totalNotes > 0 && (action === "read_comments" || action === "read_more_notes")) {
619
+ return {
620
+ action: "save_to_table",
621
+ label: "保存到表格",
622
+ reason: "已采集到数据,可保存到表格以便分析",
623
+ };
624
+ }
625
+
626
+ return undefined;
627
+ }
@@ -0,0 +1,84 @@
1
+ import { selectCurrentSpaceId } from "../../create/space/spaceSlice";
2
+ import { callToolApi } from "./toolApiClient";
3
+ import type { RememberMemoryScope } from "../memory/remember";
4
+ import type { MemoryKind } from "../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
+ }