nolo-cli 0.1.30 → 0.1.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/agent-runtime/agentRecordConfig.ts +0 -2
  2. package/agent-runtime/hostAdapter.ts +0 -1
  3. package/agent-runtime/hostRuntimeCapabilities.ts +7 -0
  4. package/agent-runtime/hostRuntimeConfig.ts +86 -0
  5. package/agent-runtime/index.ts +13 -0
  6. package/agent-runtime/localToolPolicy.ts +13 -6
  7. package/agent-runtime/localWorkspaceTools.ts +333 -30
  8. package/agent-runtime/platformChatProvider.ts +4 -1
  9. package/agent-runtime/runtimeToolPolicy.ts +32 -47
  10. package/agent-runtime/shellCommandPolicy.ts +117 -0
  11. package/agent-runtime/toolGate.ts +38 -0
  12. package/agentRecordCommands.ts +1 -1
  13. package/agentRecordHelpers.ts +35 -20
  14. package/agentRunParsing.ts +18 -5
  15. package/agentRuntimeLocal.ts +10 -0
  16. package/ai/agent/agentRunDialogLineage.ts +56 -0
  17. package/ai/agent/agentSlice.ts +45 -10
  18. package/ai/agent/avatarUtils.ts +1 -1
  19. package/ai/agent/buildSystemPrompt.ts +1 -2
  20. package/ai/agent/cliExecutor.ts +330 -19
  21. package/ai/agent/createAgentSchema.ts +22 -0
  22. package/ai/agent/hooks/fetchPublicAgents.ts +14 -39
  23. package/ai/agent/hooks/usePublicAgents.ts +90 -192
  24. package/ai/agent/publicAgentCatalog.ts +359 -0
  25. package/ai/agent/publicAgentIdentity.ts +76 -0
  26. package/ai/agent/server/fetchPublicAgents.ts +21 -46
  27. package/ai/agent/serverOrigin.ts +7 -0
  28. package/ai/agent/streamAgentChatTurn.ts +23 -21
  29. package/ai/agent/streamAgentChatTurnUtils.ts +292 -6
  30. package/ai/agent/types.ts +2 -0
  31. package/ai/agent/web/agentDisplayUtils.ts +171 -0
  32. package/ai/agent/web/useAgentModelAvatarComponent.ts +32 -0
  33. package/ai/ai.locale.ts +8 -0
  34. package/ai/chat/sendOpenAICompletionsRequest.native.ts +15 -0
  35. package/ai/chat/sendOpenAICompletionsRequest.ts +93 -1
  36. package/ai/chat/sendOpenAIResponseRequest.ts +86 -9
  37. package/ai/chat/updateTotalUsage.ts +7 -0
  38. package/ai/llm/deepinfra.ts +30 -15
  39. package/ai/llm/mistral.ts +3 -4
  40. package/ai/llm/providers.ts +2 -0
  41. package/ai/llm/types.ts +15 -0
  42. package/ai/memory/capture.ts +3 -3
  43. package/ai/memory/consolidate.ts +2 -2
  44. package/ai/memory/delete.ts +4 -3
  45. package/ai/memory/query.ts +3 -3
  46. package/ai/memory/remember.ts +2 -2
  47. package/ai/memory/store.ts +3 -3
  48. package/ai/memory/storeShared.ts +3 -2
  49. package/ai/policy/commercialMultiplier.ts +16 -0
  50. package/ai/token/billingAdminAuditEvent.ts +68 -0
  51. package/ai/token/billingAdminAuditEventWriter.ts +41 -0
  52. package/ai/token/billingAnomaly.ts +90 -0
  53. package/ai/token/billingAnomalyLifecycle.ts +54 -0
  54. package/ai/token/billingAnomalyLifecycleWriter.ts +44 -0
  55. package/ai/token/billingAnomalyWriter.ts +41 -0
  56. package/ai/token/calculatePrice.ts +3 -2
  57. package/ai/token/deepinfraReconciliation.ts +153 -0
  58. package/ai/token/deepinfraRequestIdQuery.ts +92 -0
  59. package/ai/token/externalToolCost.ts +54 -41
  60. package/ai/token/missingUsageEstimate.ts +12 -3
  61. package/ai/token/normalizeUsage.ts +45 -5
  62. package/ai/token/openaiReconciliation.ts +188 -0
  63. package/ai/token/providerBillableEvent.ts +84 -0
  64. package/ai/token/providerBillableEventWriter.ts +36 -0
  65. package/ai/token/providerBillingAnomalyDrilldown.ts +308 -0
  66. package/ai/token/providerBillingDrilldown.ts +361 -0
  67. package/ai/token/providerBillingHealthReport.ts +366 -0
  68. package/ai/token/providerCall.ts +144 -0
  69. package/ai/token/providerCallSweeper.ts +168 -0
  70. package/ai/token/providerCallWriter.ts +33 -0
  71. package/ai/token/providerCredential.ts +89 -0
  72. package/ai/token/providerCredentialAnomaly.ts +154 -0
  73. package/ai/token/providerCredentialLifecycle.ts +59 -0
  74. package/ai/token/providerCredentialLifecycleWriter.ts +44 -0
  75. package/ai/token/providerCredentialRegistry.ts +83 -0
  76. package/ai/token/providerCredentialRegistryCommand.ts +97 -0
  77. package/ai/token/providerCredentialRegistryList.ts +124 -0
  78. package/ai/token/providerCredentialRegistryResolver.ts +150 -0
  79. package/ai/token/providerCredentialRegistryWriter.ts +41 -0
  80. package/ai/token/providerCredentialRotationCommand.ts +102 -0
  81. package/ai/token/providerCredentialRuntime.ts +56 -0
  82. package/ai/token/providerDispatchIntent.ts +67 -0
  83. package/ai/token/providerDispatchIntentWriter.ts +36 -0
  84. package/ai/token/providerGateway.ts +260 -0
  85. package/ai/token/providerReconciliation.ts +148 -0
  86. package/ai/token/providerReconciliationLocal.ts +97 -0
  87. package/ai/token/providerReconciliationRunner.ts +165 -0
  88. package/ai/token/providerReconciliationWriter.ts +41 -0
  89. package/ai/token/ratingResult.ts +202 -0
  90. package/ai/token/ratingResultWriter.ts +33 -0
  91. package/ai/token/serverDialogProjection.ts +5 -3
  92. package/ai/token/serverTokenWriter.ts +11 -3
  93. package/ai/token/types.ts +10 -0
  94. package/ai/tools/agent/callAgentTool.ts +3 -4
  95. package/ai/tools/agent/presets/appBuilderPreset.ts +5 -7
  96. package/ai/tools/agent/runStreamingAgentTool.ts +1 -2
  97. package/ai/tools/agent/streamParallelAgentsTool.ts +2 -3
  98. package/ai/tools/readXPostTool.ts +1 -5
  99. package/app/admin/adminPages.ts +9 -0
  100. package/app/i18n/i18n.config.ts +5 -0
  101. package/app/i18n/translations/pricing.locale.ts +397 -0
  102. package/app/utils/desktopAgentRuntimeStatusClient.ts +5 -4
  103. package/app/utils/desktopAgentRuntimeTurnClient.ts +4 -1
  104. package/app/utils/imageUtils.ts +64 -34
  105. package/auth/adminPermissions.ts +18 -0
  106. package/auth/authSlice.ts +26 -12
  107. package/auth/hooks/useFetchUsers.ts +3 -0
  108. package/auth/routes.ts +46 -0
  109. package/auth/server/accessActivity.ts +4 -3
  110. package/auth/server/adminPermissions.ts +43 -0
  111. package/auth/server/adminUsageReport.ts +375 -0
  112. package/auth/server/billingAnomalies.ts +235 -0
  113. package/auth/server/billingUsageReport.ts +41 -2
  114. package/auth/server/creatorEarningCreditConversion.ts +10 -2
  115. package/auth/server/deduct.ts +14 -7
  116. package/auth/server/delete.ts +10 -2
  117. package/auth/server/disable.ts +4 -3
  118. package/auth/server/emailAutomation.ts +7 -5
  119. package/auth/server/emailDbConfig.ts +4 -2
  120. package/auth/server/emailDelivery.ts +24 -20
  121. package/auth/server/emailDeliveryGuards.ts +10 -7
  122. package/auth/server/emailPreferences.ts +6 -4
  123. package/auth/server/emailReport.ts +6 -4
  124. package/auth/server/emailRuntimeConfig.ts +3 -3
  125. package/auth/server/emailScenarioNotifications.ts +9 -8
  126. package/auth/server/enable.ts +4 -3
  127. package/auth/server/getRechargeHistory.ts +3 -2
  128. package/auth/server/getUser.ts +3 -2
  129. package/auth/server/gptProAccess.ts +44 -0
  130. package/auth/server/inviteReward.ts +10 -7
  131. package/auth/server/listusers.ts +6 -4
  132. package/auth/server/login.ts +2 -2
  133. package/auth/server/productEntitlements.ts +7 -4
  134. package/auth/server/productPurchase.ts +10 -2
  135. package/auth/server/providerBillingDrilldown.ts +47 -0
  136. package/auth/server/providerBillingHealth.ts +71 -0
  137. package/auth/server/providerCredentials.ts +136 -0
  138. package/auth/server/recharge.ts +14 -8
  139. package/auth/server/revokeSessions.ts +4 -3
  140. package/auth/server/route.ts +77 -0
  141. package/auth/server/sendEmail.ts +5 -4
  142. package/auth/server/signup.ts +10 -3
  143. package/auth/server/token.ts +53 -55
  144. package/auth/server/tokenUsageBilling.ts +18 -7
  145. package/auth/server/usageManagementAccess.ts +43 -0
  146. package/auth/server/usageReport.ts +59 -0
  147. package/auth/types.ts +12 -0
  148. package/auth/utils.ts +24 -22
  149. package/authCommands.ts +36 -2
  150. package/buildPublish.ts +3 -1
  151. package/buildPublishArtifactAssembly.ts +62 -1
  152. package/buildPublishImportAnalysis.ts +21 -16
  153. package/chat/dialog/dialogLaunchScope.ts +32 -0
  154. package/chat/dialog/objectAssistantRegistry.ts +2 -2
  155. package/chat/dialog/useCreateDialog.ts +1 -1
  156. package/chat/hooks/useChatInput.ts +41 -10
  157. package/chat/messages/messageSlice.ts +5 -1
  158. package/chat/messages/pendingAttachmentParts.ts +28 -2
  159. package/chat/messages/sendFirstMessage.ts +76 -79
  160. package/chat/messages/types.ts +9 -0
  161. package/chat/messages/web/streamingMarkdownModel.ts +41 -0
  162. package/chat/messages/web/useStreamingReveal.ts +91 -0
  163. package/chat/web/messageInputAgentUi.ts +94 -6
  164. package/cliEnvHelpers.ts +8 -0
  165. package/cliRuntimeDoctorReport.ts +193 -0
  166. package/client/agentConfigResolver.test.ts +0 -2
  167. package/client/agentRun.test.ts +171 -10
  168. package/client/agentRun.ts +44 -637
  169. package/client/agentRunInput.ts +10 -0
  170. package/client/agentRunLocalExecutor.ts +179 -0
  171. package/client/agentRunServerTransport.ts +394 -0
  172. package/client/agentRunTaskRunRecorder.ts +176 -0
  173. package/client/localRuntimeAdapter.test.ts +236 -9
  174. package/client/localRuntimeAdapter.ts +221 -23
  175. package/client/localToolPolicy.test.ts +28 -4
  176. package/connector-experimental/daemonLauncher.ts +38 -4
  177. package/connectorRunArtifact.ts +34 -10
  178. package/connectorWebSocketTarget.ts +9 -5
  179. package/core/builtinAgents.ts +155 -11
  180. package/create/space/contentLabels.ts +1 -1
  181. package/create/space/contentTypeMeta.ts +3 -2
  182. package/create/space/sidebarVisibleTypes.ts +27 -0
  183. package/create/space/space.locale.ts +76 -4
  184. package/database/actions/agentReadResolution.ts +2 -8
  185. package/database/actions/read.ts +11 -9
  186. package/database/actions/readAndWait.ts +10 -5
  187. package/database/server/agentDelegation.ts +3 -2
  188. package/database/server/authorityStoreConformance.ts +209 -0
  189. package/database/server/authorityStoreTypes.ts +31 -0
  190. package/database/server/coreDataProxy.ts +1 -1
  191. package/database/server/dataHandlers.ts +13 -5
  192. package/database/server/db.ts +15 -34
  193. package/database/server/delete.ts +88 -71
  194. package/database/server/emailRepository.ts +11 -9
  195. package/database/server/fileService.ts +2 -1
  196. package/database/server/legacyServerDb.ts +58 -0
  197. package/database/server/levelAuthorityStore.ts +75 -0
  198. package/database/server/memoryAuthorityStore.ts +133 -0
  199. package/database/server/patch.ts +13 -12
  200. package/database/server/query.ts +3 -2
  201. package/database/server/read.ts +33 -30
  202. package/database/server/resourceAccess.ts +7 -5
  203. package/database/server/serverStoreFactory.ts +124 -0
  204. package/database/server/spaceMemberAuthority.ts +3 -2
  205. package/database/server/storeBatchCompat.ts +37 -0
  206. package/database/server/testAuthorityStore.ts +76 -0
  207. package/database/server/write.ts +29 -27
  208. package/integrations/anthropic/anthropicModels.ts +12 -12
  209. package/integrations/deepseek/models.ts +67 -67
  210. package/integrations/google/models.ts +111 -53
  211. package/integrations/openai/models.ts +22 -22
  212. package/integrations/xai/models.ts +1 -1
  213. package/localRuntimeDb.ts +39 -2
  214. package/machineCommandPrompts.ts +2 -0
  215. package/machineCommands.ts +193 -63
  216. package/machineWsRunDispatch.ts +80 -15
  217. package/machineWsSession.ts +39 -2
  218. package/noloReadBridgePrompt.ts +16 -0
  219. package/package.json +99 -6
  220. package/render/layout/mainLayoutViewMode.ts +25 -0
  221. package/render/page/server/createPage.ts +3 -1
  222. package/render/page/server/handleCreatePage.ts +2 -11
  223. package/runtimeDoctorCommands.ts +15 -66
  224. package/server/api/methods.ts +34 -12
  225. package/server/api/tableHandlers.ts +6 -3
  226. package/server/authenticateToken.ts +47 -2
  227. package/server/billingLedgerRoutes.ts +15 -0
  228. package/server/buildManifest.ts +54 -0
  229. package/server/coreReadiness.ts +34 -25
  230. package/server/coreRuntime.ts +15 -10
  231. package/server/handlers/activityStatsHandler.ts +5 -2
  232. package/server/handlers/agentEmailRegistrationE2EHandler.ts +25 -23
  233. package/server/handlers/agentRun/agentLookup.ts +1 -7
  234. package/server/handlers/agentRun/autonomousRuntime.ts +11 -10
  235. package/server/handlers/agentRun/builtinAgents.ts +12 -88
  236. package/server/handlers/agentRun/continueDialogContext.ts +15 -3
  237. package/server/handlers/agentRun/{inheritedDialogPrompt.ts → conversationReference.ts} +3 -3
  238. package/server/handlers/agentRun/dialogLookup.ts +4 -3
  239. package/server/handlers/agentRun/index.ts +864 -404
  240. package/server/handlers/agentRun/localRuntimeBootstrap.ts +17 -1
  241. package/server/handlers/agentRun/loop.ts +920 -508
  242. package/server/handlers/agentRun/machineConnector.ts +56 -8
  243. package/server/handlers/agentRun/machineRunAudit.ts +3 -2
  244. package/server/handlers/agentRun/modelUsageToolHandlers.ts +13 -10
  245. package/server/handlers/agentRun/requestContext.ts +12 -8
  246. package/server/handlers/agentRun/runtimeExecutionContext.ts +15 -3
  247. package/server/handlers/agentRun/runtimePreparation.ts +26 -24
  248. package/server/handlers/agentRun/runtimeRouting.ts +25 -40
  249. package/server/handlers/agentRun/runtimeSystemMessages.ts +65 -0
  250. package/server/handlers/agentRun/saveDialog.ts +97 -87
  251. package/server/handlers/agentRun/taskRunToolHandler.ts +9 -7
  252. package/server/handlers/agentRun/toolExecutor.ts +42 -78
  253. package/server/handlers/agentRun/types.ts +2 -1
  254. package/server/handlers/appDeployStatusStore.ts +17 -10
  255. package/server/handlers/appDomainHandler.ts +21 -15
  256. package/server/handlers/appLegacyInfraCleanup.ts +5 -2
  257. package/server/handlers/appSandboxHandler.ts +29 -8
  258. package/server/handlers/appSpaceAccess.ts +15 -8
  259. package/server/handlers/chatHandler.ts +22 -2
  260. package/server/handlers/chatUpstreamRetry.ts +225 -2
  261. package/server/handlers/connector/connectorConnectionRegistry.ts +55 -7
  262. package/server/handlers/connector/connectorWebSocket.ts +14 -10
  263. package/server/handlers/desktopAgentRuntimeAdapter.ts +4 -4
  264. package/server/handlers/desktopAgentRuntimeHostCapabilities.ts +25 -0
  265. package/server/handlers/desktopAgentRuntimeReadiness.ts +62 -0
  266. package/server/handlers/desktopAgentRuntimeStatusHandler.ts +38 -30
  267. package/server/handlers/desktopAgentRuntimeTurnHandler.ts +7 -3
  268. package/server/handlers/desktopAgentRuntimeTurnService.ts +39 -45
  269. package/server/handlers/desktopLlamaRuntimeHandler.ts +85 -51
  270. package/server/handlers/desktopUpdaterHandler.ts +132 -24
  271. package/server/handlers/favoriteHandlers.ts +8 -2
  272. package/server/handlers/getDialogBillingHandler.ts +4 -3
  273. package/server/handlers/getTransactionsHandler.ts +5 -2
  274. package/server/handlers/machines/machineBinding.ts +1 -0
  275. package/server/handlers/machines/machineHandlers.ts +0 -14
  276. package/server/handlers/machines/machineInstallAssets.ts +4 -2
  277. package/server/handlers/notificationEmitter.ts +5 -3
  278. package/server/handlers/notificationsHandler.ts +5 -2
  279. package/server/handlers/providerCallsRecentHandler.ts +234 -0
  280. package/server/handlers/providerReconciliationRunHandler.ts +180 -0
  281. package/server/handlers/providerRequestIdsHandler.ts +105 -0
  282. package/server/handlers/tableAccess.ts +6 -2
  283. package/server/handlers/tableToolHandlers.ts +28 -14
  284. package/server/handlers/userSecretsHandler.ts +17 -6
  285. package/server/handlers/versionHandler.ts +9 -4
  286. package/server/handlers/versionStore.ts +18 -10
  287. package/server/html/ssrPreload.ts +5 -3
  288. package/server/payments/crypto/cryptoUsdcBasePaymentProvider.ts +11 -8
  289. package/server/payments/crypto/cryptoUsdcBaseScanner.ts +12 -7
  290. package/server/payments/crypto/cryptoUsdtTronPaymentProvider.ts +11 -8
  291. package/server/payments/crypto/cryptoUsdtTronScanner.ts +9 -7
  292. package/server/payments/waffo/waffoPaymentProvider.ts +12 -9
  293. package/server/runtimeRole.ts +15 -0
  294. package/server/scheduler/scheduledTaskRuntime.ts +4 -2
  295. package/server/scheduler/schedulerService.ts +2 -2
  296. package/server/taskRunBridgeRoutes.ts +8 -5
  297. package/share/server/fetchCommunityShares.ts +1 -1
  298. package/share/server/helpers.ts +19 -17
  299. package/share/server/importShare.ts +9 -13
  300. package/share/server/listCommunityShares.ts +4 -4
  301. package/share/server/purchaseDoc.ts +8 -16
  302. package/share/server/readCommunityShareCover.ts +3 -2
  303. package/share/server/readSharedTable.ts +14 -13
  304. package/share/server/tableReplication.ts +42 -39
  305. package/spaceAttachCommands.ts +135 -0
  306. package/spaceInternalCommandEntries.ts +2 -0
  307. package/ai/agent/runtimeServerBase.ts +0 -37
  308. package/server/handlers/desktopAgentRuntimeHostFacts.ts +0 -40
