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.
- package/README.md +4 -4
- package/agent-runtime/dialogWritePlan.ts +39 -0
- package/agent-runtime/hostAdapter.ts +4 -0
- package/agent-runtime/hybridRecordStore.ts +5 -3
- package/agent-runtime/index.ts +15 -0
- package/agent-runtime/localLoop.ts +87 -7
- package/agent-runtime/localToolPolicy.ts +2 -13
- package/agent-runtime/localWorkspaceTools.ts +42 -110
- package/agent-runtime/runtimeToolPolicy.ts +2 -11
- package/agent-runtime/runtimeToolSurface.ts +198 -0
- package/agent-runtime/types.ts +1 -0
- package/agentAliases.ts +2 -1
- package/agentRunCommand.ts +10 -32
- package/agentRuntimeLocal.ts +1 -0
- package/ai/agent/_executeModel.ts +146 -0
- package/ai/agent/agentSlice.ts +556 -1
- package/ai/agent/appWorkingMemory.ts +126 -0
- package/ai/agent/buildEditingContext.ts +378 -0
- package/ai/agent/buildSystemPrompt.ts +585 -0
- package/ai/agent/canvasEditingContext.ts +49 -0
- package/ai/agent/cleanAgentMessages.ts +140 -0
- package/ai/agent/cliChatClient.ts +153 -0
- package/ai/agent/cliExecutor.ts +314 -40
- package/ai/agent/contextCompiler.ts +107 -0
- package/ai/agent/contextLayerContract.ts +44 -0
- package/ai/agent/createAgentSchema.ts +272 -0
- package/ai/agent/currentTimeContext.ts +65 -0
- package/ai/agent/executeToolCall.ts +58 -0
- package/ai/agent/fetchAgentContexts.ts +42 -0
- package/ai/agent/generatePrompt.ts +3 -0
- package/ai/agent/getFullChatContextKeys.ts +168 -0
- package/ai/agent/guidedCreation/capabilities.ts +84 -0
- package/ai/agent/guidedCreation/types.ts +38 -0
- package/ai/agent/isLiveAudioOnlyAgent.ts +26 -0
- package/ai/agent/liveAudioModel.ts +2 -0
- package/ai/agent/pageBuilderHandoffRules.ts +75 -0
- package/ai/agent/persistMessageWithFixedId.ts +37 -0
- package/ai/agent/planSlice.ts +259 -0
- package/ai/agent/referenceUtils.ts +229 -0
- package/ai/agent/runAgentBackground.ts +310 -0
- package/ai/agent/runAgentClientLoop.ts +164 -0
- package/ai/agent/runtimeGuidance.ts +116 -0
- package/ai/agent/serverOrigin.ts +7 -0
- package/ai/agent/startParallelAgentStreams.ts +424 -0
- package/ai/agent/startupProtocol.ts +53 -0
- package/ai/agent/streamAgentChatTurn.ts +2001 -0
- package/ai/agent/streamAgentChatTurnUtils.ts +860 -0
- package/ai/agent/toolFailureGuard.ts +99 -0
- package/ai/agent/types.ts +73 -0
- package/ai/agent/utils/imageOutput.ts +37 -0
- package/ai/agent/utils/publicImageAgentMode.ts +26 -0
- package/ai/ai.locale.ts +1095 -0
- package/ai/chat/accumulateToolCallChunks.ts +126 -0
- package/ai/chat/fetchUtils.ts +143 -0
- package/ai/chat/inlineImageUrlsForCustomProvider.ts +117 -0
- package/ai/chat/parseApiError.ts +67 -0
- package/ai/chat/parseMultilineSSE.ts +95 -0
- package/ai/chat/sendOpenAICompletionsRequest.ts +897 -0
- package/ai/chat/sendOpenAIResponseRequest.ts +720 -0
- package/ai/chat/serverProxyRetry.ts +102 -0
- package/ai/chat/shouldUseServerProxy.ts +18 -0
- package/ai/chat/streamRetry.ts +46 -0
- package/ai/chat/updateTotalUsage.ts +89 -0
- package/ai/context/buildReferenceContext.ts +437 -0
- package/ai/context/retention.ts +165 -0
- package/ai/context/tokenUtils.ts +78 -0
- package/ai/llm/agentCapabilities.ts +74 -0
- package/ai/llm/deepinfra.ts +79 -0
- package/ai/llm/fireworks.ts +68 -0
- package/ai/llm/generateRequestBody.ts +165 -0
- package/ai/llm/getModelContextWindow.ts +93 -0
- package/ai/llm/getPricing.ts +252 -0
- package/ai/llm/imagePricing.ts +66 -0
- package/ai/llm/isResponseAPIModel.ts +13 -0
- package/ai/llm/kimi.ts +23 -0
- package/ai/llm/mimo.ts +99 -0
- package/ai/llm/mistral.ts +21 -0
- package/ai/llm/models.ts +45 -0
- package/ai/llm/openrouterModels.ts +6 -0
- package/ai/llm/providers.ts +313 -0
- package/ai/llm/reasoningModels.ts +27 -0
- package/ai/llm/types.ts +82 -0
- package/ai/llm/usageRequestOptions.ts +59 -0
- package/ai/memory/queryShared.ts +161 -0
- package/ai/memory/recentRelationshipRecap.ts +247 -0
- package/ai/memory/remember.ts +167 -0
- package/ai/memory/store.ts +20 -0
- package/ai/memory/storeShared.ts +76 -0
- package/ai/memory/types.ts +46 -0
- package/ai/memory/understanding.ts +349 -0
- package/ai/memory/understandingGreeting.ts +264 -0
- package/ai/policy/personalizationDialog.ts +333 -0
- package/ai/policy/runtimePolicy.ts +454 -0
- package/ai/policy/selfUpdateFields.ts +48 -0
- package/ai/policy/types.ts +64 -0
- package/ai/skills/referenceRuntime.ts +274 -0
- package/ai/skills/skillDiagnostics.ts +251 -0
- package/ai/skills/skillDocBuilder.ts +139 -0
- package/ai/skills/skillSummaryMarker.ts +26 -0
- package/ai/token/calculatePrice.ts +576 -0
- package/ai/token/missingUsageEstimate.ts +42 -0
- package/ai/token/normalizeUsage.ts +124 -0
- package/ai/token/openaiImageGenerationUsage.ts +56 -0
- package/ai/token/prepareTokenUsageData.ts +93 -0
- package/ai/token/resolveBillingTarget.ts +52 -0
- package/ai/token/saveTokenRecord.ts +53 -0
- package/ai/token/types.ts +103 -0
- package/ai/tools/agent/agentTools.ts +235 -0
- package/ai/tools/agent/agentUpdateShared.ts +311 -0
- package/ai/tools/agent/callAgentTool.ts +139 -0
- package/ai/tools/agent/createAgentTool.ts +512 -0
- package/ai/tools/agent/createDialogTool.ts +69 -0
- package/ai/tools/agent/createSkillAgentTool.ts +62 -0
- package/ai/tools/agent/parallelBudget.ts +221 -0
- package/ai/tools/agent/prepareAgentDraftTool.ts +159 -0
- package/ai/tools/agent/presets/appBuilderPreset.ts +154 -0
- package/ai/tools/agent/runLlmTool.ts +96 -0
- package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
- package/ai/tools/agent/skillAgentArgs.ts +106 -0
- package/ai/tools/agent/startAgentDialogTool.ts +53 -0
- package/ai/tools/agent/streamParallelAgentsTool.ts +123 -0
- package/ai/tools/agent/updateAgentTool.ts +96 -0
- package/ai/tools/agent/updateSelfTool.ts +113 -0
- package/ai/tools/amazonProductScraperTool.ts +86 -0
- package/ai/tools/apifyActorClient.ts +45 -0
- package/ai/tools/appEditGuard.ts +372 -0
- package/ai/tools/appReadSnapshot.ts +153 -0
- package/ai/tools/appTools.ts +1549 -0
- package/ai/tools/applyEditTool.ts +259 -0
- package/ai/tools/applyLineEditsTool.ts +315 -0
- package/ai/tools/browserTools/click.ts +33 -0
- package/ai/tools/browserTools/closeSession.ts +29 -0
- package/ai/tools/browserTools/common.ts +27 -0
- package/ai/tools/browserTools/openSession.ts +48 -0
- package/ai/tools/browserTools/readContent.ts +38 -0
- package/ai/tools/browserTools/selectOption.ts +46 -0
- package/ai/tools/browserTools/typeText.ts +42 -0
- package/ai/tools/category/createCategoryTool.ts +66 -0
- package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
- package/ai/tools/category/updateContentCategoryTool.ts +75 -0
- package/ai/tools/cfBrowserTools.ts +319 -0
- package/ai/tools/cfSpeechToTextTool.ts +49 -0
- package/ai/tools/checkEnvTool.ts +102 -0
- package/ai/tools/cloudflareCrawlTool.ts +289 -0
- package/ai/tools/codeSearchTool.ts +123 -0
- package/ai/tools/codeTools.ts +101 -0
- package/ai/tools/convertMarxistsBookTool.ts +103 -0
- package/ai/tools/createDocTool.ts +132 -0
- package/ai/tools/createSkillDocTool.ts +155 -0
- package/ai/tools/createWorkflowTool.ts +154 -0
- package/ai/tools/delayTool.ts +31 -0
- package/ai/tools/deleteSpacesTool.ts +325 -0
- package/ai/tools/deleteSpacesToolModel.ts +159 -0
- package/ai/tools/devReloadUtils.ts +29 -0
- package/ai/tools/dialogMessageSearch.ts +137 -0
- package/ai/tools/doctorSkillTool.ts +72 -0
- package/ai/tools/ecommerceScraperTool.ts +86 -0
- package/ai/tools/emailTools.ts +549 -0
- package/ai/tools/evalSkillTool.ts +92 -0
- package/ai/tools/exaSearchTool.ts +63 -0
- package/ai/tools/execShellTool.ts +266 -0
- package/ai/tools/executeSqlTool.ts +192 -0
- package/ai/tools/fetchWebpageSupport.ts +333 -0
- package/ai/tools/fetchWebpageTool.ts +97 -0
- package/ai/tools/geminiImagePreviewTool.ts +386 -0
- package/ai/tools/generateDocxTool.ts +215 -0
- package/ai/tools/googleSearchScraperTool.ts +106 -0
- package/ai/tools/importDataTool.ts +133 -0
- package/ai/tools/importSkillTool.ts +162 -0
- package/ai/tools/index.ts +2308 -0
- package/ai/tools/jdProductScraperTool.ts +821 -0
- package/ai/tools/listUserSpacesTool.ts +113 -0
- package/ai/tools/localFilesTool.ts +276 -0
- package/ai/tools/marxistsOfflineBook.ts +253 -0
- package/ai/tools/modelUsageTools.ts +206 -0
- package/ai/tools/noloWorkspaceReadTools.ts +467 -0
- package/ai/tools/olmOcrTool.ts +33 -0
- package/ai/tools/openaiImageTool.ts +267 -0
- package/ai/tools/prepareTools.ts +23 -0
- package/ai/tools/readDocTool.ts +88 -0
- package/ai/tools/readFileTool.ts +214 -0
- package/ai/tools/readTool.ts +194 -0
- package/ai/tools/readXPostTool.ts +229 -0
- package/ai/tools/readXhsProfileTool.ts +627 -0
- package/ai/tools/rememberMemoryTool.ts +84 -0
- package/ai/tools/remotionVideoTool.ts +151 -0
- package/ai/tools/searchDialogMessagesTool.ts +222 -0
- package/ai/tools/searchWorkspaceTool.ts +259 -0
- package/ai/tools/skillFollowup.ts +86 -0
- package/ai/tools/surfWeatherTool.ts +169 -0
- package/ai/tools/table/addTableRowTool.ts +217 -0
- package/ai/tools/table/createTableTool.ts +315 -0
- package/ai/tools/table/rowTools.ts +386 -0
- package/ai/tools/table/schemaTools.ts +244 -0
- package/ai/tools/table/shareTableTool.ts +148 -0
- package/ai/tools/table/toolShared.ts +129 -0
- package/ai/tools/taobaoTmallProductScraperTool.ts +49 -0
- package/ai/tools/toolApiClient.ts +279 -0
- package/ai/tools/toolResultError.ts +42 -0
- package/ai/tools/toolRunSlice.ts +303 -0
- package/ai/tools/toolSchemaCompatibility.ts +53 -0
- package/ai/tools/uiAskChoiceTool.ts +104 -0
- package/ai/tools/updateContentTitleTool.ts +84 -0
- package/ai/tools/updateDocTool.ts +105 -0
- package/ai/tools/updateUserPreferenceProfileTool.ts +153 -0
- package/ai/tools/wereadGatewayTool.ts +152 -0
- package/ai/tools/whisperTool.ts +76 -0
- package/ai/tools/writeFileTool.ts +213 -0
- package/ai/tools/youtubeScraperTool.ts +116 -0
- package/ai/tools/ziweiChartTool.ts +678 -0
- package/ai/types.ts +55 -0
- package/ai/workflow/workflowExecutor.ts +323 -0
- package/ai/workflow/workflowSlice.ts +73 -0
- package/ai/workflow/workflowTypes.ts +106 -0
- package/app/actions/syncAppRecord.ts +73 -0
- package/app/constants/animationSets.ts +21 -0
- package/app/constants/appEditor.ts +99 -0
- package/app/favorite/favoriteSlice.ts +690 -0
- package/app/favorite/type.ts +43 -0
- package/app/hooks/deleteDbKey.ts +233 -0
- package/app/i18n/client.ts +13 -0
- package/app/i18n/i18n.base.ts +14 -0
- package/app/i18n/i18n.config.ts +77 -0
- package/app/i18n/index.ts +15 -0
- package/app/i18n/mapLanguage.ts +11 -0
- package/app/i18n/translations/appBuilder.locale.ts +453 -0
- package/app/i18n/translations/error.locale.ts +246 -0
- package/app/i18n/translations/interface.locale.ts +2174 -0
- package/app/i18n/translations/pricing.locale.ts +397 -0
- package/app/i18n/translations/privacy.locale.ts +168 -0
- package/app/i18n/translations/seo.locale.ts +129 -0
- package/app/i18n/translations/terms.locale.ts +124 -0
- package/app/i18n/types.ts +6 -0
- package/app/notifications/model.ts +77 -0
- package/app/notifications/notificationSlice.ts +141 -0
- package/app/reducer.ts +36 -0
- package/app/settings/dbActionThunks.ts +34 -0
- package/app/settings/defaultSpacePreference.ts +87 -0
- package/app/settings/settingSlice.tsx +1212 -0
- package/app/settings/settingsRecord.ts +8 -0
- package/app/stateViews/runtime.ts +90 -0
- package/app/store.ts +55 -0
- package/app/theme/colors.ts +280 -0
- package/app/theme/fontPreference.ts +77 -0
- package/app/theme/theme.config.ts +120 -0
- package/app/theme/themeModeBootstrap.ts +123 -0
- package/app/types/appSummary.ts +114 -0
- package/app/types.ts +358 -0
- package/app/utils/appKeys.ts +55 -0
- package/app/utils/async.ts +28 -0
- package/app/utils/desktopAgentRuntimeTurnClient.ts +73 -0
- package/app/utils/env.ts +17 -0
- package/app/utils/fileUtils.ts +229 -0
- package/app/utils/imageUtils.ts +274 -0
- package/app/utils/myContentItems.ts +289 -0
- package/app/utils/retryAfter.ts +36 -0
- package/app/utils/retryFetch.ts +61 -0
- package/app/utils/toast.ts +3 -0
- package/auth/action/signUpAction.ts +227 -0
- package/auth/adminPermissions.ts +18 -0
- package/auth/authSlice.ts +531 -0
- package/auth/client/loginRequest.ts +14 -0
- package/auth/resetAuthScopedClientState.ts +27 -0
- package/auth/routes.ts +178 -0
- package/auth/token.ts +63 -0
- package/auth/types.ts +40 -0
- package/chat/chat.locale.ts +813 -0
- package/chat/dialog/actions/addCybotAction.ts +52 -0
- package/chat/dialog/actions/addReferenceKeysAction.ts +62 -0
- package/chat/dialog/actions/builtinDialogLlm.ts +35 -0
- package/chat/dialog/actions/cleanupCliSession.ts +40 -0
- package/chat/dialog/actions/createDialogAction.ts +379 -0
- package/chat/dialog/actions/createScheduledTaskAction.ts +78 -0
- package/chat/dialog/actions/handleSendMessageAction.ts +197 -0
- package/chat/dialog/actions/handleSendMessageResolver.ts +27 -0
- package/chat/dialog/actions/removeCybotAction.ts +6 -0
- package/chat/dialog/actions/removeDialogAgentAction.ts +44 -0
- package/chat/dialog/actions/replacePrimaryCybotAction.ts +6 -0
- package/chat/dialog/actions/setPrimaryDialogAgentAction.ts +52 -0
- package/chat/dialog/actions/updateDialogSummaryAction.ts +430 -0
- package/chat/dialog/actions/updateDialogTitleAction.ts +151 -0
- package/chat/dialog/actions/updateDialogTitlePolicy.ts +30 -0
- package/chat/dialog/actions/updateTokensAction.ts +233 -0
- package/chat/dialog/dialogAgents.ts +72 -0
- package/chat/dialog/dialogSlice.ts +872 -0
- package/chat/dialog/dialogTitle.ts +81 -0
- package/chat/dialog/dialogTokenStats.ts +12 -0
- package/chat/dialog/dialogUrl.ts +6 -0
- package/chat/dialog/goal.ts +108 -0
- package/chat/dialog/objectAssistantRegistry.ts +286 -0
- package/chat/dialog/schedule.ts +17 -0
- package/chat/messages/fetchAndCacheMessages.ts +119 -0
- package/chat/messages/fetchConvMsgs.ts +51 -0
- package/chat/messages/fileUrl.ts +13 -0
- package/chat/messages/messageAgent.ts +8 -0
- package/chat/messages/messageContent.ts +199 -0
- package/chat/messages/messageContract.ts +88 -0
- package/chat/messages/messageSlice.ts +1367 -0
- package/chat/messages/toolThunks.ts +625 -0
- package/cli/agentAliases.ts +2 -1
- package/cli/agentRunCommand.ts +10 -32
- package/cli/agentRuntimeLocal.ts +1 -0
- package/cli/client/agentRun.ts +67 -95
- package/cli/client/localRuntimeAdapter.ts +323 -54
- package/cli/commandRegistry.ts +2 -2
- package/cli/machineWsRunDispatch.ts +51 -6
- package/cli/offlineMarxistsAgentCommand.ts +6 -4
- package/client/agentConfigResolver.test.ts +2 -2
- package/client/agentRun.test.ts +175 -57
- package/client/agentRun.ts +67 -95
- package/client/localRuntimeAdapter.test.ts +682 -37
- package/client/localRuntimeAdapter.ts +323 -54
- package/client/localRuntimeDryRun.test.ts +23 -9
- package/client/localToolPolicy.test.ts +4 -4
- package/commandRegistry.ts +2 -2
- package/core/builtinAgents.ts +209 -0
- package/core/config.ts +15 -0
- package/core/crypto.ts +51 -0
- package/core/generateKeyPairFromSeedV1.ts +15 -0
- package/core/generateMainKey.ts +22 -0
- package/core/init.ts +41 -0
- package/core/localOrigins.ts +8 -0
- package/core/password.ts +13 -0
- package/core/prefix.ts +23 -0
- package/create/editor/transforms/fromMarkdown/index.ts +260 -0
- package/create/editor/transforms/fromMarkdown/inline.ts +285 -0
- package/create/editor/transforms/fromMarkdown/table.ts +130 -0
- package/create/editor/transforms/markdownToSlate.ts +24 -0
- package/create/editor/transforms/slateToRenderMarkdown.ts +218 -0
- package/create/editor/transforms/slateToSimplifiedMarkdown.ts +224 -0
- package/create/editor/transforms/slateToText.ts +33 -0
- package/create/editor/utils/slateUtils.ts +233 -0
- package/create/space/addSpaceAction.ts +193 -0
- package/create/space/category/categoryActions.ts +427 -0
- package/create/space/changeSpaceAction.ts +36 -0
- package/create/space/constants.ts +8 -0
- package/create/space/content/addContentAction.ts +116 -0
- package/create/space/content/contentThunks.ts +90 -0
- package/create/space/content/deleteContentFromSpaceAction.ts +187 -0
- package/create/space/content/deleteMultipleContentAction.ts +112 -0
- package/create/space/content/moveContentAction.ts +285 -0
- package/create/space/content/updateContentCategoryAction.ts +154 -0
- package/create/space/content/updateContentTitleAction.ts +151 -0
- package/create/space/content/uploadAndAddFileToSpaceAction.ts +98 -0
- package/create/space/contentKeyUtils.ts +117 -0
- package/create/space/deleteSpaceAction.ts +276 -0
- package/create/space/fetchSpaceAction.ts +70 -0
- package/create/space/fetchSpaceSidebarStateAction.ts +26 -0
- package/create/space/loadDefaultSpaceAction.ts +57 -0
- package/create/space/member/addMemberAction.ts +79 -0
- package/create/space/member/fetchUserSpaceMembershipsAction.ts +386 -0
- package/create/space/member/memberThunks.ts +47 -0
- package/create/space/member/removeMemberAction.ts +67 -0
- package/create/space/resolvePreferredSpaceId.ts +113 -0
- package/create/space/sidebarVisibleTypes.ts +241 -0
- package/create/space/space.locale.ts +1087 -0
- package/create/space/spaceAccess.ts +182 -0
- package/create/space/spaceCollapsedState.ts +54 -0
- package/create/space/spaceKeys.ts +65 -0
- package/create/space/spaceSlice.ts +328 -0
- package/create/space/spaceThunks.ts +410 -0
- package/create/space/types.ts +27 -0
- package/create/space/updateSpaceAction.ts +107 -0
- package/create/space/utils/permissions.ts +47 -0
- package/create/types.ts +21 -0
- package/database/actions/agentReadResolution.ts +33 -0
- package/database/actions/common.ts +243 -0
- package/database/actions/deleteFile.ts +40 -0
- package/database/actions/fileContent.ts +125 -0
- package/database/actions/patch.ts +155 -0
- package/database/actions/read.ts +358 -0
- package/database/actions/readAndWait.ts +260 -0
- package/database/actions/readRequestManager.ts +120 -0
- package/database/actions/readResolution.ts +125 -0
- package/database/actions/remove.ts +94 -0
- package/database/actions/replication.ts +477 -0
- package/database/actions/upload.ts +186 -0
- package/database/actions/upsert.ts +56 -0
- package/database/actions/write.ts +146 -0
- package/database/authority/ownerKey.ts +80 -0
- package/database/authority/recordAuthority.ts +67 -0
- package/database/authority/userAuthorityRegistry.ts +54 -0
- package/database/client/fetchUserData.ts +61 -0
- package/database/dbActionThunks.ts +1 -0
- package/database/dbSlice.ts +149 -0
- package/database/fileRing.ts +51 -0
- package/database/fileStorage.ts +232 -0
- package/database/fileUrl.ts +34 -0
- package/database/keys.ts +767 -0
- package/database/queryPrefixes.ts +14 -0
- package/database/requests.ts +443 -0
- package/database/runtimeServerContext.ts +54 -0
- package/database/server/levelAuthorityStore.ts +20 -1
- package/database/tenantPlacement.ts +57 -0
- package/database/userPreferenceRegister.ts +131 -0
- package/database/utils/ulid.ts +1 -0
- package/integrations/anthropic/anthropicModels.ts +47 -0
- package/integrations/deepseek/models.ts +37 -0
- package/integrations/google/models.ts +341 -0
- package/integrations/openai/chatCompletionStreamMode.ts +10 -0
- package/integrations/openai/filterAndCleanMessages.ts +284 -0
- package/integrations/openai/flexTier.ts +102 -0
- package/integrations/openai/generateOpenAIRequestBody.ts +274 -0
- package/integrations/openai/generateResponseRequestBody.ts +77 -0
- package/integrations/openai/models.ts +271 -0
- package/integrations/openai/providerBodyCompatibility.ts +23 -0
- package/integrations/openai/responsesHelpers.ts +297 -0
- package/integrations/x-reader/types.ts +109 -0
- package/integrations/xai/models.ts +13 -0
- package/integrations/xhs-reader/analyze/profileAnalyzer.ts +205 -0
- package/integrations/xhs-reader/backends/playwrightProfileCollector.ts +624 -0
- package/integrations/xhs-reader/bridge/readXhsProfileWithBridge.ts +227 -0
- package/integrations/xhs-reader/client/xhsWebApiClient.ts +229 -0
- package/integrations/xhs-reader/normalize.ts +390 -0
- package/integrations/xhs-reader/orchestrator.ts +178 -0
- package/integrations/xhs-reader/redaction.ts +68 -0
- package/integrations/xhs-reader/types.ts +244 -0
- package/integrations/xhs-reader/url.ts +57 -0
- package/machineWsRunDispatch.ts +51 -6
- package/offlineMarxistsAgentCommand.ts +6 -4
- package/package.json +430 -3
- package/render/page/createPageAction.ts +183 -0
- package/render/page/docSlice.ts +468 -0
- package/render/page/types.ts +17 -0
- package/render/table/createTableAction.ts +270 -0
- package/render/table/deleteTableAction.ts +193 -0
- package/render/table/fetchAndCacheTableRows.ts +174 -0
- package/render/table/tableSlice.ts +1106 -0
- package/render/table/toolValueUtils.ts +363 -0
- package/render/table/types.ts +252 -0
- package/render/table/utils/tableSerialization.ts +50 -0
- package/server/handlers/agentRun/types.ts +104 -0
- package/share/action.ts +225 -0
- package/share/helpers.ts +302 -0
- package/share/keys.ts +243 -0
- package/share/publicSharePolicy.ts +27 -0
- package/share/shareSlice.ts +53 -0
- 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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
378
|
-
|
|
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(
|
|
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: ["
|
|
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(
|
|
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: ["
|
|
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).
|
|
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: ["
|
|
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: "
|
|
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
|
-
|
|
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: "
|
|
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("
|
|
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
|
|
1214
|
+
const result = await adapter.executeTool({
|
|
1056
1215
|
id: "call-1",
|
|
1057
1216
|
name: "execShell",
|
|
1058
1217
|
arguments: "{\"cmd\":\"pwd\"}",
|
|
1059
|
-
})
|
|
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
|
|
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
|
|
1709
|
+
test("runs execShell locally by default", async () => {
|
|
1360
1710
|
const adapter = createCliLocalRuntimeAdapter({
|
|
1361
|
-
env: {
|
|
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
|
|
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'
|
|
1430
|
-
: "
|
|
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("
|
|
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: ["
|
|
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: "
|
|
2360
|
+
name: "writeFile",
|
|
1716
2361
|
arguments: JSON.stringify({
|
|
1717
2362
|
path: "src/app.ts",
|
|
1718
2363
|
content: "export const cliValue = 1;\n",
|