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
@@ -20,9 +20,52 @@ type EnvLike = Record<string, string | undefined>;
20
20
  export type LocalCliExecutor = (
21
21
  provider: string,
22
22
  prompt: string,
23
- options: { model?: string; timeout?: number; cwd?: string; yolo?: boolean; env?: EnvLike }
23
+ options: {
24
+ model?: string;
25
+ timeout?: number;
26
+ cwd?: string;
27
+ yolo?: boolean;
28
+ env?: EnvLike;
29
+ imageInputs?: Array<{ source: string; materializedPath?: string }>;
30
+ }
24
31
  ) => Promise<{ text: string; raw?: string; elapsed?: number }>;
25
32
 
33
+ /**
34
+ * 从 connector payload 的 userInput 中提取 multimodal 内容。
35
+ * 如果 userInput 是字符串,直接返回 { text, imageUrls: [] }。
36
+ * 如果 userInput 是 multimodal content array(`[{ type: "text" }, { type: "image_url" }]`),
37
+ * 提取 text 和 image_url parts。
38
+ */
39
+ function extractMultimodalUserInput(userInput: unknown): {
40
+ text: string;
41
+ imageUrls: string[];
42
+ } {
43
+ if (typeof userInput === "string") {
44
+ return { text: userInput, imageUrls: [] };
45
+ }
46
+ if (!Array.isArray(userInput)) {
47
+ return { text: String(userInput ?? ""), imageUrls: [] };
48
+ }
49
+
50
+ const textParts: string[] = [];
51
+ const imageUrls: string[] = [];
52
+
53
+ for (const part of userInput) {
54
+ if (!part || typeof part !== "object") continue;
55
+ if ((part as any).type === "text" && typeof (part as any).text === "string") {
56
+ textParts.push((part as any).text);
57
+ } else if (
58
+ (part as any).type === "image_url" &&
59
+ typeof (part as any).image_url?.url === "string" &&
60
+ (part as any).image_url.url.trim()
61
+ ) {
62
+ imageUrls.push((part as any).image_url.url.trim());
63
+ }
64
+ }
65
+
66
+ return { text: textParts.join("\n"), imageUrls };
67
+ }
68
+
26
69
  type ConnectorRuntimePolicy = {
27
70
  runtimeTools?: string[];
28
71
  agentTools?: string[];
@@ -103,7 +146,6 @@ function summarizeRuntimePolicyForLogs(policy?: ConnectorRuntimePolicy) {
103
146
  workspaceMode: policy?.workspace?.mode ?? null,
104
147
  workspaceCwd: policy?.workspace?.cwd ?? null,
105
148
  shellEnabled: policy?.shell?.enabled ?? null,
106
- shellMode: policy?.shell?.mode ?? null,
107
149
  };
108
150
  }
109
151
 