@@ -11,38 +11,31 @@ import {
11
11
  import { selectUserId } from "../../../auth/authSlice";
12
12
 
13
13
  import { fetchPublicAgents as fetchLocal } from "../../agent/hooks/fetchPublicAgents";
14
- import { remove } from "../../../database/dbSlice";
15
- import { getAllServers } from "../../../database/actions/common";
16
14
  import {
17
- getRecordTimestamp,
18
- isTombstoneRecord,
19
- } from "../../../database/tombstones";
15
+ dedupeRemotePublicAgents,
16
+ maskRemoteAgentsByLocalTombstones,
17
+ planPublicAgentCatalogView,
18
+ type PublicAgentFilterOptions,
19
+ type PublicAgentListOptions,
20
+ shouldPruneStalePublicAgentCache as shouldPruneStalePublicAgentCacheImpl,
21
+ } from "../../agent/publicAgentCatalog";
20
22
  import {
21
- buildSortMeta,
22
- sortAgents,
23
- toTimeMs,
24
- MAgent
25
- } from "../../agent/utils/sortUtils";
23
+ getPublicAgentId,
24
+ getPublicAgentPruneDbKey,
25
+ matchesPublicAgentIdentifiers,
26
+ } from "../../agent/publicAgentIdentity";
27
+ import { remove } from "../../../database/dbSlice";
28
+ import { getAllServers } from "../../../database/actions/common";
29
+ import { isTombstoneRecord } from "../../../database/tombstones";
26
30
 
