nolo-cli 0.1.40 → 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/agent-runtime/hybridRecordStore.ts +5 -3
- 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 +65 -6
- 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/client/agentRun.ts +27 -8
- package/cli/client/localRuntimeAdapter.ts +144 -28
- package/client/agentRun.test.ts +52 -0
- package/client/agentRun.ts +27 -8
- package/client/localRuntimeAdapter.test.ts +437 -6
- package/client/localRuntimeAdapter.ts +144 -28
- 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/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/package.json +430 -4
- 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
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { ContentType } from "../../app/types";
|
|
2
|
+
import { addContentAction } from "../../create/space/content/addContentAction";
|
|
3
|
+
import { selectCurrentSpaceId } from "../../create/space/spaceSlice";
|
|
4
|
+
import { buildDatabaseFileContentUrl } from "../../database/fileUrl";
|
|
5
|
+
import { fileKey } from "../../database/keys";
|
|
6
|
+
import { selectCurrentServer } from "../../app/settings/settingSlice";
|
|
7
|
+
import { selectUserId } from "../../auth/authSlice";
|
|
8
|
+
import { callToolApi } from "./toolApiClient";
|
|
9
|
+
|
|
10
|
+
type RemotionRenderVideoArgs = {
|
|
11
|
+
template?: "mobile-product" | "landscape-product" | "nolo-mobile-product" | "nolo-landscape-product";
|
|
12
|
+
brand?: string;
|
|
13
|
+
hook?: string;
|
|
14
|
+
headline?: string;
|
|
15
|
+
subline?: string;
|
|
16
|
+
prompt?: string;
|
|
17
|
+
cta?: string;
|
|
18
|
+
outputName?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const remotionRenderVideoFunctionSchema = {
|
|
22
|
+
name: "remotionRenderVideo",
|
|
23
|
+
description: [
|
|
24
|
+
"使用平台内 Remotion 模板渲染产品视频,并保存为可复用 MP4 文件。",
|
|
25
|
+
"",
|
|
26
|
+
"适用场景:",
|
|
27
|
+
"- 用户要生成手机传播视频、产品介绍视频、欢迎页短片、Agent/AI 工作流演示视频。",
|
|
28
|
+
"- 需要把文案、标题、输入框示例等参数化后产出 MP4。",
|
|
29
|
+
"",
|
|
30
|
+
"当前模板:",
|
|
31
|
+
"- mobile-product: 9:16 竖版,适合手机传播。",
|
|
32
|
+
"- landscape-product: 16:9 横版,适合官网/演示页。",
|
|
33
|
+
"- 兼容旧别名 nolo-mobile-product / nolo-landscape-product。",
|
|
34
|
+
].join("\n"),
|
|
35
|
+
parameters: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
template: {
|
|
39
|
+
type: "string",
|
|
40
|
+
enum: ["mobile-product", "landscape-product", "nolo-mobile-product", "nolo-landscape-product"],
|
|
41
|
+
description: "视频模板。默认 mobile-product。",
|
|
42
|
+
},
|
|
43
|
+
brand: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "品牌名,例如 Nolo.Chat、你的产品名、店铺名或活动名。",
|
|
46
|
+
},
|
|
47
|
+
hook: {
|
|
48
|
+
type: "string",
|
|
49
|
+
description: "竖版视频首屏钩子标题,例如“把一句想法,推进成结果”。",
|
|
50
|
+
},
|
|
51
|
+
headline: {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: "横版视频主标题;竖版缺少 hook 时也会作为 hook 使用。",
|
|
54
|
+
},
|
|
55
|
+
subline: {
|
|
56
|
+
type: "string",
|
|
57
|
+
description: "横版视频副标题。",
|
|
58
|
+
},
|
|
59
|
+
prompt: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "手机输入框里逐字打出的示例需求。",
|
|
62
|
+
},
|
|
63
|
+
cta: {
|
|
64
|
+
type: "string",
|
|
65
|
+
description: "结尾行动号召,例如“开始体验”。",
|
|
66
|
+
},
|
|
67
|
+
outputName: {
|
|
68
|
+
type: "string",
|
|
69
|
+
description: "输出文件名,建议以 .mp4 结尾。",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const remotionRenderVideoFunc = async (
|
|
76
|
+
args: RemotionRenderVideoArgs,
|
|
77
|
+
thunkApi: any
|
|
78
|
+
): Promise<{ rawData: any; displayData: string; llmContext?: string }> => {
|
|
79
|
+
const result: any = await callToolApi(
|
|
80
|
+
thunkApi,
|
|
81
|
+
"/api/remotion/render",
|
|
82
|
+
{
|
|
83
|
+
template: args.template || "mobile-product",
|
|
84
|
+
brand: args.brand,
|
|
85
|
+
hook: args.hook,
|
|
86
|
+
headline: args.headline,
|
|
87
|
+
subline: args.subline,
|
|
88
|
+
prompt: args.prompt,
|
|
89
|
+
cta: args.cta,
|
|
90
|
+
outputName: args.outputName,
|
|
91
|
+
},
|
|
92
|
+
{ withAuth: true }
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const state = thunkApi.getState();
|
|
96
|
+
const userId = selectUserId(state);
|
|
97
|
+
const spaceId = selectCurrentSpaceId(state);
|
|
98
|
+
const currentServer = selectCurrentServer(state);
|
|
99
|
+
const fileId = result?.fileId;
|
|
100
|
+
const metadata = result?.metadata || {};
|
|
101
|
+
const fileDbKey = userId && fileId ? fileKey.single(userId, fileId) : "";
|
|
102
|
+
const url = buildDatabaseFileContentUrl(currentServer, fileDbKey || fileId);
|
|
103
|
+
|
|
104
|
+
if (spaceId && fileDbKey) {
|
|
105
|
+
try {
|
|
106
|
+
await addContentAction(
|
|
107
|
+
{
|
|
108
|
+
spaceId,
|
|
109
|
+
contentKey: fileDbKey,
|
|
110
|
+
title: metadata.originalName || "Remotion video.mp4",
|
|
111
|
+
type: ContentType.FILE,
|
|
112
|
+
fileCategory: "video",
|
|
113
|
+
} as any,
|
|
114
|
+
{ dispatch: thunkApi.dispatch, getState: thunkApi.getState }
|
|
115
|
+
);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.warn("[remotionRenderVideoFunc] Failed to add video to space:", error);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const displayLines = [
|
|
122
|
+
result?.text || "已使用 Remotion 生成视频。",
|
|
123
|
+
fileId ? `- fileId: ${fileId}` : "",
|
|
124
|
+
fileDbKey ? `- fileDbKey: ${fileDbKey}` : "",
|
|
125
|
+
url ? `- url: ${url}` : "",
|
|
126
|
+
metadata?.size ? `- size: ${metadata.size} bytes` : "",
|
|
127
|
+
result?.template ? `- template: ${result.template}` : "",
|
|
128
|
+
].filter(Boolean);
|
|
129
|
+
|
|
130
|
+
const llmContext = [
|
|
131
|
+
"The Remotion video tool produced a reusable video file.",
|
|
132
|
+
"Reuse these exact references when mentioning or embedding the video:",
|
|
133
|
+
fileId ? `- fileId: ${fileId}` : "",
|
|
134
|
+
fileDbKey ? `- fileDbKey: ${fileDbKey}` : "",
|
|
135
|
+
url ? `- url: ${url}` : "",
|
|
136
|
+
metadata?.originalName ? `- name: ${metadata.originalName}` : "",
|
|
137
|
+
result?.template ? `- template: ${result.template}` : "",
|
|
138
|
+
]
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.join("\n");
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
rawData: {
|
|
144
|
+
...result,
|
|
145
|
+
fileDbKey,
|
|
146
|
+
url,
|
|
147
|
+
},
|
|
148
|
+
displayData: displayLines.join("\n"),
|
|
149
|
+
llmContext,
|
|
150
|
+
};
|
|
151
|
+
};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { extractCustomId } from "../../core/prefix";
|
|
2
|
+
import { selectRuntimeSnapshot } from "../../app/stateViews/runtime";
|
|
3
|
+
import {
|
|
4
|
+
buildDialogMessageSearchResults,
|
|
5
|
+
clampDialogSearchNumber,
|
|
6
|
+
formatDialogMessageSearchDisplay,
|
|
7
|
+
normalizeDialogSearchText,
|
|
8
|
+
type DialogMessageSearchRecord,
|
|
9
|
+
} from "./dialogMessageSearch";
|
|
10
|
+
|
|
11
|
+
type SearchDialogMessagesArgs = {
|
|
12
|
+
dialogKey: string;
|
|
13
|
+
query: string;
|
|
14
|
+
limit?: number;
|
|
15
|
+
scanLimit?: number;
|
|
16
|
+
contextMessages?: number;
|
|
17
|
+
role?: "user" | "assistant" | "tool" | "system";
|
|
18
|
+
includeTools?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const MAX_LIMIT = 10;
|
|
22
|
+
const MAX_CONTEXT_MESSAGES = 3;
|
|
23
|
+
const MAX_CONTENT_CHARS = 1800;
|
|
24
|
+
const CONTEXT_CONTENT_CHARS = 600;
|
|
25
|
+
const SERVER_SCAN_LIMIT = 500;
|
|
26
|
+
|
|
27
|
+
const getMessageSortValue = (message: DialogMessageSearchRecord) => {
|
|
28
|
+
const createdAt = message.createdAt;
|
|
29
|
+
if (typeof createdAt === "number") return createdAt;
|
|
30
|
+
if (typeof createdAt === "string") {
|
|
31
|
+
const parsed = Date.parse(createdAt);
|
|
32
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
33
|
+
}
|
|
34
|
+
const id = normalizeDialogSearchText(message.id);
|
|
35
|
+
return id ? id : normalizeDialogSearchText(message.dbKey);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
async function collectDialogMessages(db: any, dialogId: string): Promise<DialogMessageSearchRecord[]> {
|
|
39
|
+
if (!db?.iterator) return [];
|
|
40
|
+
const prefix = `dialog-${dialogId}-msg-`;
|
|
41
|
+
let iterator = db.iterator({
|
|
42
|
+
gte: prefix,
|
|
43
|
+
lte: `${prefix}\uffff`,
|
|
44
|
+
});
|
|
45
|
+
if (iterator && typeof iterator.then === "function") {
|
|
46
|
+
iterator = await iterator;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const messages: DialogMessageSearchRecord[] = [];
|
|
50
|
+
for await (const [key, value] of iterator) {
|
|
51
|
+
if (!value || typeof value !== "object") continue;
|
|
52
|
+
messages.push({
|
|
53
|
+
...(value as DialogMessageSearchRecord),
|
|
54
|
+
dbKey: (value as DialogMessageSearchRecord).dbKey || String(key),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return messages.sort((a, b) => {
|
|
59
|
+
const left = getMessageSortValue(a);
|
|
60
|
+
const right = getMessageSortValue(b);
|
|
61
|
+
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
62
|
+
return String(left).localeCompare(String(right));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function fetchDialogMessagesFromServer(args: {
|
|
67
|
+
serverBase: string;
|
|
68
|
+
token?: string;
|
|
69
|
+
dialogId: string;
|
|
70
|
+
limit: number;
|
|
71
|
+
}): Promise<DialogMessageSearchRecord[]> {
|
|
72
|
+
const serverBase = args.serverBase.replace(/\/+$/, "");
|
|
73
|
+
if (!serverBase || !args.token) return [];
|
|
74
|
+
|
|
75
|
+
const response = await fetch(`${serverBase}/rpc/getConvMsgs`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
Authorization: `Bearer ${args.token}`,
|
|
79
|
+
"Content-Type": "application/json",
|
|
80
|
+
},
|
|
81
|
+
body: JSON.stringify({ dialogId: args.dialogId, limit: args.limit }),
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) return [];
|
|
84
|
+
|
|
85
|
+
const newestFirst = await response.json();
|
|
86
|
+
if (!Array.isArray(newestFirst)) return [];
|
|
87
|
+
return [...newestFirst].reverse().map((message) => ({
|
|
88
|
+
...(message as DialogMessageSearchRecord),
|
|
89
|
+
dbKey: (message as DialogMessageSearchRecord).dbKey,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function collectBestAvailableDialogMessages(
|
|
94
|
+
db: any,
|
|
95
|
+
dialogId: string,
|
|
96
|
+
thunkApi: any,
|
|
97
|
+
scanLimit: number,
|
|
98
|
+
): Promise<DialogMessageSearchRecord[]> {
|
|
99
|
+
const localMessages = await collectDialogMessages(db, dialogId);
|
|
100
|
+
const state = thunkApi?.getState?.();
|
|
101
|
+
const runtime = state ? selectRuntimeSnapshot(state) : null;
|
|
102
|
+
const serverBases = Array.from(new Set([
|
|
103
|
+
runtime?.localRuntimeOrigin,
|
|
104
|
+
runtime?.currentServer,
|
|
105
|
+
...(Array.isArray(runtime?.syncServers) ? runtime.syncServers : []),
|
|
106
|
+
].filter((base): base is string => typeof base === "string" && base.trim().length > 0)));
|
|
107
|
+
|
|
108
|
+
let bestMessages = localMessages;
|
|
109
|
+
for (const serverBase of serverBases) {
|
|
110
|
+
const serverMessages = await fetchDialogMessagesFromServer({
|
|
111
|
+
serverBase,
|
|
112
|
+
token: runtime?.currentToken,
|
|
113
|
+
dialogId,
|
|
114
|
+
limit: scanLimit,
|
|
115
|
+
}).catch(() => []);
|
|
116
|
+
if (serverMessages.length > bestMessages.length) {
|
|
117
|
+
bestMessages = serverMessages;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return bestMessages;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const searchDialogMessagesFunctionSchema = {
|
|
125
|
+
name: "searchDialogMessages",
|
|
126
|
+
description: [
|
|
127
|
+
"Search original messages inside a specific dialog by exact or fuzzy text.",
|
|
128
|
+
"Use this when a user asks for an exact old message, original wording, who said what, why a decision was made, early-history detail, failed attempts, files or tool evidence, or comparison with prior work from an attached conversation.",
|
|
129
|
+
"Prefer this over answering from a lossy dialog summary when the user needs evidence, provenance, or a specific prior detail.",
|
|
130
|
+
"Returns matching message ids, roles, clipped original content, and nearby context without loading the full dialog into the model context.",
|
|
131
|
+
].join(" "),
|
|
132
|
+
parameters: {
|
|
133
|
+
type: "object",
|
|
134
|
+
properties: {
|
|
135
|
+
dialogKey: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "Dialog dbKey, for example dialog-userId-01ABC...",
|
|
138
|
+
},
|
|
139
|
+
query: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "Text to search for in original message content.",
|
|
142
|
+
},
|
|
143
|
+
limit: {
|
|
144
|
+
type: "number",
|
|
145
|
+
description: `Maximum matches to return. Capped at ${MAX_LIMIT}.`,
|
|
146
|
+
},
|
|
147
|
+
scanLimit: {
|
|
148
|
+
type: "number",
|
|
149
|
+
description: `Maximum messages to scan when fetching from a server. Capped at ${SERVER_SCAN_LIMIT}.`,
|
|
150
|
+
},
|
|
151
|
+
contextMessages: {
|
|
152
|
+
type: "number",
|
|
153
|
+
description: `Number of neighboring messages before/after each match. Capped at ${MAX_CONTEXT_MESSAGES}.`,
|
|
154
|
+
},
|
|
155
|
+
role: {
|
|
156
|
+
type: "string",
|
|
157
|
+
enum: ["user", "assistant", "tool", "system"],
|
|
158
|
+
description: "Optional role filter.",
|
|
159
|
+
},
|
|
160
|
+
includeTools: {
|
|
161
|
+
type: "boolean",
|
|
162
|
+
description: "Whether tool messages may match. Defaults to true.",
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
required: ["dialogKey", "query"],
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export async function searchDialogMessagesFunc(
|
|
170
|
+
args: SearchDialogMessagesArgs,
|
|
171
|
+
_thunkApi: any,
|
|
172
|
+
context?: { db?: any }
|
|
173
|
+
) {
|
|
174
|
+
const dialogKey = normalizeDialogSearchText(args?.dialogKey);
|
|
175
|
+
const query = normalizeDialogSearchText(args?.query);
|
|
176
|
+
if (!dialogKey.startsWith("dialog-")) {
|
|
177
|
+
throw new Error("searchDialogMessages requires a dialog-* dbKey.");
|
|
178
|
+
}
|
|
179
|
+
if (!query) {
|
|
180
|
+
throw new Error("searchDialogMessages requires a non-empty query.");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const db = context?.db ?? _thunkApi?.extra?.db;
|
|
184
|
+
if (!db) {
|
|
185
|
+
throw new Error("searchDialogMessages cannot access the local message database.");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const dialogId = extractCustomId(dialogKey) || dialogKey.split("-").at(-1) || "";
|
|
189
|
+
const scanLimit = clampDialogSearchNumber(
|
|
190
|
+
args.scanLimit,
|
|
191
|
+
SERVER_SCAN_LIMIT,
|
|
192
|
+
1,
|
|
193
|
+
SERVER_SCAN_LIMIT,
|
|
194
|
+
);
|
|
195
|
+
const messages = await collectBestAvailableDialogMessages(db, dialogId, _thunkApi, scanLimit);
|
|
196
|
+
const limit = clampDialogSearchNumber(args.limit, 5, 1, MAX_LIMIT);
|
|
197
|
+
const contextMessages = clampDialogSearchNumber(args.contextMessages, 1, 0, MAX_CONTEXT_MESSAGES);
|
|
198
|
+
|
|
199
|
+
const results = buildDialogMessageSearchResults({
|
|
200
|
+
messages,
|
|
201
|
+
query,
|
|
202
|
+
limit,
|
|
203
|
+
contextMessages,
|
|
204
|
+
role: args.role,
|
|
205
|
+
includeTools: args.includeTools,
|
|
206
|
+
contentClipChars: MAX_CONTENT_CHARS,
|
|
207
|
+
contextClipChars: CONTEXT_CONTENT_CHARS,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const displayData = formatDialogMessageSearchDisplay({ dialogKey, query, results });
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
rawData: {
|
|
214
|
+
success: true,
|
|
215
|
+
dialogKey,
|
|
216
|
+
query,
|
|
217
|
+
scannedMessages: messages.length,
|
|
218
|
+
matches: results,
|
|
219
|
+
},
|
|
220
|
+
displayData,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// ai/tools/searchWorkspaceTool.ts
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildMyContentItemsFromUserData,
|
|
5
|
+
MY_CONTENT_USER_DATA_TYPES,
|
|
6
|
+
type MyContentListItem,
|
|
7
|
+
} from "../../app/utils/myContentItems";
|
|
8
|
+
import type { SpaceContent, SpaceData, SpaceMemberWithSpaceInfo } from "../../app/types";
|
|
9
|
+
import { fetchUserData } from "../../database/client/fetchUserData";
|
|
10
|
+
import { getUserDataItemTimestamp, mergeAndDedupUserData } from "../../database/userDataMerge";
|
|
11
|
+
|
|
12
|
+
type SearchWorkspaceArgs = { query: string };
|
|
13
|
+
|
|
14
|
+
type SearchWorkspaceResultItem = {
|
|
15
|
+
title: string;
|
|
16
|
+
type: string;
|
|
17
|
+
contentKey: string;
|
|
18
|
+
spaceId: string | null;
|
|
19
|
+
spaceName?: string;
|
|
20
|
+
createdAt?: string | number;
|
|
21
|
+
updatedAt?: string | number;
|
|
22
|
+
serverOrigin?: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type SearchWorkspaceResult = {
|
|
26
|
+
rawData: { success: true; contents: SearchWorkspaceResultItem[] };
|
|
27
|
+
displayData: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type SearchWorkspaceState = {
|
|
31
|
+
auth?: {
|
|
32
|
+
currentUser?: {
|
|
33
|
+
userId?: string | null;
|
|
34
|
+
} | null;
|
|
35
|
+
};
|
|
36
|
+
settings?: {
|
|
37
|
+
currentServer?: string;
|
|
38
|
+
};
|
|
39
|
+
space: {
|
|
40
|
+
currentSpaceId: string | null;
|
|
41
|
+
currentSpace: SpaceData | null;
|
|
42
|
+
memberSpaces: SpaceMemberWithSpaceInfo[] | null;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type SearchWorkspaceThunkApi = {
|
|
47
|
+
getState: () => SearchWorkspaceState;
|
|
48
|
+
dispatch: (action: unknown) => unknown;
|
|
49
|
+
extra: {
|
|
50
|
+
db: any | null;
|
|
51
|
+
tokenManager: any | null;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const selectCurrentSpaceIdFromState = (state: SearchWorkspaceState) =>
|
|
56
|
+
state.space.currentSpaceId;
|
|
57
|
+
|
|
58
|
+
const selectCurrentSpaceFromState = (state: SearchWorkspaceState) =>
|
|
59
|
+
state.space.currentSpace;
|
|
60
|
+
|
|
61
|
+
const selectAllMemberSpacesFromState = (state: SearchWorkspaceState) => {
|
|
62
|
+
const memberSpaces = state.space.memberSpaces ?? [];
|
|
63
|
+
return [...memberSpaces].sort((a, b) => {
|
|
64
|
+
const aUpdatedAt =
|
|
65
|
+
a.spaceUpdatedAt ??
|
|
66
|
+
(a as any).memberUpdatedAt ??
|
|
67
|
+
(a as any).updatedAt ??
|
|
68
|
+
(a as any).createdAt ??
|
|
69
|
+
a.joinedAt ??
|
|
70
|
+
0;
|
|
71
|
+
const bUpdatedAt =
|
|
72
|
+
b.spaceUpdatedAt ??
|
|
73
|
+
(b as any).memberUpdatedAt ??
|
|
74
|
+
(b as any).updatedAt ??
|
|
75
|
+
(b as any).createdAt ??
|
|
76
|
+
b.joinedAt ??
|
|
77
|
+
0;
|
|
78
|
+
return bUpdatedAt - aUpdatedAt;
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const searchWorkspaceFunctionSchema = {
|
|
83
|
+
name: "search_workspace",
|
|
84
|
+
description: "在当前空间(Workspace)中搜索页面、表格等内容。",
|
|
85
|
+
parameters: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: {
|
|
88
|
+
query: {
|
|
89
|
+
type: "string",
|
|
90
|
+
description: "搜索关键词。将匹配标题和文件名。",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
required: ["query"],
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const searchAllSpacesFunctionSchema = {
|
|
98
|
+
name: "search_all_spaces",
|
|
99
|
+
description:
|
|
100
|
+
"在当前设备已同步的全部内容中搜索当前用户的数据(等同于全部视图 Recent 的内容语义),并返回所属空间(如有)。",
|
|
101
|
+
parameters: searchWorkspaceFunctionSchema.parameters,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const normalizeQuery = (value: unknown) => String(value || "").trim().toLowerCase();
|
|
105
|
+
|
|
106
|
+
const toSearchResultItem = (
|
|
107
|
+
item:
|
|
108
|
+
| Pick<
|
|
109
|
+
MyContentListItem,
|
|
110
|
+
"title" | "type" | "contentKey" | "spaceId" | "spaceName" | "createdAt" | "updatedAt" | "serverOrigin"
|
|
111
|
+
>
|
|
112
|
+
| (SpaceContent & { spaceId: string; spaceName?: string })
|
|
113
|
+
): SearchWorkspaceResultItem => ({
|
|
114
|
+
title: String(item.title || item.contentKey || "").trim(),
|
|
115
|
+
type: String(item.type || "").trim(),
|
|
116
|
+
contentKey: String(item.contentKey || "").trim(),
|
|
117
|
+
spaceId: item.spaceId ?? null,
|
|
118
|
+
...(item.spaceName ? { spaceName: item.spaceName } : {}),
|
|
119
|
+
...(item.createdAt !== undefined ? { createdAt: item.createdAt } : {}),
|
|
120
|
+
...(item.updatedAt !== undefined ? { updatedAt: item.updatedAt } : {}),
|
|
121
|
+
...(typeof item.serverOrigin === "string" && item.serverOrigin.trim().length > 0
|
|
122
|
+
? { serverOrigin: item.serverOrigin }
|
|
123
|
+
: {}),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const searchSpaceContents = (
|
|
127
|
+
space: SpaceData,
|
|
128
|
+
query: string,
|
|
129
|
+
options?: { spaceName?: string }
|
|
130
|
+
): SearchWorkspaceResultItem[] => {
|
|
131
|
+
const kw = normalizeQuery(query);
|
|
132
|
+
const allContents = Object.values(space.contents || {});
|
|
133
|
+
|
|
134
|
+
return allContents
|
|
135
|
+
.filter((content): content is SpaceContent => {
|
|
136
|
+
if (!content) return false;
|
|
137
|
+
const titleMatch = (content.title ?? "").toLowerCase().includes(kw);
|
|
138
|
+
const keyMatch = (content.contentKey ?? "").toLowerCase().includes(kw);
|
|
139
|
+
return titleMatch || keyMatch;
|
|
140
|
+
})
|
|
141
|
+
.map((content) =>
|
|
142
|
+
toSearchResultItem({
|
|
143
|
+
...content,
|
|
144
|
+
spaceId: space.id,
|
|
145
|
+
...(options?.spaceName ? { spaceName: options.spaceName } : {}),
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const matchesMyContentSearch = (
|
|
151
|
+
query: string,
|
|
152
|
+
item: Pick<MyContentListItem, "title" | "type" | "spaceName" | "contentKey">
|
|
153
|
+
) => {
|
|
154
|
+
const kw = normalizeQuery(query);
|
|
155
|
+
if (!kw) return false;
|
|
156
|
+
return [item.title, item.type, item.spaceName, item.contentKey].some((value) =>
|
|
157
|
+
normalizeQuery(value).includes(kw)
|
|
158
|
+
);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const buildScopedDisplayData = (
|
|
162
|
+
query: string,
|
|
163
|
+
results: SearchWorkspaceResultItem[],
|
|
164
|
+
scopeLabel: string
|
|
165
|
+
) => {
|
|
166
|
+
if (results.length === 0) {
|
|
167
|
+
return `未能在${scopeLabel}中找到匹配 "${query}" 的内容。`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const summary = results
|
|
171
|
+
.map((item) => {
|
|
172
|
+
const spaceSuffix = item.spaceName ? ` [${item.spaceName}]` : "";
|
|
173
|
+
return `- ${item.title} (${item.contentKey})${spaceSuffix}`;
|
|
174
|
+
})
|
|
175
|
+
.join("\n");
|
|
176
|
+
|
|
177
|
+
return `在${scopeLabel}中找到 ${results.length} 个匹配项:\n${summary}`;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const loadLocalMyContentResults = async (
|
|
181
|
+
thunkApi: SearchWorkspaceThunkApi,
|
|
182
|
+
state: SearchWorkspaceState
|
|
183
|
+
): Promise<MyContentListItem[]> => {
|
|
184
|
+
const userId = state.auth?.currentUser?.userId?.trim();
|
|
185
|
+
if (!userId) {
|
|
186
|
+
throw new Error("无法搜索全部内容,因为当前用户未登录。");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const db = thunkApi.extra?.db;
|
|
190
|
+
if (!db) {
|
|
191
|
+
throw new Error("无法搜索全部内容,因为本地数据库不可用。");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const localResults = await fetchUserData(db, MY_CONTENT_USER_DATA_TYPES, userId, {
|
|
195
|
+
includeDeleted: true,
|
|
196
|
+
});
|
|
197
|
+
const dedupedRecords = mergeAndDedupUserData(Object.values(localResults).flat(), []);
|
|
198
|
+
const sortedRecords = [...dedupedRecords].sort(
|
|
199
|
+
(a, b) => getUserDataItemTimestamp(b) - getUserDataItemTimestamp(a)
|
|
200
|
+
);
|
|
201
|
+
const memberSpaces = selectAllMemberSpacesFromState(state);
|
|
202
|
+
const spaceNameById = new Map(
|
|
203
|
+
memberSpaces.map((space) => [space.spaceId, space.spaceName || space.spaceId] as const)
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
return buildMyContentItemsFromUserData(
|
|
207
|
+
sortedRecords,
|
|
208
|
+
state.settings?.currentServer || "",
|
|
209
|
+
spaceNameById,
|
|
210
|
+
"我的应用",
|
|
211
|
+
"我的内容"
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* [Executor] 'search_workspace' 工具的执行函数。
|
|
217
|
+
*/
|
|
218
|
+
export async function searchWorkspaceFunc(
|
|
219
|
+
args: SearchWorkspaceArgs,
|
|
220
|
+
thunkApi: SearchWorkspaceThunkApi
|
|
221
|
+
): Promise<SearchWorkspaceResult> {
|
|
222
|
+
const { getState } = thunkApi;
|
|
223
|
+
const state = getState();
|
|
224
|
+
const spaceId = selectCurrentSpaceIdFromState(state);
|
|
225
|
+
|
|
226
|
+
if (!spaceId) {
|
|
227
|
+
throw new Error("无法查询内容,因为当前空间未设定。");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const currentSpace = selectCurrentSpaceFromState(state);
|
|
231
|
+
if (!currentSpace) {
|
|
232
|
+
throw new Error("当前空间数据未找到。");
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const results = searchSpaceContents(currentSpace, args.query, {
|
|
236
|
+
spaceName: currentSpace.name,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const rawData = { success: true, contents: results };
|
|
240
|
+
const displayData = buildScopedDisplayData(args.query, results, "当前空间");
|
|
241
|
+
|
|
242
|
+
return { rawData, displayData };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export async function searchAllSpacesFunc(
|
|
246
|
+
args: SearchWorkspaceArgs,
|
|
247
|
+
thunkApi: SearchWorkspaceThunkApi
|
|
248
|
+
): Promise<SearchWorkspaceResult> {
|
|
249
|
+
const state = thunkApi.getState();
|
|
250
|
+
const items = await loadLocalMyContentResults(thunkApi, state);
|
|
251
|
+
const results = items
|
|
252
|
+
.filter((item) => matchesMyContentSearch(args.query, item))
|
|
253
|
+
.map((item) => toSearchResultItem(item));
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
rawData: { success: true, contents: results },
|
|
257
|
+
displayData: buildScopedDisplayData(args.query, results, "已同步的全部内容"),
|
|
258
|
+
};
|
|
259
|
+
}
|