@@ -188,13 +230,13 @@ function runtimeWorkspacePermissionPolicy(
188
230
  runtimeEnv: EnvLike,
189
231
  cwd: string
190
232
  ): PermissionPolicy | null {
233
+ void runtimeEnv;
191
234
  if (!requestsLocalWorkspaceRuntime(runtimePolicy)) return null;
192
235
  return {
193
236
  mode: "full_access",
194
237
  allowFilesystemRead: true,
195
238
  allowFilesystemWrite: true,
196
239
  allowShell:
197
- runtimeEnv.NOLO_LOCAL_SHELL_MODE === "worktree" &&
198
240
  Array.isArray(runtimePolicy?.runtimeTools) &&
199
241
  runtimePolicy.runtimeTools.includes("execShell"),
200
242
  writableRoots: [cwd],
@@ -332,8 +374,6 @@ async function defaultRunConnectorLocalRuntimeAgent(args: {
332
374
  requestId: args.parsed.requestId,
333
375
  agentKey,
334
376
  cwd: args.cwd,
335
- runtimeEnvShellModeBeforePolicy: args.runtimeEnv.NOLO_LOCAL_SHELL_MODE ?? null,
336
- runtimeEnvShellModeAfterPolicy: env.NOLO_LOCAL_SHELL_MODE ?? null,
337
377
  ...summarizeRuntimePolicyForLogs(policy),
338
378
  });
339
379
  const adapter = createCliLocalRuntimeAdapter({
@@ -454,7 +494,9 @@ export async function handleConnectorRunMessage(
454
494
  try {
455
495
  const machinePermissionPolicy = resolveMachineRunPermissionPolicy(agentConfig);
456
496
  const runtimePolicy = runtimePolicyFromConnectorPayload(parsed);
457
- const userInput = String(parsed.payload?.userInput ?? "");
497
+ const extractedInput = extractMultimodalUserInput(parsed.payload?.userInput);
498
+ const userInput = extractedInput.text;
499
+ const connectorImageUrls = extractedInput.imageUrls;
458
500
  const timeout = normalizeConnectorRunTimeoutMs(parsed.payload?.timeoutMs);
459
501
  let cwd = resolveConnectorRunCwd({ env: runtimeEnv, policy: machinePermissionPolicy });
460
502
  let runContent = "";
@@ -553,6 +595,9 @@ export async function handleConnectorRunMessage(
553
595
  effectiveRuntimeEnv.AUTH_TOKEN ||
554
596
  effectiveRuntimeEnv.AUTH,
555
597
  },
598
+ ...(connectorImageUrls.length > 0
599
+ ? { imageInputs: connectorImageUrls.map((url) => ({ source: url })) }
600
+ : {}),
556
601
  }).finally(() => clearInterval(heartbeat));
557
602
  logConnectorRun("agent.run.cli.result", {
558
603
  requestId: parsed.requestId,
@@ -40,15 +40,17 @@ function readFlagValue(args: string[], flag: string) {
40
40
  }
41
41
 
42
42
  function parseUserIdFromToken(token: string) {
43
- const payload = token.split(".")[0];
44
- if (!payload) return "";
43
+ const payload = token.split(".")[1];
44
+ if (!payload) return undefined;
45
45
  try {
46
46
  const normalized = payload.replace(/-/g, "+").replace(/_/g, "/");
47
47
  const padded = normalized + "=".repeat((4 - (normalized.length % 4)) % 4);
48
48
  const parsed = JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
49
- return typeof parsed?.userId === "string" ? parsed.userId : "";
49
+ return typeof parsed?.userId === "string" && parsed.userId.trim()
50
+ ? parsed.userId.trim()
51
+ : undefined;
50
52
  } catch {
51
- return "";
53
+ return undefined;
52
54
  }
53
55
  }
54
56
 
@@ -15,7 +15,7 @@ describe("agent config resolver", () => {
15
15
  cliProvider: "codex",
16
16
  customProviderUrl: "https://provider.example/v1",
17
17
  toolNames: ["legacyTool", "readFile"],
18
- tools: ["readFile", "applyEdit"],
18
+ tools: ["readFile", "editFile"],
19
19
  runtimeBinding: { machineId: "machine-1" },
20
20
  delegation: { target: "local" },
21
21
  temperature: 0.2,
@@ -33,7 +33,7 @@ describe("agent config resolver", () => {
33
33
  apiSource: "platform",
34
34
  cliProvider: "codex",
35
35
  customProviderUrl: "https://provider.example/v1",
36
- toolNames: ["legacyTool", "readFile", "applyEdit"],
36
+ toolNames: ["legacyTool", "readFile", "editFile"],
37
37
  runtimeBinding: { machineId: "machine-1" },
38
38
  delegation: { target: "local" },
39
39
  temperature: 0.2,
@@ -35,11 +35,11 @@ describe("cli agent run client", () => {
35
35
  });
36
36
 
37
37
  test("identifies server platform tools that local runtime cannot provide", () => {
38
- expect(findServerPlatformTools(["readWorkspaceFile", "queryTableRows", "updateTableRow"])).toEqual([
38
+ expect(findServerPlatformTools(["readFile", "queryTableRows", "updateTableRow"])).toEqual([
39
39
  "queryTableRows",
40
40
  "updateTableRow",
41
41
  ]);
42
- expect(findServerPlatformTools(["readWorkspaceFile", "execShell"])).toEqual([]);
42
+ expect(findServerPlatformTools(["readFile", "execShell"])).toEqual([]);
43
43
  });
44
44
 
45
45
  test("calls the Nolo HTTP API directly when AUTH_TOKEN is present", async () => {
@@ -239,7 +239,6 @@ describe("cli agent run client", () => {
239
239
  parentDialogId: "dialog-2",
240
240
  background: true,
241
241
  noStream: true,
242
- maxToolRounds: 12,
243
242
  timeoutMs: 600000,
244
243
  scriptDir: "C:/missing/scripts",
245
244
  env: { AUTH_TOKEN: "token-123" },
@@ -259,7 +258,6 @@ describe("cli agent run client", () => {
259
258
  inheritedFromDialogKey: "dialog-user-1-dialog-2",
260
259
  parentDialogId: "dialog-2",
261
260
  background: true,
262
- maxRounds: 12,
263
261
  timeoutMs: 600000,
264
262
  stream: false,
265
263
  });
@@ -345,72 +343,75 @@ describe("cli agent run client", () => {
345
343
  expect(output.text()).toContain("frontend > local:polish notifications");
346
344
  });
347
345
 
348
- test("increases local max tool rounds when a forced local run exhausts them", async () => {
346
+ test("continues forced local tool loops until the provider returns final text", async () => {
349
347
  const output = new CaptureOutput();
350
348
  let completeCalls = 0;
349
+ let toolCalls = 0;
350
+
351
351
  const result = await runAgentTurn({
352
352
  agentName: "frontend",
353
353
  agentKey: "frontend-local",
354
354
  serverUrl: "https://nolo.chat",
355
- message: "polish notifications",
355
+ message: "make screenshots",
356
356
  scriptDir: "C:/missing/scripts",
357
- env: { AUTH_TOKEN: "token-123", NOLO_LOCAL_MAX_TOOL_ROUNDS_LIMIT: "1" },
357
+ env: { AUTH_TOKEN: "token-123" },
358
358
  output,
359
359
  runtimeMode: "local",
360
- maxToolRounds: 0,
361
360
  localRuntimeAdapter: {
362
361
  host: "cli",
363
- capabilities: ["local-provider", "local-persistence"],
362
+ capabilities: ["local-provider", "local-persistence", "local-tools"],
364
363
  loadAgentConfig: async (agentRef) => ({
365
364
  key: agentRef,
366
365
  name: "Frontend",
367
366
  prompt: "Fix UI",
368
367
  model: "fake-local",
368
+ toolNames: ["readFile"],
369
369
  }),
370
370
  loadDialogHistory: async () => [],
371
- saveTurn: async () => ({ dialogId: "dialog-local" }),
371
+ saveTurn: async () => ({ dialogId: "dialog-local-retry" }),
372
372
  resolveProvider: async () => ({
373
373
  model: "fake-local",
374
374
  complete: async () => {
375
375
  completeCalls += 1;
376
- return {
377
- content: "",
378
- model: "fake-local",
379
- tool_calls: [{
380
- id: `call-${completeCalls}`,
381
- type: "function",
382
- function: { name: "readWorkspaceFile", arguments: "{}" },
383
- }],
384
- };
376
+ if (completeCalls <= 3) {
377
+ return {
378
+ content: "",
379
+ model: "fake-local",
380
+ tool_calls: [{
381
+ id: `call-${completeCalls}`,
382
+ type: "function",
383
+ function: { name: "readFile", arguments: "{}" },
384
+ }],
385
+ };
386
+ }
387
+ return { content: "done after retry", model: "fake-local" };
385
388
  },
386
389
  }),
387
- executeTool: async () => ({ content: "ok" }),
388
- },
389
- fetchImpl: async () => {
390
- throw new Error("HTTP should not be called for forced local runs");
390
+ executeTool: async () => {
391
+ toolCalls += 1;
392
+ return { content: "ok" };
393
+ },
391
394
  },
392
395
  });
393
396
 
394
- expect(result).toMatchObject({ exitCode: 1 });
395
- expect(output.text()).toContain("Local agent used all 0 tool rounds; retrying with 1.");
396
- expect(output.text()).toContain("Local agent exceeded max tool rounds: 1");
397
+ expect(result).toEqual({ exitCode: 0, dialogId: "dialog-local-retry" });
398
+ expect(toolCalls).toBe(3);
399
+ expect(output.text()).toContain("frontend > done after retry");
397
400
  });
398
401
 
399
- test("completes a forced local run after automatically increasing tool rounds", async () => {
402
+ test("prints compact local tool trace by default", async () => {
400
403
  const output = new CaptureOutput();
401
404
  let completeCalls = 0;
402
- let toolCalls = 0;
403
405
 
404
406
  const result = await runAgentTurn({
405
407
  agentName: "frontend",
406
408
  agentKey: "frontend-local",
407
409
  serverUrl: "https://nolo.chat",
408
- message: "make screenshots",
410
+ message: "inspect repo",
409
411
  scriptDir: "C:/missing/scripts",
410
412
  env: { AUTH_TOKEN: "token-123" },
411
413
  output,
412
414
  runtimeMode: "local",
413
- maxToolRounds: 1,
414
415
  localRuntimeAdapter: {
415
416
  host: "cli",
416
417
  capabilities: ["local-provider", "local-persistence", "local-tools"],
@@ -419,42 +420,39 @@ describe("cli agent run client", () => {
419
420
  name: "Frontend",
420
421
  prompt: "Fix UI",
421
422
  model: "fake-local",
422
- toolNames: ["readWorkspaceFile"],
423
+ toolNames: ["readFile"],
423
424
  }),
424
425
  loadDialogHistory: async () => [],
425
- saveTurn: async () => ({ dialogId: "dialog-local-retry" }),
426
+ saveTurn: async () => ({ dialogId: "dialog-local" }),
426
427
  resolveProvider: async () => ({
427
428
  model: "fake-local",
428
429
  complete: async () => {
429
430
  completeCalls += 1;
430
- if (completeCalls <= 3) {
431
+ if (completeCalls === 1) {
431
432
  return {
432
433
  content: "",
433
434
  model: "fake-local",
434
435
  tool_calls: [{
435
- id: `call-${completeCalls}`,
436
+ id: "call-read",
436
437
  type: "function",
437
- function: { name: "readWorkspaceFile", arguments: "{}" },
438
+ function: { name: "readFile", arguments: JSON.stringify({ path: "README.md" }) },
438
439
  }],
439
440
  };
440
441
  }
441
- return { content: "done after retry", model: "fake-local" };
442
+ return { content: "done", model: "fake-local" };
442
443
  },
443
444
  }),
444
- executeTool: async () => {
445
- toolCalls += 1;
446
- return { content: "ok" };
447
- },
445
+ executeTool: async () => ({ content: "clean" }),
448
446
  },
449
447
  });
450
448
 
451
- expect(result).toEqual({ exitCode: 0, dialogId: "dialog-local-retry" });
452
- expect(toolCalls).toBe(2);
453
- expect(output.text()).toContain("Local agent used all 1 tool rounds; retrying with 2.");
454
- expect(output.text()).toContain("frontend > done after retry");
449
+ expect(result).toMatchObject({ exitCode: 0, dialogId: "dialog-local" });
450
+ expect(output.text()).toContain("[nolo:tool] #1 -> readFile README.md");
451
+ expect(output.text()).toContain("[nolo:tool] #1 <- readFile");
452
+ expect(output.text()).toContain("1 line");
455
453
  });
456
454
 
457
- test("prints local tool trace when requested", async () => {
455
+ test("does not print local tool trace when disabled by env", async () => {
458
456
  const output = new CaptureOutput();
459
457
  let completeCalls = 0;
460
458
 
@@ -464,10 +462,9 @@ describe("cli agent run client", () => {
464
462
  serverUrl: "https://nolo.chat",
465
463
  message: "inspect repo",
466
464
  scriptDir: "C:/missing/scripts",
467
- env: { AUTH_TOKEN: "token-123" },
465
+ env: { AUTH_TOKEN: "token-123", NOLO_TRACE_TOOLS: "0" },
468
466
  output,
469
467
  runtimeMode: "local",
470
- traceTools: true,
471
468
  localRuntimeAdapter: {
472
469
  host: "cli",
473
470
  capabilities: ["local-provider", "local-persistence", "local-tools"],
@@ -476,10 +473,10 @@ describe("cli agent run client", () => {
476
473
  name: "Frontend",
477
474
  prompt: "Fix UI",
478
475
  model: "fake-local",
479
- toolNames: ["readWorkspaceFile"],
476
+ toolNames: ["readFile"],
480
477
  }),
481
478
  loadDialogHistory: async () => [],
482
- saveTurn: async () => ({ dialogId: "dialog-local" }),
479
+ saveTurn: async () => ({ dialogId: "dialog-local-no-trace" }),
483
480
  resolveProvider: async () => ({
484
481
  model: "fake-local",
485
482
  complete: async () => {
@@ -491,7 +488,7 @@ describe("cli agent run client", () => {
491
488
  tool_calls: [{
492
489
  id: "call-read",
493
490
  type: "function",
494
- function: { name: "readWorkspaceFile", arguments: JSON.stringify({ path: "README.md" }) },
491
+ function: { name: "readFile", arguments: JSON.stringify({ path: "README.md" }) },
495
492
  }],
496
493
  };
497
494
  }
@@ -502,9 +499,79 @@ describe("cli agent run client", () => {
502
499
  },
503
500
  });
504
501
 
505
- expect(result).toMatchObject({ exitCode: 0, dialogId: "dialog-local" });
506
- expect(output.text()).toContain("[nolo:tool] round 1 -> readWorkspaceFile (call-read)");
507
- expect(output.text()).toContain("[nolo:tool] round 1 <- readWorkspaceFile (call-read)");
502
+ expect(result).toMatchObject({ exitCode: 0, dialogId: "dialog-local-no-trace" });
503
+ expect(output.text()).not.toContain("[nolo:tool]");
504
+ });
505
+
506
+ test("prints local tool events as jsonl when requested", async () => {
507
+ const output = new CaptureOutput();
508
+ let completeCalls = 0;
509
+
510
+ const result = await runAgentTurn({
511
+ agentName: "frontend",
512
+ agentKey: "frontend-local",
513
+ serverUrl: "https://nolo.chat",
514
+ message: "inspect repo",
515
+ scriptDir: "C:/missing/scripts",
516
+ env: { AUTH_TOKEN: "token-123" },
517
+ output,
518
+ runtimeMode: "local",
519
+ eventsMode: "jsonl",
520
+ localRuntimeAdapter: {
521
+ host: "cli",
522
+ capabilities: ["local-provider", "local-persistence", "local-tools"],
523
+ loadAgentConfig: async (agentRef) => ({
524
+ key: agentRef,
525
+ name: "Frontend",
526
+ prompt: "Fix UI",
527
+ model: "fake-local",
528
+ toolNames: ["execShell"],
529
+ }),
530
+ loadDialogHistory: async () => [],
531
+ saveTurn: async () => ({ dialogId: "dialog-local-jsonl" }),
532
+ resolveProvider: async () => ({
533
+ model: "fake-local",
534
+ complete: async () => {
535
+ completeCalls += 1;
536
+ if (completeCalls === 1) {
537
+ return {
538
+ content: "",
539
+ model: "fake-local",
540
+ tool_calls: [{
541
+ id: "call-shell",
542
+ type: "function",
543
+ function: { name: "execShell", arguments: JSON.stringify({ command: "git status --short" }) },
544
+ }],
545
+ };
546
+ }
547
+ return { content: "done", model: "fake-local" };
548
+ },
549
+ }),
550
+ executeTool: async () => ({ content: "stdout:\nclean\n\nexitCode: 0", metadata: { exitCode: 0 } }),
551
+ },
552
+ });
553
+
554
+ expect(result).toMatchObject({ exitCode: 0, dialogId: "dialog-local-jsonl" });
555
+ const events = output.text()
556
+ .split(/\r?\n/)
557
+ .filter((line) => line.startsWith("{"))
558
+ .map((line) => JSON.parse(line))
559
+ .filter((event) => typeof event.type === "string" && event.type.startsWith("tool-"));
560
+ expect(events).toHaveLength(2);
561
+ expect(events[0]).toMatchObject({
562
+ schemaVersion: 1,
563
+ type: "tool-call",
564
+ round: 1,
565
+ tool: "execShell",
566
+ argsPreview: "git status --short",
567
+ });
568
+ expect(events[1]).toMatchObject({
569
+ schemaVersion: 1,
570
+ type: "tool-result",
571
+ round: 1,
572
+ tool: "execShell",
573
+ summary: expect.stringContaining("exit=0"),
574
+ });
508
575
  });
509
576
 
510
577
  test("passes local tool evidence to task-run writeback", async () => {
@@ -536,7 +603,7 @@ describe("cli agent run client", () => {
536
603
  name: "Frontend",
537
604
  prompt: "Fix UI",
538
605
  model: "fake-local",
539
- toolNames: ["readWorkspaceFile"],
606
+ toolNames: ["readFile"],
540
607
  }),
541
608
  loadDialogHistory: async () => [],
542
609
  saveTurn: async () => ({ dialogId: "dialog-local" }),
@@ -551,7 +618,7 @@ describe("cli agent run client", () => {
551
618
  tool_calls: [{
552
619
  id: "call-read",
553
620
  type: "function",
554
- function: { name: "readWorkspaceFile", arguments: JSON.stringify({ path: "README.md" }) },
621
+ function: { name: "readFile", arguments: JSON.stringify({ path: "README.md" }) },
555
622
  }],
556
623
  };
557
624
  }
@@ -565,7 +632,7 @@ describe("cli agent run client", () => {
565
632
  expect(result).toMatchObject({ exitCode: 0, dialogId: "dialog-local" });
566
633
  expect(writebacks).toHaveLength(1);
567
634
  expect(writebacks[0].toolEvidence).toEqual({
568
- toolsUsed: ["readWorkspaceFile"],
635
+ toolsUsed: ["readFile"],
569
636
  summary: {
570
637
  callCount: 1,
571
638
  resultCount: 1,
@@ -820,6 +887,58 @@ describe("cli agent run client", () => {
820
887
  expect(output.text()).toContain("pm > server ok");
821
888
  });
822
889
 
890
+ test("auto mode keeps local runtime for CLI provider agents even when they declare platform tools", async () => {
891
+ const output = new CaptureOutput();
892
+ const httpCalls: string[] = [];
893
+ let providerCalled = false;
894
+
895
+ const result = await runAgentTurn({
896
+ agentName: "frontend-implementer",
897
+ agentKey: "frontend-implementer",
898
+ serverUrl: "https://nolo.chat",
899
+ message: "polish notifications",
900
+ scriptDir: "C:/missing/scripts",
901
+ env: { AUTH_TOKEN: "token-123" },
902
+ output,
903
+ runtimeMode: "auto",
904
+ localRuntimeAdapter: {
905
+ host: "cli",
906
+ capabilities: ["leveldb-agent-config", "local-provider", "local-tools"],
907
+ loadAgentConfig: async (agentRef) => ({
908
+ key: agentRef,
909
+ name: "AGY",
910
+ prompt: "Implement frontend tasks.",
911
+ provider: "agy",
912
+ cliProvider: "agy",
913
+ toolNames: ["streamParallelAgents", "taskRun"],
914
+ }),
915
+ loadDialogHistory: async () => [],
916
+ saveTurn: async () => ({ dialogId: "dialog-agy-auto-local" }),
917
+ resolveProvider: async () => ({
918
+ model: "agy",
919
+ complete: async () => {
920
+ providerCalled = true;
921
+ return { content: "agy local ok", model: "agy" };
922
+ },
923
+ }),
924
+ executeTool: async () => {
925
+ throw new Error("no tools expected");
926
+ },
927
+ },
928
+ fetchImpl: async (url) => {
929
+ httpCalls.push(String(url));
930
+ return Response.json({ content: "server" });
931
+ },
932
+ });
933
+
934
+ expect(providerCalled).toBe(true);
935
+ expect(result).toEqual({ exitCode: 0, dialogId: "dialog-agy-auto-local" });
936
+ expect(httpCalls).toEqual([]);
937
+ expect(output.text()).not.toContain("skipping local runtime");
938
+ expect(output.text()).toContain("frontend-implementer -> working locally");
939
+ expect(output.text()).toContain("frontend-implementer > agy local ok");
940
+ });
941
+
823
942
  test("auto mode does not skip monthly Mimo when a local shell cwd is already bound", async () => {
824
943
  const output = new CaptureOutput();
825
944
  const httpCalls: string[] = [];
@@ -833,7 +952,6 @@ describe("cli agent run client", () => {
833
952
  scriptDir: "C:/missing/scripts",
834
953
  env: {
835
954
  AUTH_TOKEN: "token-123",
836
- NOLO_LOCAL_SHELL_MODE: "worktree",
837
955
  },
838
956
  output,
839
957
  runtimeMode: "auto",