27
31
  /* -------------------------------------------------------------------------- */
28
32
  /* 类型定义 */
29
33
  /* -------------------------------------------------------------------------- */
30
34
 
31
- export interface UsePublicAgentsOptions {
32
- limit?: number;
33
- sortBy?:
34
- | "recommended"
35
- | "newest"
36
- | "popular"
37
- | "rating"
38
- | "outputPriceAsc"
39
- | "outputPriceDesc"
40
- | "favorite"; // 按收藏数排序
41
- searchName?: string;
42
- userId?: string;
43
- imageOutputOnly?: boolean;
35
+ export interface UsePublicAgentsOptions
36
+ extends PublicAgentFilterOptions,
37
+ PublicAgentListOptions {
44
38
  /** Filter agents that include this tool in their tools array */
45
- toolName?: string;
46
39
  /** Return list-card metadata only from remote public-agent APIs. */
47
40
  summary?: boolean;
48
41
  initialData?: Agent[];
@@ -55,79 +48,19 @@ interface PublicAgentsState {
55
48
  data: Agent[];
56
49
  }
57
50
 
58
- const matchesExcludedAgent = (agent: Agent, excludedIds: Set<string>) => {
59
- const identifiers = [(agent as any)?.dbKey, agent?.id]
60
- .filter(Boolean)
61
- .map((value) => String(value));
62
- return identifiers.some((identifier) => excludedIds.has(identifier));
63
- };
64
-
65
- const getAgentIdentifiers = (agent: Partial<Agent> | Record<string, any>) =>
66
- [agent?.dbKey, agent?.id]
67
- .filter(Boolean)
68
- .map((value) => String(value));
69
-
70
51
  /* -------------------------------------------------------------------------- */
71
52
  /* 删除策略:最低投入档——误删抑制开关 */
72
53
  /* -------------------------------------------------------------------------- */
73
54
 
74
- const PRUNE_ONLY_WHEN_NO_SEARCH = true;
75
- const PRUNE_ONLY_WHEN_SORT_NEWEST = true;
76
55
  const PRUNE_LIMIT_MULTIPLIER = 5;
77
56
  const PRUNE_LIMIT_CAP = 500;
78
57
 
79
- /* -------------------------------------------------------------------------- */
80
- /* 工具函数 */
81
- /* -------------------------------------------------------------------------- */
82
-
83
- // Local helpers removed, using shared utils from ai/agent/utils/sortUtils.ts
84
-
85
- /* -------------------------------------------------------------------------- */
86
- /* 合并 + 差集删除计算 */
87
- /* -------------------------------------------------------------------------- */
88
-
89
- function mergeAgents(localData: Agent[], remoteData: Agent[]) {
90
- const remoteIdSet = new Set(remoteData.map((a) => String(a.id)));
91
- const merged: MAgent[] = [];
92
- const toDelete: string[] = [];
93
-
94
- // 本地优先
95
- for (const local of localData) {
96
- const id = String(local.id);
97
- const remote = remoteIdSet.has(id)
98
- ? remoteData.find((r) => String(r.id) === id)
99
- : undefined;
100
-
101
- if (remote) {
102
- const localTimestamp = getRecordTimestamp(local);
103
- const remoteTimestamp = getRecordTimestamp(remote);
104
- const newest =
105
- remoteTimestamp >= localTimestamp
106
- ? { ...(local as any), ...(remote as any) }
107
- : { ...(remote as any), ...(local as any) };
108
- merged.push({
109
- ...newest,
110
- __sort: buildSortMeta(local, remote),
111
- });
112
- } else {
113
- toDelete.push(id);
114
- merged.push({
115
- ...(local as any),
116
- __sort: buildSortMeta(local, undefined),
117
- });
118
- }
119
- }
120
-
121
- // 再补仅远程有的
122
- for (const r of remoteData) {
123
- const id = String(r.id);
124
- const exists = merged.some((m) => String(m.id) === id);
125
- if (!exists) {
126
- merged.push({ ...(r as any), __sort: buildSortMeta(undefined, r) });
127
- }
128
- }
129
-
130
- return { merged, toDelete };
58
+ export function shouldPruneStalePublicAgentCache({
59
+ searchName,
60
+ }: {
61
+ searchName?: string;
62
+ }) {
63
+ return shouldPruneStalePublicAgentCacheImpl({ searchName });
131
64
  }
132
65
 
133
66
  /* -------------------------------------------------------------------------- */
@@ -209,6 +142,8 @@ export function usePublicAgents({
209
142
  }));
210
143
 
211
144
  const excludedIds = pendingExcludedIdsRef.current;
145
+ const servers = getAllServers(currentServer, syncServers);
146
+ const hasRemoteServers = servers.length > 0;
212
147
 
213
148
  /* -------------------------- 1) 本地优先渲染 -------------------------- */
214
149
 
@@ -217,47 +152,43 @@ export function usePublicAgents({
217
152
  tombstones: [],
218
153
  };
219
154
  let localDataForUi: Agent[] = [];
155
+ let localSortedForFallback: Agent[] = [];
220
156
 
221
157
  try {
222
158
  localResult = await fetchLocal(uiOptions);
223
159
  localDataForUi =
224
160
  excludedIds.size > 0
225
- ? localResult.data.filter((agent) => !matchesExcludedAgent(agent, excludedIds))
161
+ ? localResult.data.filter(
162
+ (agent) => !matchesPublicAgentIdentifiers(agent, excludedIds)
163
+ )
226
164
  : localResult.data;
227
165
 
228
166
  if (myReqId !== requestIdRef.current) return;
229
167
 
230
- const localDecorated = localDataForUi.map((a) => ({
231
- ...(a as any),
232
- __sort: buildSortMeta(a, undefined),
233
- }));
168
+ localSortedForFallback = planPublicAgentCatalogView({
169
+ localAgents: localDataForUi,
170
+ remoteAgents: [],
171
+ hasAuthoritativeRemoteResult: false,
172
+ currentUserId,
173
+ options: uiOptions,
174
+ }).localFallbackAgents;
234
175
 
235
- let localFiltered = localDecorated as Agent[];
236
- if (toolName) {
237
- const kw = toolName.toLowerCase();
238
- localFiltered = localFiltered.filter((a) =>
239
- (a as any).tools?.some((t: string) => t.toLowerCase().includes(kw))
240
- );
176
+ if (!hasRemoteServers) {
177
+ setState((prev) => ({ ...prev, data: localSortedForFallback }));
241
178
  }
242
-
243
- const localSorted = sortAgents(localFiltered, sortBy).slice(0, limit);
244
-
245
- setState((prev) => ({ ...prev, data: localSorted }));
246
179
  } catch {
247
180
  // 本地失败不阻塞远程
248
181
  }
249
182
 
250
183
  /* -------------------------- 2) 构造远程服务器列表 --------------------- */
251
184
 
252
- const servers = getAllServers(currentServer, syncServers);
253
-
254
185
  // 若没有任何可用远程(离线或未配置),则结束(只保留本地)
255
186
  if (servers.length === 0) {
256
187
  if (excludedIds.size > 0) {
257
188
  const stillPending = new Set(
258
189
  Array.from(excludedIds).filter((identifier) =>
259
190
  localResult.data.some((agent) =>
260
- matchesExcludedAgent(agent, new Set([identifier]))
191
+ matchesPublicAgentIdentifiers(agent, new Set([identifier]))
261
192
  )
262
193
  )
263
194
  );
@@ -290,97 +221,59 @@ export function usePublicAgents({
290
221
 
291
222
  if (myReqId !== requestIdRef.current) return;
292
223
 
293
- const remoteMap = new Map<string, Agent>();
294
-
295
- remoteResults.forEach((res) => {
296
- if (res.status !== "fulfilled") return;
297
- const list: Agent[] = (res.value?.data ?? []).filter(
298
- (agent: Agent) => !isTombstoneRecord(agent)
299
- );
300
- for (const agent of list) {
301
- const id = String(agent.id);
302
- if (!remoteMap.has(id)) {
303
- remoteMap.set(id, agent);
304
- }
305
- }
306
- });
307
-
308
- const localTombstoneMap = new Map<string, Record<string, any>>();
309
- for (const tombstone of localResult.tombstones ?? []) {
310
- for (const identifier of getAgentIdentifiers(tombstone)) {
311
- const existing = localTombstoneMap.get(identifier);
312
- if (!existing || getRecordTimestamp(tombstone) > getRecordTimestamp(existing)) {
313
- localTombstoneMap.set(identifier, tombstone);
314
- }
315
- }
316
- }
317
-
318
- const remoteData: Agent[] = Array.from(remoteMap.values()).filter((agent) => {
319
- const matchingTombstones = getAgentIdentifiers(agent)
320
- .map((identifier) => localTombstoneMap.get(identifier))
321
- .filter(Boolean) as Array<Record<string, any>>;
322
- if (matchingTombstones.length === 0) return true;
323
- const newestLocalTombstone = matchingTombstones.reduce((latest, current) =>
324
- getRecordTimestamp(current) > getRecordTimestamp(latest) ? current : latest
325
- );
326
- return getRecordTimestamp(agent) > getRecordTimestamp(newestLocalTombstone);
327
- });
224
+ const hasAuthoritativeRemoteResult = remoteResults.some(
225
+ (res) => res.status === "fulfilled"
226
+ );
227
+ const remoteData = maskRemoteAgentsByLocalTombstones(
228
+ dedupeRemotePublicAgents(
229
+ remoteResults.flatMap((res, index) => {
230
+ if (res.status !== "fulfilled") return [];
231
+ const originServer = servers[index];
232
+ return (res.value?.data ?? [])
233
+ .filter((agent: Agent) => !isTombstoneRecord(agent))
234
+ .map((agent: Agent) => ({
235
+ ...agent,
236
+ originServer,
237
+ }));
238
+ })
239
+ ),
240
+ localResult.tombstones ?? []
241
+ );
328
242
  const remoteDataForUi =
329
243
  excludedIds.size > 0
330
- ? remoteData.filter((agent) => !matchesExcludedAgent(agent, excludedIds))
244
+ ? remoteData.filter(
245
+ (agent) => !matchesPublicAgentIdentifiers(agent, excludedIds)
246
+ )
331
247
  : remoteData;
332
248
 
333
- const { merged, toDelete } = mergeAgents(
334
- localDataForUi ?? [],
335
- remoteDataForUi
336
- );
337
-
338
- /* -------------------------- 4) 计算删除建议(带保护) -------------------- */
339
-
340
- const toDeleteFiltered = toDelete.filter((id) => {
341
- const localItem = localResult.data.find((a) => String(a.id) === id) as any;
342
-
343
- // 1. 主权保护:如果是我的 Agent,绝对不准自动删除
344
- if (currentUserId && localItem?.userId === currentUserId) return false;
345
-
346
- // 2. 时间宽限期:如果是最近 5 分钟内创建的,处于同步风险期,不准删除
347
- const isRecentlyCreated =
348
- Date.now() - toTimeMs(localItem?.createdAt) < 5 * 60 * 1000;
349
- if (isRecentlyCreated) return false;
350
-
351
- const origin = localItem?.meta?.origin; // "remote" | "local" | "both" | undefined
352
- if (origin === "local") return false;
353
- return true;
249
+ const viewPlan = planPublicAgentCatalogView({
250
+ localAgents: localDataForUi ?? [],
251
+ remoteAgents: remoteDataForUi,
252
+ hasAuthoritativeRemoteResult,
253
+ currentUserId,
254
+ options: uiOptions,
354
255
  });
355
256
 
356
- const toDeleteFilteredSet = new Set(toDeleteFiltered);
357
- let filteredForUI = (merged as Agent[]).filter(
358
- (a) => !toDeleteFilteredSet.has(String(a.id))
359
- );
360
-
361
- // Client-side toolName filter applied after merge — guards against servers
362
- // that don't yet support the toolName param (e.g. old code still running).
363
- if (toolName) {
364
- const kw = toolName.toLowerCase();
365
- filteredForUI = filteredForUI.filter((a) =>
366
- (a as any).tools?.some((t: string) => t.toLowerCase().includes(kw))
367
- );
368
- }
369
-
370
- const finalSorted = sortAgents(filteredForUI, sortBy).slice(0, limit);
371
-
372
257
  /* -------------------------- 5) 条件化删除本地缓存 -------------------- */
373
258
 
374
- const canPruneScene =
375
- (!PRUNE_ONLY_WHEN_NO_SEARCH || !searchName) &&
376
- (!PRUNE_ONLY_WHEN_SORT_NEWEST || sortBy === "newest");
259
+ const canPruneScene = shouldPruneStalePublicAgentCache({
260
+ searchName,
261
+ });
377
262
 
378
263
  if (
379
264
  canPruneScene &&
380
- toDeleteFiltered.length > 0 &&
265
+ viewPlan.pruneIds.length > 0 &&
381
266
  myReqId === requestIdRef.current
382
267
  ) {
383
- toDeleteFiltered.forEach((id) => dispatch(remove(id)));
268
+ viewPlan.pruneIds.forEach((id) => {
269
+ const localItem = localResult.data.find(
270
+ (agent) => getPublicAgentId(agent) === id
271
+ );
272
+ const dbKey = getPublicAgentPruneDbKey(localItem);
273
+ if (dbKey) {
274
+ dispatch(remove(dbKey));
275
+ }
276
+ });
384
277
  }
385
278
 
386
279
  if (myReqId !== requestIdRef.current) return;
@@ -391,10 +284,10 @@ export function usePublicAgents({
391
284
  const identifierSet = new Set([identifier]);
392
285
  return (
393
286
  localResult.data.some((agent) =>
394
- matchesExcludedAgent(agent, identifierSet)
287
+ matchesPublicAgentIdentifiers(agent, identifierSet)
395
288
  ) ||
396
289
  remoteData.some((agent) =>
397
- matchesExcludedAgent(agent, identifierSet)
290
+ matchesPublicAgentIdentifiers(agent, identifierSet)
398
291
  )
399
292
  );
400
293
  })
@@ -402,13 +295,18 @@ export function usePublicAgents({
402
295
  pendingExcludedIdsRef.current = stillPending;
403
296
  }
404
297
 
405
- setState({ loading: false, error: null, data: finalSorted });
298
+ setState({ loading: false, error: null, data: viewPlan.visibleAgents });
406
299
  } catch (err: any) {
407
300
  if (err?.name === "AbortError") return;
408
301
  if (myReqId !== requestIdRef.current) return;
409
302
 
410
- // 远程失败:保留本地阶段结果
411
- setState((prev) => ({ ...prev, loading: false, error: null }));
303
+ // 远程失败:没有已渲染数据时回退到本地缓存。
304
+ setState((prev) => ({
305
+ ...prev,
306
+ data: prev.data.length > 0 ? prev.data : localSortedForFallback,
307
+ loading: false,
308
+ error: null,
309
+ }));
412
310
  }
413
311
  }, [
414
312
  limit,
@@ -454,7 +352,7 @@ export function usePublicAgents({
454
352
  excludedAgentIds.length > 0
455
353
  ? prev.data.filter(
456
354
  (agent) =>
457
- !matchesExcludedAgent(
355
+ !matchesPublicAgentIdentifiers(
458
356
  agent,
459
357
  new Set(excludedAgentIds.map((value) => String(value)))
460
358
  )