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
@@ -4,6 +4,7 @@ import { join } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
5
 
6
6
  import { runLocalAgentTurn } from "../agent-runtime/localLoop";
7
+ import { MIMO_MONTH_AGENT_KEY } from "../agentAliases";
7
8
  import { createCliLocalRuntimeAdapter } from "./localRuntimeAdapter";
8
9
 
9
10
  describe("CLI local runtime adapter", () => {
@@ -13,23 +14,183 @@ describe("CLI local runtime adapter", () => {
13
14
  "writeFile",
14
15
  "editFile",
15
16
  "searchFiles",
17
+ "execShell",
16
18
  ];
17
19
  const LEGACY_WRITE_LOCAL_CODING_TOOL_NAMES = [
18
- "writeWorkspaceFile",
19
20
  "listFiles",
20
21
  "readFile",
22
+ "writeFile",
21
23
  "editFile",
22
24
  "searchFiles",
25
+ "execShell",
23
26
  ];
24
27
  const SHELL_LOCAL_CODING_TOOL_NAMES = [
25
28
  ...DEFAULT_LOCAL_CODING_TOOL_NAMES,
26
- "execShell",
29
+ ];
30
+ const DEFAULT_PRIVATE_NOLO_WORKSPACE_TOOL_NAMES = [
31
+ "listDialogs",
32
+ "readDialog",
33
+ "listAgents",
34
+ "readAgent",
35
+ "listSpaces",
36
+ "readSpace",
37
+ "readDoc",
38
+ "readSkillDoc",
39
+ "queryTableRows",
40
+ "cliWhoami",
41
+ "cliDoctor",
42
+ ];
43
+ const DEFAULT_PRIVATE_LOCAL_TOOL_NAMES = [
44
+ ...DEFAULT_LOCAL_CODING_TOOL_NAMES,
45
+ ...DEFAULT_PRIVATE_NOLO_WORKSPACE_TOOL_NAMES,
27
46
  ];
28
47
 
29
48
  function toolNamesFromRequest(request: any) {
30
49
  return request?.body?.tools?.map((tool: any) => tool.function.name) ?? [];
31
50
  }
32
51
 
52
+ test("runs cli-provider agents through the local CLI executor instead of OpenAI-compatible direct mode", async () => {
53
+ const cliExecutions: Array<{ provider: string; prompt: string; options: any }> = [];
54
+ const adapter = createCliLocalRuntimeAdapter({
55
+ env: {
56
+ NOLO_LOCAL_USER_ID: "user-1",
57
+ OPENAI_API_KEY: "sk-should-not-be-used",
58
+ },
59
+ db: {
60
+ get: async (key) => {
61
+ if (key !== "agent-user-1-frontend") throw new Error(`not found: ${key}`);
62
+ return {
63
+ dbKey: "agent-user-1-frontend",
64
+ id: "frontend",
65
+ name: "Frontend",
66
+ prompt: "You are the frontend implementer.",
67
+ apiSource: "cli",
68
+ cliProvider: "agy",
69
+ model: "gemini-3.1-pro",
70
+ };
71
+ },
72
+ put: async () => {},
73
+ batch: async () => {},
74
+ iterator: () => (async function* () {})(),
75
+ },
76
+ cwd: "/repo/worktree",
77
+ now: () => 1710000000000,
78
+ createId: () => "01CLI",
79
+ fetchImpl: async () => {
80
+ throw new Error("OpenAI-compatible fetch should not be used for cli providers");
81
+ },
82
+ executeCli: async (provider, prompt, options) => {
83
+ cliExecutions.push({ provider, prompt, options });
84
+ return { text: "cli ok", raw: "cli ok", elapsed: 1 };
85
+ },
86
+ } as any);
87
+
88
+ const result = await runLocalAgentTurn({
89
+ adapter,
90
+ agentRef: "frontend",
91
+ input: "add tooltip",
92
+ });
93
+
94
+ expect(result).toMatchObject({
95
+ content: "cli ok",
96
+ model: "gemini-3.1-pro",
97
+ });
98
+ expect(cliExecutions).toHaveLength(1);
99
+ expect(cliExecutions[0]).toMatchObject({
100
+ provider: "agy",
101
+ options: {
102
+ model: "gemini-3.1-pro",
103
+ cwd: "/repo/worktree",
104
+ yolo: true,
105
+ },
106
+ });
107
+ expect(cliExecutions[0].prompt).toContain("You are the frontend implementer.");
108
+ expect(cliExecutions[0].prompt).toContain("add tooltip");
109
+ });
110
+
111
+ test("fails cli-provider local runs clearly when the requested local CLI is unavailable", async () => {
112
+ const adapter = createCliLocalRuntimeAdapter({
113
+ env: {
114
+ NOLO_LOCAL_USER_ID: "user-1",
115
+ OPENAI_API_KEY: "sk-should-not-be-used",
116
+ },
117
+ db: {
118
+ get: async (key) => {
119
+ if (key !== "agent-user-1-frontend") throw new Error(`not found: ${key}`);
120
+ return {
121
+ dbKey: "agent-user-1-frontend",
122
+ id: "frontend",
123
+ name: "Frontend",
124
+ prompt: "You are the frontend implementer.",
125
+ apiSource: "cli",
126
+ cliProvider: "agy",
127
+ };
128
+ },
129
+ put: async () => {},
130
+ batch: async () => {},
131
+ iterator: () => (async function* () {})(),
132
+ },
133
+ fetchImpl: async () => {
134
+ throw new Error("OpenAI-compatible fetch should not be used for cli providers");
135
+ },
136
+ executeCli: async () => {
137
+ throw new Error("agy: command not found");
138
+ },
139
+ } as any);
140
+
141
+ await expect(runLocalAgentTurn({
142
+ adapter,
143
+ agentRef: "frontend",
144
+ input: "add tooltip",
145
+ })).rejects.toThrow("Local CLI provider \"agy\" is unavailable");
146
+ });
147
+
148
+ test("passes cli-provider image inputs to the CLI executor instead of rejecting", async () => {
149
+ let cliCalledWith: any = null;
150
+ const adapter = createCliLocalRuntimeAdapter({
151
+ env: {
152
+ NOLO_LOCAL_USER_ID: "user-1",
153
+ },
154
+ db: {
155
+ get: async (key) => {
156
+ if (key !== "agent-user-1-frontend") throw new Error(`not found: ${key}`);
157
+ return {
158
+ dbKey: "agent-user-1-frontend",
159
+ id: "frontend",
160
+ name: "Frontend",
161
+ prompt: "You are the frontend implementer.",
162
+ apiSource: "cli",
163
+ cliProvider: "agy",
164
+ };
165
+ },
166
+ put: async () => {},
167
+ batch: async () => {},
168
+ iterator: () => (async function* () {})(),
169
+ },
170
+ executeCli: async (provider, prompt, options) => {
171
+ cliCalledWith = { provider, prompt, options };
172
+ return { text: "image handled", raw: "", elapsed: 1 };
173
+ },
174
+ } as any);
175
+
176
+ const result = await runLocalAgentTurn({
177
+ adapter,
178
+ agentRef: "frontend",
179
+ input: [
180
+ { type: "text", text: "look at this screenshot" },
181
+ { type: "image_url", image_url: { url: "https://example.com/screen.png" } },
182
+ ],
183
+ });
184
+
185
+ expect(result.content).toBe("image handled");
186
+ expect(cliCalledWith).not.toBeNull();
187
+ expect(cliCalledWith.provider).toBe("agy");
188
+ expect(cliCalledWith.prompt).toContain("look at this screenshot");
189
+ expect(cliCalledWith.options.imageInputs).toEqual([
190
+ { source: "https://example.com/screen.png" },
191
+ ]);
192
+ });
193
+
33
194
  test("loads agent/history from LevelDB and saves dialog/message records back to LevelDB", async () => {
34
195
  const requests: Array<{ url: string; body: any; auth: string | null }> = [];
35
196
  const store = new Map<string, any>([
@@ -122,7 +283,7 @@ describe("CLI local runtime adapter", () => {
122
283
  stream: false,
123
284
  },
124
285
  });
125
- expect(toolNamesFromRequest(requests[0])).toEqual(DEFAULT_LOCAL_CODING_TOOL_NAMES);
286
+ expect(toolNamesFromRequest(requests[0])).toEqual(DEFAULT_PRIVATE_LOCAL_TOOL_NAMES);
126
287
  expect(batchOps.map((op) => op.key)).toEqual([
127
288
  "dialog-user-1-dialog-existing",
128
289
  "dialog-dialog-existing-msg-1710000000000-001",
@@ -354,7 +515,7 @@ describe("CLI local runtime adapter", () => {
354
515
  reasoning_effort: "medium",
355
516
  },
356
517
  });
357
- expect(toolNamesFromRequest(requests[0])).toEqual(DEFAULT_LOCAL_CODING_TOOL_NAMES);
518
+ expect(toolNamesFromRequest(requests[0])).toEqual(DEFAULT_PRIVATE_LOCAL_TOOL_NAMES);
358
519
  });
359
520
 
360
521
  test("aborts stalled custom provider requests when timeoutMs is provided", async () => {
@@ -374,11 +535,8 @@ describe("CLI local runtime adapter", () => {
374
535
  env: {
375
536
  NOLO_LOCAL_USER_ID: "user-1",
376
537
  },
377
- db: {
378
- get: async (key) => {
379
- if (!store.has(key)) throw new Error(`not found: ${key}`);
380
- return store.get(key);
381
- },
538
+ store: {
539
+ read: async (key) => store.get(key) ?? null,
382
540
  put: async (key, value) => {
383
541
  store.set(key, value);
384
542
  },
@@ -473,7 +631,7 @@ describe("CLI local runtime adapter", () => {
473
631
  stream: false,
474
632
  },
475
633
  });
476
- expect(toolNamesFromRequest(loopbackRequests[0])).toEqual(DEFAULT_LOCAL_CODING_TOOL_NAMES);
634
+ expect(toolNamesFromRequest(loopbackRequests[0])).toEqual(DEFAULT_PRIVATE_LOCAL_TOOL_NAMES);
477
635
  });
478
636
 
479
637
  test("uses the Nolo chat proxy when local provider keys are absent", async () => {
@@ -485,7 +643,7 @@ describe("CLI local runtime adapter", () => {
485
643
  prompt: "Fix UI.",
486
644
  model: "accounts/fireworks/models/kimi-k2p6",
487
645
  provider: "fireworks",
488
- tools: ["writeWorkspaceFile"],
646
+ tools: ["writeFile"],
489
647
  }],
490
648
  ]);
491
649
  const adapter = createCliLocalRuntimeAdapter({
@@ -546,7 +704,10 @@ describe("CLI local runtime adapter", () => {
546
704
  agentKey: "agent-user-1-frontend",
547
705
  },
548
706
  });
549
- expect(toolNamesFromRequest(requests[0])).toEqual(LEGACY_WRITE_LOCAL_CODING_TOOL_NAMES);
707
+ expect(toolNamesFromRequest(requests[0])).toEqual([
708
+ ...LEGACY_WRITE_LOCAL_CODING_TOOL_NAMES,
709
+ ...DEFAULT_PRIVATE_NOLO_WORKSPACE_TOOL_NAMES,
710
+ ]);
550
711
  });
551
712
 
552
713
  test("uses the Nolo chat proxy for platform agents even when direct provider env exists", async () => {
@@ -560,7 +721,7 @@ describe("CLI local runtime adapter", () => {
560
721
  provider: "fireworks",
561
722
  apiSource: "platform",
562
723
  useServerProxy: true,
563
- tools: ["readWorkspaceFile"],
724
+ tools: ["readFile"],
564
725
  }],
565
726
  ]);
566
727
  const adapter = createCliLocalRuntimeAdapter({
@@ -728,7 +889,7 @@ describe("CLI local runtime adapter", () => {
728
889
 
729
890
  expect(result.content).toBe("platform longer retry ok");
730
891
  expect(attempts).toBe(6);
731
- expect(retryDelays.length).toBe(5);
892
+ expect(retryDelays.length).toBeGreaterThanOrEqual(3);
732
893
  expect(retryDelays[0]).toBeGreaterThan(0);
733
894
  });
734
895
 
@@ -745,7 +906,6 @@ describe("CLI local runtime adapter", () => {
745
906
  env: {
746
907
  NOLO_LOCAL_USER_ID: "user-1",
747
908
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
748
- NOLO_LOCAL_SHELL_MODE: "worktree",
749
909
  },
750
910
  db: {
751
911
  get: async (key) => {
@@ -851,7 +1011,7 @@ describe("CLI local runtime adapter", () => {
851
1011
  prompt: "Read narrowly",
852
1012
  model: "gpt-4.1-mini",
853
1013
  provider: "openai-compatible",
854
- tools: ["readWorkspaceFile"],
1014
+ tools: ["readFile"],
855
1015
  }],
856
1016
  ]);
857
1017
  let requestCount = 0;
@@ -860,7 +1020,7 @@ describe("CLI local runtime adapter", () => {
860
1020
  NOLO_LOCAL_USER_ID: "user-1",
861
1021
  NOLO_LOCAL_OPENAI_BASE_URL: "https://llm.example/v1",
862
1022
  NOLO_LOCAL_OPENAI_API_KEY: "sk-test",
863
- NOLO_LOCAL_TOOL_BUDGETS: "readWorkspaceFile=1",
1023
+ NOLO_LOCAL_TOOL_BUDGETS: "readFile=1",
864
1024
  },
865
1025
  store: {
866
1026
  read: async (key) => {
@@ -881,7 +1041,7 @@ describe("CLI local runtime adapter", () => {
881
1041
  now: () => 1710000000000,
882
1042
  createId: () => "01BUDGET",
883
1043
  localToolExecutors: {
884
- readWorkspaceFile: async () => ({ content: "file content" }),
1044
+ readFile: async () => ({ content: "file content" }),
885
1045
  },
886
1046
  fetchImpl: async (_url, init) => {
887
1047
  requestCount += 1;
@@ -898,7 +1058,7 @@ describe("CLI local runtime adapter", () => {
898
1058
  id: `call-read-${requestCount}`,
899
1059
  type: "function",
900
1060
  function: {
901
- name: "readWorkspaceFile",
1061
+ name: "readFile",
902
1062
  arguments: JSON.stringify({ path: "file.ts" }),
903
1063
  },
904
1064
  }],
@@ -912,7 +1072,6 @@ describe("CLI local runtime adapter", () => {
912
1072
  adapter,
913
1073
  agentRef: "agent-user-1-reader",
914
1074
  input: "inspect",
915
- maxToolRounds: 3,
916
1075
  });
917
1076
 
918
1077
  expect(result.content).toBe("budget handled");
@@ -1043,7 +1202,7 @@ describe("CLI local runtime adapter", () => {
1043
1202
  });
1044
1203
  });
1045
1204
 
1046
- test("requires explicit shell mode for registered execShell", async () => {
1205
+ test("allows registered execShell by default", async () => {
1047
1206
  const adapter = createCliLocalRuntimeAdapter({
1048
1207
  env: {},
1049
1208
  localToolExecutors: {
@@ -1052,11 +1211,13 @@ describe("CLI local runtime adapter", () => {
1052
1211
  fetchImpl: async () => Response.json({}),
1053
1212
  });
1054
1213
 
1055
- await expect(adapter.executeTool({
1214
+ const result = await adapter.executeTool({
1056
1215
  id: "call-1",
1057
1216
  name: "execShell",
1058
1217
  arguments: "{\"cmd\":\"pwd\"}",
1059
- })).rejects.toThrow("execShell requires NOLO_LOCAL_SHELL_MODE=worktree");
1218
+ });
1219
+
1220
+ expect(result.content).toContain("\"cmd\":\"pwd\"");
1060
1221
  });
1061
1222
 
1062
1223
  test("executes explicitly allowed registered local tools declared by the agent", async () => {
@@ -1098,13 +1259,12 @@ describe("CLI local runtime adapter", () => {
1098
1259
  expect(result.content).toContain("README.md");
1099
1260
  });
1100
1261
 
1101
- test("advertises execShell to OpenAI-compatible providers only in explicit shell mode", async () => {
1262
+ test("advertises execShell to OpenAI-compatible providers by default", async () => {
1102
1263
  const requests: Array<{ body: any }> = [];
1103
1264
  const adapter = createCliLocalRuntimeAdapter({
1104
1265
  env: {
1105
1266
  OPENAI_API_KEY: "sk-local",
1106
1267
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1107
- NOLO_LOCAL_SHELL_MODE: "worktree",
1108
1268
  },
1109
1269
  db: {
1110
1270
  get: async () => ({
@@ -1130,6 +1290,61 @@ describe("CLI local runtime adapter", () => {
1130
1290
  input: "pwd",
1131
1291
  });
1132
1292
 
1293
+ expect(toolNamesFromRequest(requests[0])).toEqual([
1294
+ ...SHELL_LOCAL_CODING_TOOL_NAMES,
1295
+ ...DEFAULT_PRIVATE_NOLO_WORKSPACE_TOOL_NAMES,
1296
+ ]);
1297
+ });
1298
+
1299
+ test("keeps monthly Mimo local model tools to the compact coding surface", async () => {
1300
+ const requests: Array<{ body: any }> = [];
1301
+ const adapter = createCliLocalRuntimeAdapter({
1302
+ env: {
1303
+ OPENAI_API_KEY: "sk-local",
1304
+ NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1305
+ },
1306
+ db: {
1307
+ get: async () => ({
1308
+ dbKey: MIMO_MONTH_AGENT_KEY,
1309
+ prompt: "Use local coding tools.",
1310
+ model: "mimo-v2.5-pro",
1311
+ provider: "custom",
1312
+ tools: [
1313
+ "read",
1314
+ "searchDialogMessages",
1315
+ "searchFiles",
1316
+ "codeSearch",
1317
+ "listFiles",
1318
+ "readFile",
1319
+ "writeFile",
1320
+ "editFile",
1321
+ "searchFiles",
1322
+ "legacyLocalAlias",
1323
+ "applyPatch",
1324
+ "execShell",
1325
+ "checkEnv",
1326
+ "queryTableRows",
1327
+ "taskRun",
1328
+ ],
1329
+ }),
1330
+ put: async () => {},
1331
+ batch: async () => {},
1332
+ iterator: () => (async function* () {})(),
1333
+ },
1334
+ fetchImpl: async (_url, init) => {
1335
+ requests.push({ body: JSON.parse(String(init?.body)) });
1336
+ return Response.json({
1337
+ choices: [{ message: { content: "done" } }],
1338
+ });
1339
+ },
1340
+ });
1341
+
1342
+ await runLocalAgentTurn({
1343
+ adapter,
1344
+ agentRef: MIMO_MONTH_AGENT_KEY,
1345
+ input: "inspect cwd",
1346
+ });
1347
+
1133
1348
  expect(toolNamesFromRequest(requests[0])).toEqual(SHELL_LOCAL_CODING_TOOL_NAMES);
1134
1349
  });
1135
1350
 
@@ -1251,6 +1466,141 @@ describe("CLI local runtime adapter", () => {
1251
1466
  expect(result.metadata).toMatchObject({ serverPlatformTool: true });
1252
1467
  });
1253
1468
 
1469
+ test("exposes declared server table write tools in local runtime requests", async () => {
1470
+ const requests: Array<{ body: any }> = [];
1471
+ const adapter = createCliLocalRuntimeAdapter({
1472
+ env: {
1473
+ OPENAI_API_KEY: "sk-local",
1474
+ NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1475
+ },
1476
+ db: {
1477
+ get: async () => ({
1478
+ dbKey: "agent-local-table",
1479
+ prompt: "Use table tools.",
1480
+ model: "gpt-4.1-mini",
1481
+ toolNames: ["createTable", "addTableRow", "addTableRows"],
1482
+ }),
1483
+ put: async () => {},
1484
+ batch: async () => {},
1485
+ iterator: () => (async function* () {})(),
1486
+ },
1487
+ fetchImpl: async (_url, init) => {
1488
+ requests.push({ body: JSON.parse(String(init?.body)) });
1489
+ return Response.json({
1490
+ choices: [{ message: { content: "done" } }],
1491
+ });
1492
+ },
1493
+ });
1494
+
1495
+ await runLocalAgentTurn({
1496
+ adapter,
1497
+ agentRef: "table",
1498
+ input: "采集并写入 table",
1499
+ });
1500
+
1501
+ const toolNames = toolNamesFromRequest(requests[0]);
1502
+ expect(toolNames).toContain("createTable");
1503
+ expect(toolNames).toContain("addTableRow");
1504
+ expect(toolNames).toContain("addTableRows");
1505
+ });
1506
+
1507
+ test("executes declared createTable through the server table bridge when capture is explicit", async () => {
1508
+ const requests: Array<{ url: string; auth: string | null; body: any }> = [];
1509
+ const adapter = createCliLocalRuntimeAdapter({
1510
+ env: {
1511
+ NOLO_SERVER: "https://us.nolo.chat",
1512
+ AUTH_TOKEN: "token-1",
1513
+ },
1514
+ db: {
1515
+ get: async () => ({
1516
+ dbKey: "agent-local-table-write",
1517
+ toolNames: ["createTable"],
1518
+ }),
1519
+ put: async () => {},
1520
+ batch: async () => {},
1521
+ iterator: () => (async function* () {})(),
1522
+ },
1523
+ fetchImpl: async (url, init) => {
1524
+ requests.push({
1525
+ url: String(url),
1526
+ auth: new Headers(init?.headers).get("authorization"),
1527
+ body: JSON.parse(String(init?.body)),
1528
+ });
1529
+ return Response.json({
1530
+ ok: true,
1531
+ tenantId: "user-1",
1532
+ tableId: "table-1",
1533
+ });
1534
+ },
1535
+ });
1536
+
1537
+ await adapter.loadAgentConfig("table-write");
1538
+ const result = await adapter.executeTool({
1539
+ id: "call-create-table",
1540
+ name: "createTable",
1541
+ userInput: "采集这个用户并写入 table",
1542
+ arguments: JSON.stringify({
1543
+ title: "XHS profile",
1544
+ columns: [{ name: "nickname" }],
1545
+ }),
1546
+ });
1547
+
1548
+ expect(requests).toEqual([
1549
+ {
1550
+ url: "https://us.nolo.chat/api/table/create",
1551
+ auth: "Bearer token-1",
1552
+ body: {
1553
+ title: "XHS profile",
1554
+ columns: [{ name: "nickname" }],
1555
+ },
1556
+ },
1557
+ ]);
1558
+ expect(result.content).toContain("\"tableId\":\"table-1\"");
1559
+ expect(result.metadata).toMatchObject({
1560
+ serverPlatformTool: true,
1561
+ tableWrite: true,
1562
+ });
1563
+ });
1564
+
1565
+ test("blocks local table writes when the current user request is not explicit capture", async () => {
1566
+ const adapter = createCliLocalRuntimeAdapter({
1567
+ env: {
1568
+ NOLO_SERVER: "https://us.nolo.chat",
1569
+ AUTH_TOKEN: "token-1",
1570
+ },
1571
+ db: {
1572
+ get: async () => ({
1573
+ dbKey: "agent-local-table-blocked",
1574
+ toolNames: ["createTable"],
1575
+ }),
1576
+ put: async () => {},
1577
+ batch: async () => {},
1578
+ iterator: () => (async function* () {})(),
1579
+ },
1580
+ fetchImpl: async () => {
1581
+ throw new Error("blocked createTable must not reach the server");
1582
+ },
1583
+ });
1584
+
1585
+ await adapter.loadAgentConfig("table-blocked");
1586
+ const result = await adapter.executeTool({
1587
+ id: "call-create-table-blocked",
1588
+ name: "createTable",
1589
+ userInput: "总结这个用户画像",
1590
+ arguments: JSON.stringify({
1591
+ title: "XHS profile",
1592
+ columns: [{ name: "nickname" }],
1593
+ }),
1594
+ });
1595
+
1596
+ const parsed = JSON.parse(result.content);
1597
+ expect(parsed.error).toBe("knowledge_capture_requires_confirmation");
1598
+ expect(result.metadata).toMatchObject({
1599
+ serverPlatformTool: true,
1600
+ tableWriteBlocked: true,
1601
+ });
1602
+ });
1603
+
1254
1604
  test("adds typed CLI workspace tools to the default nolo local agent request", async () => {
1255
1605
  const requests: Array<{ body: any }> = [];
1256
1606
  const adapter = createCliLocalRuntimeAdapter({
@@ -1356,9 +1706,9 @@ describe("CLI local runtime adapter", () => {
1356
1706
  }
1357
1707
  });
1358
1708
 
1359
- test("runs execShell locally in explicit worktree shell mode", async () => {
1709
+ test("runs execShell locally by default", async () => {
1360
1710
  const adapter = createCliLocalRuntimeAdapter({
1361
- env: { NOLO_LOCAL_SHELL_MODE: "worktree" },
1711
+ env: {},
1362
1712
  db: {
1363
1713
  get: async () => ({
1364
1714
  dbKey: "agent-local-shell",
@@ -1389,12 +1739,11 @@ describe("CLI local runtime adapter", () => {
1389
1739
  expect(result.metadata).toMatchObject({ exitCode: 0 });
1390
1740
  });
1391
1741
 
1392
- test("applies runtime policy shell output limit to local executors without adding a timeout", async () => {
1742
+ test("applies runtime policy shell settings to local executors without adding a timeout", async () => {
1393
1743
  const requests: Array<{ body: any }> = [];
1394
1744
  const adapter = createCliLocalRuntimeAdapter({
1395
1745
  env: {
1396
1746
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1397
- NOLO_LOCAL_SHELL_MODE: "worktree",
1398
1747
  },
1399
1748
  db: {
1400
1749
  get: async () => ({
@@ -1426,8 +1775,8 @@ describe("CLI local runtime adapter", () => {
1426
1775
  name: "execShell",
1427
1776
  arguments: JSON.stringify({
1428
1777
  cmd: process.platform === "win32"
1429
- ? "'abcdefghijklmnopqrstuvwxyz0123456789'.PadRight(500, 'x')"
1430
- : "bun -e 'console.log(\"x\".repeat(500))'",
1778
+ ? "'abcdefghijklmnopqrstuvwxyz0123456789'"
1779
+ : "node -e 'console.log(\"x\".repeat(50))'",
1431
1780
  }),
1432
1781
  },
1433
1782
  }],
@@ -1449,7 +1798,7 @@ describe("CLI local runtime adapter", () => {
1449
1798
 
1450
1799
  expect(result.content).toBe("limits applied");
1451
1800
  const toolResult = requests[1]?.body.messages.at(-1)?.content ?? "";
1452
- expect(toolResult).toContain("[truncated ");
1801
+ expect(toolResult).toContain("exitCode: 0");
1453
1802
  expect(toolResult).not.toContain("command timed out");
1454
1803
  });
1455
1804
 
@@ -1458,7 +1807,6 @@ describe("CLI local runtime adapter", () => {
1458
1807
  const adapter = createCliLocalRuntimeAdapter({
1459
1808
  env: {
1460
1809
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1461
- NOLO_LOCAL_SHELL_MODE: "worktree",
1462
1810
  },
1463
1811
  db: {
1464
1812
  get: async () => ({
@@ -1515,7 +1863,6 @@ describe("CLI local runtime adapter", () => {
1515
1863
  const adapter = createCliLocalRuntimeAdapter({
1516
1864
  env: {
1517
1865
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1518
- NOLO_LOCAL_SHELL_MODE: "worktree",
1519
1866
  },
1520
1867
  db: {
1521
1868
  get: async () => ({
@@ -1583,7 +1930,6 @@ describe("CLI local runtime adapter", () => {
1583
1930
  const adapter = createCliLocalRuntimeAdapter({
1584
1931
  env: {
1585
1932
  NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
1586
- NOLO_LOCAL_SHELL_MODE: "worktree",
1587
1933
  },
1588
1934
  db: {
1589
1935
  get: async () => ({
@@ -1682,6 +2028,305 @@ describe("CLI local runtime adapter", () => {
1682
2028
  });
1683
2029
  });
1684
2030
 
2031
+ test("exposes read_xhs_profile to OpenAI-compatible providers when the agent declares it", async () => {
2032
+ const requests: Array<{ body: any }> = [];
2033
+ const adapter = createCliLocalRuntimeAdapter({
2034
+ env: {
2035
+ OPENAI_API_KEY: "sk-local",
2036
+ NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
2037
+ },
2038
+ db: {
2039
+ get: async () => ({
2040
+ dbKey: "agent-local-xhs",
2041
+ prompt: "Read XHS profile.",
2042
+ model: "gpt-4.1-mini",
2043
+ toolNames: ["read_xhs_profile"],
2044
+ }),
2045
+ put: async () => {},
2046
+ batch: async () => {},
2047
+ iterator: () => (async function* () {})(),
2048
+ },
2049
+ fetchImpl: async (_url, init) => {
2050
+ requests.push({ body: JSON.parse(String(init?.body)) });
2051
+ return Response.json({
2052
+ choices: [{ message: { content: "done" } }],
2053
+ });
2054
+ },
2055
+ });
2056
+
2057
+ await runLocalAgentTurn({
2058
+ adapter,
2059
+ agentRef: "xhs",
2060
+ input: "读取小红书用户主页",
2061
+ });
2062
+
2063
+ expect(toolNamesFromRequest(requests[0])).toContain("read_xhs_profile");
2064
+ });
2065
+
2066
+ test("does not expose read_xhs_profile when the agent does not declare it", async () => {
2067
+ const requests: Array<{ body: any }> = [];
2068
+ const adapter = createCliLocalRuntimeAdapter({
2069
+ env: {
2070
+ OPENAI_API_KEY: "sk-local",
2071
+ NOLO_LOCAL_OPENAI_BASE_URL: "http://127.0.0.1:11434/v1",
2072
+ },
2073
+ db: {
2074
+ get: async () => ({
2075
+ dbKey: "agent-local-no-xhs",
2076
+ prompt: "Be helpful.",
2077
+ model: "gpt-4.1-mini",
2078
+ }),
2079
+ put: async () => {},
2080
+ batch: async () => {},
2081
+ iterator: () => (async function* () {})(),
2082
+ },
2083
+ fetchImpl: async (_url, init) => {
2084
+ requests.push({ body: JSON.parse(String(init?.body)) });
2085
+ return Response.json({
2086
+ choices: [{ message: { content: "done" } }],
2087
+ });
2088
+ },
2089
+ });
2090
+
2091
+ await runLocalAgentTurn({
2092
+ adapter,
2093
+ agentRef: "no-xhs",
2094
+ input: "hello",
2095
+ });
2096
+
2097
+ expect(toolNamesFromRequest(requests[0])).not.toContain("read_xhs_profile");
2098
+ });
2099
+
2100
+ test("executes read_xhs_profile locally through the desktop bridge", async () => {
2101
+ const xhsCalls: Array<{ args: any }> = [];
2102
+ const adapter = createCliLocalRuntimeAdapter({
2103
+ env: {
2104
+ NOLO_LOCAL_USER_ID: "user-1",
2105
+ },
2106
+ db: {
2107
+ get: async () => ({
2108
+ dbKey: "agent-user-1-xhs",
2109
+ id: "xhs-agent",
2110
+ prompt: "Read XHS.",
2111
+ toolNames: ["read_xhs_profile"],
2112
+ }),
2113
+ put: async () => {},
2114
+ batch: async () => {},
2115
+ iterator: () => (async function* () {})(),
2116
+ },
2117
+ localToolExecutors: {
2118
+ read_xhs_profile: async (call) => {
2119
+ const parsed = JSON.parse(call.arguments || "{}");
2120
+ xhsCalls.push({ args: parsed });
2121
+ return {
2122
+ content: JSON.stringify({
2123
+ ok: true,
2124
+ data: {
2125
+ profile: { nickname: "test-soul", redId: "12345" },
2126
+ notes: [],
2127
+ noteDetails: [],
2128
+ analysis: {
2129
+ totalNotes: 0,
2130
+ commentBuckets: [],
2131
+ },
2132
+ },
2133
+ }),
2134
+ metadata: { xhsLocalBridge: true },
2135
+ };
2136
+ },
2137
+ },
2138
+ fetchImpl: async () => Response.json({}),
2139
+ });
2140
+
2141
+ await adapter.loadAgentConfig("xhs-agent");
2142
+ const result = await adapter.executeTool({
2143
+ id: "call-xhs-1",
2144
+ name: "read_xhs_profile",
2145
+ arguments: JSON.stringify({
2146
+ url: "https://www.xiaohongshu.com/user/profile/5d2be8720000000010007556",
2147
+ maxScrollPages: 3,
2148
+ }),
2149
+ });
2150
+
2151
+ expect(xhsCalls).toHaveLength(1);
2152
+ expect(xhsCalls[0].args.url).toBe(
2153
+ "https://www.xiaohongshu.com/user/profile/5d2be8720000000010007556"
2154
+ );
2155
+ expect(xhsCalls[0].args.maxScrollPages).toBe(3);
2156
+ expect(result.metadata).toMatchObject({ xhsLocalBridge: true });
2157
+ const parsed = JSON.parse(result.content);
2158
+ expect(parsed.ok).toBe(true);
2159
+ expect(parsed.data.profile.nickname).toBe("test-soul");
2160
+ });
2161
+
2162
+ test("default read_xhs_profile executor calls the local bridge reader", async () => {
2163
+ const readerCalls: Array<{ args: any; thunkApi: any }> = [];
2164
+ const adapter = createCliLocalRuntimeAdapter({
2165
+ env: {
2166
+ NOLO_LOCAL_USER_ID: "user-1",
2167
+ },
2168
+ db: {
2169
+ get: async () => ({
2170
+ dbKey: "agent-user-1-xhs-default",
2171
+ id: "xhs-default",
2172
+ prompt: "Read XHS.",
2173
+ toolNames: ["read_xhs_profile"],
2174
+ }),
2175
+ put: async () => {},
2176
+ batch: async () => {},
2177
+ iterator: () => (async function* () {})(),
2178
+ },
2179
+ readXhsProfile: async (args, thunkApi) => {
2180
+ readerCalls.push({ args, thunkApi });
2181
+ return {
2182
+ rawData: {
2183
+ ok: true,
2184
+ data: {
2185
+ profile: { nickname: "default-bridge", redId: "67890" },
2186
+ notes: [],
2187
+ noteDetails: [],
2188
+ commentsByNote: {},
2189
+ analysis: {
2190
+ totalNotes: 0,
2191
+ averageLikes: 0,
2192
+ averageComments: 0,
2193
+ averageCollects: 0,
2194
+ averageShares: 0,
2195
+ commentBuckets: [],
2196
+ themes: [],
2197
+ },
2198
+ },
2199
+ fetchedAt: "2026-06-03T00:00:00.000Z",
2200
+ } as any,
2201
+ displayData: "小红书用户: default-bridge",
2202
+ };
2203
+ },
2204
+ fetchImpl: async () => Response.json({}),
2205
+ });
2206
+
2207
+ await adapter.loadAgentConfig("xhs-default");
2208
+ const result = await adapter.executeTool({
2209
+ id: "call-xhs-default",
2210
+ name: "read_xhs_profile",
2211
+ arguments: JSON.stringify({
2212
+ url: "https://www.xiaohongshu.com/user/profile/5d2be8720000000010007556",
2213
+ includeComments: true,
2214
+ maxCommentPagesPerNote: 1,
2215
+ }),
2216
+ });
2217
+
2218
+ expect(readerCalls).toHaveLength(1);
2219
+ expect(readerCalls[0].args).toMatchObject({
2220
+ url: "https://www.xiaohongshu.com/user/profile/5d2be8720000000010007556",
2221
+ includeComments: true,
2222
+ maxCommentPagesPerNote: 1,
2223
+ });
2224
+ expect(String(readerCalls[0].args.profileDir).replaceAll("\\", "/")).toContain(
2225
+ "chat.nolo.desktop/stable/external-readers/xhs-profile"
2226
+ );
2227
+ expect(readerCalls[0].thunkApi).toBeUndefined();
2228
+ expect(result.metadata).toMatchObject({
2229
+ xhsLocalBridge: true,
2230
+ displayData: "小红书用户: default-bridge",
2231
+ });
2232
+ expect(JSON.parse(result.content).data.profile.nickname).toBe("default-bridge");
2233
+ });
2234
+
2235
+ test("default read_xhs_profile executor honors explicit XHS profile env", async () => {
2236
+ const readerCalls: Array<{ args: any }> = [];
2237
+ const adapter = createCliLocalRuntimeAdapter({
2238
+ env: {
2239
+ NOLO_LOCAL_USER_ID: "user-1",
2240
+ NOLO_XHS_READER_PROFILE_DIR: "/tmp/custom-xhs-profile",
2241
+ },
2242
+ db: {
2243
+ get: async () => ({
2244
+ dbKey: "agent-user-1-xhs-env",
2245
+ id: "xhs-env",
2246
+ prompt: "Read XHS.",
2247
+ toolNames: ["read_xhs_profile"],
2248
+ }),
2249
+ put: async () => {},
2250
+ batch: async () => {},
2251
+ iterator: () => (async function* () {})(),
2252
+ },
2253
+ readXhsProfile: async (args) => {
2254
+ readerCalls.push({ args });
2255
+ return {
2256
+ rawData: {
2257
+ ok: true,
2258
+ data: {
2259
+ profile: { nickname: "env-bridge" },
2260
+ notes: [],
2261
+ noteDetails: [],
2262
+ commentsByNote: {},
2263
+ analysis: { totalNotes: 0, commentBuckets: [] },
2264
+ },
2265
+ fetchedAt: "2026-06-03T00:00:00.000Z",
2266
+ } as any,
2267
+ displayData: "小红书用户: env-bridge",
2268
+ };
2269
+ },
2270
+ fetchImpl: async () => Response.json({}),
2271
+ });
2272
+
2273
+ await adapter.loadAgentConfig("xhs-env");
2274
+ await adapter.executeTool({
2275
+ id: "call-xhs-env",
2276
+ name: "read_xhs_profile",
2277
+ arguments: JSON.stringify({
2278
+ url: "https://www.xiaohongshu.com/user/profile/5d2be8720000000010007556",
2279
+ }),
2280
+ });
2281
+
2282
+ expect(readerCalls).toHaveLength(1);
2283
+ expect(readerCalls[0].args.profileDir).toBeUndefined();
2284
+ });
2285
+
2286
+ test("read_xhs_profile executor does not falsely succeed when bridge is unavailable", async () => {
2287
+ const adapter = createCliLocalRuntimeAdapter({
2288
+ env: {
2289
+ NOLO_LOCAL_USER_ID: "user-1",
2290
+ },
2291
+ db: {
2292
+ get: async () => ({
2293
+ dbKey: "agent-user-1-xhs-fail",
2294
+ id: "xhs-fail",
2295
+ prompt: "Read XHS.",
2296
+ toolNames: ["read_xhs_profile"],
2297
+ }),
2298
+ put: async () => {},
2299
+ batch: async () => {},
2300
+ iterator: () => (async function* () {})(),
2301
+ },
2302
+ localToolExecutors: {
2303
+ read_xhs_profile: async () => ({
2304
+ content: JSON.stringify({
2305
+ ok: false,
2306
+ code: "network_error",
2307
+ message: "read_xhs_profile needs Playwright but it is not installed.",
2308
+ }),
2309
+ metadata: { xhsLocalBridge: true, bridgeError: true },
2310
+ }),
2311
+ },
2312
+ fetchImpl: async () => Response.json({}),
2313
+ });
2314
+
2315
+ await adapter.loadAgentConfig("xhs-fail");
2316
+ const result = await adapter.executeTool({
2317
+ id: "call-xhs-fail",
2318
+ name: "read_xhs_profile",
2319
+ arguments: JSON.stringify({
2320
+ url: "https://www.xiaohongshu.com/user/profile/5d2be8720000000010007556",
2321
+ }),
2322
+ });
2323
+
2324
+ const parsed = JSON.parse(result.content);
2325
+ expect(parsed.ok).toBe(false);
2326
+ expect(parsed.code).toBe("network_error");
2327
+ expect(result.metadata).toMatchObject({ bridgeError: true });
2328
+ });
2329
+
1685
2330
  test("runs allowed workspace file tools through default local executors", async () => {
1686
2331
  const workspaceRoot = mkdtempSync(join(tmpdir(), "nolo-cli-runtime-"));
1687
2332
  try {
@@ -1689,7 +2334,7 @@ describe("CLI local runtime adapter", () => {
1689
2334
  ["agent-user-1-writer", {
1690
2335
  dbKey: "agent-user-1-writer",
1691
2336
  id: "writer",
1692
- toolNames: ["writeWorkspaceFile"],
2337
+ toolNames: ["writeFile"],
1693
2338
  }],
1694
2339
  ]);
1695
2340
  const adapter = createCliLocalRuntimeAdapter({
@@ -1712,7 +2357,7 @@ describe("CLI local runtime adapter", () => {
1712
2357
  await adapter.loadAgentConfig("writer");
1713
2358
  const result = await adapter.executeTool({
1714
2359
  id: "call-1",
1715
- name: "writeWorkspaceFile",
2360
+ name: "writeFile",
1716
2361
  arguments: JSON.stringify({
1717
2362
  path: "src/app.ts",
1718
2363
  content: "export const cliValue = 1;\n",