nolo-cli 0.1.9 → 0.1.11

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 (240) hide show
  1. package/README.md +0 -32
  2. package/agentRuntimeCommands.ts +3 -3
  3. package/commandRegistry.ts +2 -2
  4. package/machineCommands.ts +31 -6
  5. package/package.json +6 -8
  6. package/ai/agent/_executeModel.ts +0 -118
  7. package/ai/agent/agentSlice.ts +0 -525
  8. package/ai/agent/appWorkingMemory.ts +0 -126
  9. package/ai/agent/avatarUtils.ts +0 -24
  10. package/ai/agent/buildEditingContext.ts +0 -373
  11. package/ai/agent/buildSystemPrompt.ts +0 -532
  12. package/ai/agent/cleanAgentMessages.ts +0 -140
  13. package/ai/agent/cliChatClient.ts +0 -119
  14. package/ai/agent/cliExecutor.ts +0 -733
  15. package/ai/agent/cliPrompt.ts +0 -10
  16. package/ai/agent/contextCompiler.ts +0 -107
  17. package/ai/agent/contextLayerContract.ts +0 -44
  18. package/ai/agent/createAgentSchema.ts +0 -234
  19. package/ai/agent/executeToolCall.ts +0 -58
  20. package/ai/agent/fetchAgentContexts.ts +0 -42
  21. package/ai/agent/generatePrompt.ts +0 -3
  22. package/ai/agent/getFullChatContextKeys.ts +0 -168
  23. package/ai/agent/hooks/fetchPublicAgents.ts +0 -133
  24. package/ai/agent/hooks/useAgentConfig.ts +0 -61
  25. package/ai/agent/hooks/useAgentDialog.ts +0 -35
  26. package/ai/agent/hooks/useAgentFormValidation.ts +0 -202
  27. package/ai/agent/hooks/usePublicAgents.ts +0 -473
  28. package/ai/agent/machineRunPermissions.ts +0 -95
  29. package/ai/agent/persistMessageWithFixedId.ts +0 -37
  30. package/ai/agent/planSlice.ts +0 -259
  31. package/ai/agent/referenceUtils.ts +0 -229
  32. package/ai/agent/runAgentBackground.ts +0 -238
  33. package/ai/agent/runAgentClientLoop.ts +0 -138
  34. package/ai/agent/runtimeGuidance.ts +0 -97
  35. package/ai/agent/runtimeServerBase.ts +0 -37
  36. package/ai/agent/server/fetchPublicAgents.ts +0 -128
  37. package/ai/agent/startParallelAgentStreams.ts +0 -424
  38. package/ai/agent/startupProtocol.ts +0 -53
  39. package/ai/agent/streamAgentChatTurn.ts +0 -1278
  40. package/ai/agent/streamAgentChatTurnUtils.ts +0 -738
  41. package/ai/agent/types.ts +0 -71
  42. package/ai/agent/utils/imageOutput.ts +0 -33
  43. package/ai/agent/utils/sortUtils.ts +0 -250
  44. package/ai/agent/web/referencePickerUtils.ts +0 -146
  45. package/ai/ai.locale.ts +0 -1075
  46. package/ai/chat/accumulateToolCallChunks.ts +0 -95
  47. package/ai/chat/fetchUtils.native.ts +0 -276
  48. package/ai/chat/fetchUtils.ts +0 -153
  49. package/ai/chat/parseApiError.ts +0 -64
  50. package/ai/chat/parseMultilineSSE.ts +0 -95
  51. package/ai/chat/sendOpenAICompletionsRequest.native.ts +0 -682
  52. package/ai/chat/sendOpenAICompletionsRequest.ts +0 -703
  53. package/ai/chat/sendOpenAIResponseRequest.ts +0 -491
  54. package/ai/chat/shouldUseServerProxy.ts +0 -18
  55. package/ai/chat/sseClient.native.ts +0 -91
  56. package/ai/chat/sseClient.ts +0 -67
  57. package/ai/chat/streamReader.native.ts +0 -31
  58. package/ai/chat/streamReader.ts +0 -62
  59. package/ai/chat/updateTotalUsage.ts +0 -72
  60. package/ai/context/buildReferenceContext.ts +0 -437
  61. package/ai/context/calculateContextUsage.ts +0 -133
  62. package/ai/context/retention.ts +0 -165
  63. package/ai/context/tokenUtils.ts +0 -78
  64. package/ai/index.ts +0 -1
  65. package/ai/llm/calculateGeminiImageTokens.ts +0 -57
  66. package/ai/llm/deepinfra.ts +0 -28
  67. package/ai/llm/fireworks.ts +0 -50
  68. package/ai/llm/generateRequestBody.ts +0 -165
  69. package/ai/llm/getModelContextWindow.ts +0 -84
  70. package/ai/llm/getNoloKey.ts +0 -31
  71. package/ai/llm/getPricing.ts +0 -199
  72. package/ai/llm/hooks/useModelPricing.ts +0 -75
  73. package/ai/llm/imagePricing.ts +0 -40
  74. package/ai/llm/isResponseAPIModel.ts +0 -13
  75. package/ai/llm/mimo.ts +0 -71
  76. package/ai/llm/mistral.ts +0 -22
  77. package/ai/llm/modelAvatar.ts +0 -427
  78. package/ai/llm/models.ts +0 -45
  79. package/ai/llm/openrouterModels.ts +0 -269
  80. package/ai/llm/providers.ts +0 -306
  81. package/ai/llm/reasoningModels.ts +0 -28
  82. package/ai/llm/types.ts +0 -59
  83. package/ai/llm/usageRequestOptions.ts +0 -59
  84. package/ai/memory/capture.ts +0 -148
  85. package/ai/memory/consolidate.ts +0 -104
  86. package/ai/memory/delete.ts +0 -147
  87. package/ai/memory/overlay.ts +0 -84
  88. package/ai/memory/query.ts +0 -38
  89. package/ai/memory/queryShared.ts +0 -160
  90. package/ai/memory/rank.ts +0 -105
  91. package/ai/memory/recentRelationshipRecap.ts +0 -249
  92. package/ai/memory/remember.ts +0 -167
  93. package/ai/memory/runtime.ts +0 -76
  94. package/ai/memory/store.ts +0 -20
  95. package/ai/memory/storeShared.ts +0 -76
  96. package/ai/memory/types.ts +0 -46
  97. package/ai/memory/understanding.ts +0 -349
  98. package/ai/memory/understandingGreeting.ts +0 -264
  99. package/ai/messages/type.ts +0 -20
  100. package/ai/policy/personalizationDialog.ts +0 -333
  101. package/ai/policy/runtimePolicy.ts +0 -440
  102. package/ai/policy/selfUpdateFields.ts +0 -48
  103. package/ai/policy/types.ts +0 -64
  104. package/ai/skills/referenceRuntime.ts +0 -274
  105. package/ai/skills/skillDiagnostics.ts +0 -251
  106. package/ai/skills/skillDocBuilder.ts +0 -139
  107. package/ai/skills/skillDocProtocol.ts +0 -434
  108. package/ai/skills/skillReferenceSummary.ts +0 -63
  109. package/ai/skills/skillSummaryMarker.ts +0 -26
  110. package/ai/token/calculatePrice.ts +0 -544
  111. package/ai/token/db.ts +0 -98
  112. package/ai/token/externalToolCost.ts +0 -330
  113. package/ai/token/hooks/useRecords.ts +0 -65
  114. package/ai/token/missingUsageEstimate.ts +0 -42
  115. package/ai/token/modelUsageQuery.ts +0 -252
  116. package/ai/token/normalizeUsage.ts +0 -84
  117. package/ai/token/openaiImageGenerationUsage.ts +0 -56
  118. package/ai/token/prepareTokenUsageData.ts +0 -88
  119. package/ai/token/query.ts +0 -88
  120. package/ai/token/queryUserTokens.ts +0 -59
  121. package/ai/token/resolveBillingTarget.ts +0 -52
  122. package/ai/token/saveTokenRecord.ts +0 -53
  123. package/ai/token/serverDialogProjection.ts +0 -78
  124. package/ai/token/serverTokenWriter.ts +0 -143
  125. package/ai/token/stats.ts +0 -21
  126. package/ai/token/tokenThunks.ts +0 -24
  127. package/ai/token/types.ts +0 -93
  128. package/ai/tools/agent/agentTools.ts +0 -176
  129. package/ai/tools/agent/agentUpdateShared.ts +0 -311
  130. package/ai/tools/agent/callAgentTool.ts +0 -139
  131. package/ai/tools/agent/createAgentTool.ts +0 -512
  132. package/ai/tools/agent/createDialogTool.ts +0 -69
  133. package/ai/tools/agent/createSkillAgentTool.ts +0 -62
  134. package/ai/tools/agent/parallelBudget.ts +0 -221
  135. package/ai/tools/agent/presets/appBuilderPreset.ts +0 -145
  136. package/ai/tools/agent/runLlmTool.ts +0 -96
  137. package/ai/tools/agent/runStreamingAgentTool.ts +0 -73
  138. package/ai/tools/agent/skillAgentArgs.ts +0 -106
  139. package/ai/tools/agent/skillAgentPreset.ts +0 -89
  140. package/ai/tools/agent/streamParallelAgentsTool.ts +0 -122
  141. package/ai/tools/agent/updateAgentTool.ts +0 -96
  142. package/ai/tools/agent/updateSelfTool.ts +0 -113
  143. package/ai/tools/amazonProductScraperTool.ts +0 -86
  144. package/ai/tools/apifyActorClient.ts +0 -45
  145. package/ai/tools/appEditGuard.ts +0 -372
  146. package/ai/tools/appReadSnapshot.ts +0 -153
  147. package/ai/tools/appTools.ts +0 -1549
  148. package/ai/tools/applyEditTool.ts +0 -256
  149. package/ai/tools/applyLineEditsTool.ts +0 -312
  150. package/ai/tools/browserTools/click.ts +0 -33
  151. package/ai/tools/browserTools/closeSession.ts +0 -29
  152. package/ai/tools/browserTools/common.ts +0 -27
  153. package/ai/tools/browserTools/openSession.ts +0 -48
  154. package/ai/tools/browserTools/readContent.ts +0 -38
  155. package/ai/tools/browserTools/selectOption.ts +0 -46
  156. package/ai/tools/browserTools/typeText.ts +0 -42
  157. package/ai/tools/category/createCategoryTool.ts +0 -66
  158. package/ai/tools/category/queryContentsByCategoryTool.ts +0 -69
  159. package/ai/tools/category/updateContentCategoryTool.ts +0 -75
  160. package/ai/tools/cfBrowserTools.ts +0 -319
  161. package/ai/tools/cfSpeechToTextTool.ts +0 -49
  162. package/ai/tools/checkEnvTool.ts +0 -65
  163. package/ai/tools/cloudflareCrawlTool.ts +0 -289
  164. package/ai/tools/codeSearchTool.ts +0 -111
  165. package/ai/tools/codeTools.ts +0 -101
  166. package/ai/tools/createDocTool.ts +0 -132
  167. package/ai/tools/createPlanTool.ts +0 -999
  168. package/ai/tools/createSkillDocTool.ts +0 -155
  169. package/ai/tools/createWorkflowTool.ts +0 -154
  170. package/ai/tools/deepseekOcrTool.ts +0 -34
  171. package/ai/tools/delayTool.ts +0 -31
  172. package/ai/tools/deleteSpacesTool.ts +0 -325
  173. package/ai/tools/deleteSpacesToolModel.ts +0 -159
  174. package/ai/tools/devReloadUtils.ts +0 -29
  175. package/ai/tools/dialogMessageSearch.ts +0 -137
  176. package/ai/tools/doctorSkillTool.ts +0 -72
  177. package/ai/tools/ecommerceScraperTool.ts +0 -86
  178. package/ai/tools/emailTools.ts +0 -549
  179. package/ai/tools/evalSkillTool.ts +0 -92
  180. package/ai/tools/exaSearchTool.ts +0 -64
  181. package/ai/tools/execBashTool.ts +0 -379
  182. package/ai/tools/executeSqlTool.ts +0 -192
  183. package/ai/tools/fetchWebpageSupport.ts +0 -309
  184. package/ai/tools/fetchWebpageTool.ts +0 -84
  185. package/ai/tools/geminiImagePreviewTool.ts +0 -361
  186. package/ai/tools/generateDocxTool.ts +0 -215
  187. package/ai/tools/googleSearchScraperTool.ts +0 -106
  188. package/ai/tools/importDataTool.ts +0 -133
  189. package/ai/tools/importSkillTool.ts +0 -162
  190. package/ai/tools/index.ts +0 -1858
  191. package/ai/tools/listFilesTool.ts +0 -82
  192. package/ai/tools/listUserSpacesTool.ts +0 -113
  193. package/ai/tools/modelUsageTools.ts +0 -142
  194. package/ai/tools/olmOcrTool.ts +0 -34
  195. package/ai/tools/openaiImageTool.ts +0 -218
  196. package/ai/tools/paddleOcrTool.ts +0 -34
  197. package/ai/tools/prepareTools.ts +0 -23
  198. package/ai/tools/readDocTool.ts +0 -84
  199. package/ai/tools/readFileTool.ts +0 -211
  200. package/ai/tools/readTool.ts +0 -163
  201. package/ai/tools/readXPostTool.ts +0 -233
  202. package/ai/tools/rememberMemoryTool.ts +0 -84
  203. package/ai/tools/remotionVideoTool.ts +0 -151
  204. package/ai/tools/searchDialogMessagesTool.ts +0 -222
  205. package/ai/tools/searchRepoTool.ts +0 -115
  206. package/ai/tools/searchWorkspaceTool.ts +0 -259
  207. package/ai/tools/skillFollowup.ts +0 -86
  208. package/ai/tools/surfWeatherTool.ts +0 -169
  209. package/ai/tools/table/addTableRowTool.ts +0 -217
  210. package/ai/tools/table/createTableTool.ts +0 -315
  211. package/ai/tools/table/rowTools.ts +0 -366
  212. package/ai/tools/table/schemaTools.ts +0 -244
  213. package/ai/tools/table/shareTableTool.ts +0 -148
  214. package/ai/tools/table/toolShared.ts +0 -129
  215. package/ai/tools/toolApiClient.ts +0 -198
  216. package/ai/tools/toolNameAliases.ts +0 -57
  217. package/ai/tools/toolResultError.ts +0 -42
  218. package/ai/tools/toolRunSlice.ts +0 -303
  219. package/ai/tools/toolSchemaCompatibility.ts +0 -53
  220. package/ai/tools/toolVisibility.ts +0 -4
  221. package/ai/tools/types.ts +0 -20
  222. package/ai/tools/uiAskChoiceTool.ts +0 -104
  223. package/ai/tools/updateContentTitleTool.ts +0 -84
  224. package/ai/tools/updateDocTool.ts +0 -105
  225. package/ai/tools/updateUserPreferenceProfileTool.ts +0 -145
  226. package/ai/tools/whisperTool.ts +0 -77
  227. package/ai/tools/writeFileTool.ts +0 -210
  228. package/ai/tools/youtubeScraperTool.ts +0 -116
  229. package/ai/tools/ziweiChartTool.ts +0 -678
  230. package/ai/types.ts +0 -55
  231. package/ai/workflow/workflowExecutor.ts +0 -323
  232. package/ai/workflow/workflowSlice.ts +0 -73
  233. package/ai/workflow/workflowTypes.ts +0 -106
  234. package/client/compactDialog.ts +0 -222
  235. package/connector-experimental/capabilities.ts +0 -73
  236. package/connector-experimental/codexBinary.ts +0 -41
  237. package/connector-experimental/heartbeatLoop.ts +0 -22
  238. package/connector-experimental/index.ts +0 -5
  239. package/connector-experimental/machineInfo.ts +0 -46
  240. package/connector-experimental/protocol.ts +0 -54
@@ -1,473 +0,0 @@
1
- // 文件路径: ai/agent/hooks/usePublicAgents.ts
2
-
3
- import { useEffect, useState, useCallback, useRef } from "react";
4
- import { useAppDispatch, useAppSelector } from "app/store";
5
-
6
- import type { Agent } from "app/types";
7
- import {
8
- selectCurrentServer,
9
- selectSyncServers,
10
- } from "app/settings/settingSlice";
11
- import { selectUserId } from "auth/authSlice";
12
-
13
- import { fetchPublicAgents as fetchLocal } from "ai/agent/hooks/fetchPublicAgents";
14
- import { remove } from "database/dbSlice";
15
- import { getAllServers } from "database/actions/common";
16
- import {
17
- getRecordTimestamp,
18
- isTombstoneRecord,
19
- } from "database/tombstones";
20
- import {
21
- buildSortMeta,
22
- sortAgents,
23
- toTimeMs,
24
- MAgent
25
- } from "ai/agent/utils/sortUtils";
26
-
27
- /* -------------------------------------------------------------------------- */
28
- /* 类型定义 */
29
- /* -------------------------------------------------------------------------- */
30
-
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;
44
- /** Filter agents that include this tool in their tools array */
45
- toolName?: string;
46
- initialData?: Agent[];
47
- reloadMode?: "preview" | "catalog";
48
- }
49
-
50
- interface PublicAgentsState {
51
- loading: boolean;
52
- error: Error | null;
53
- data: Agent[];
54
- }
55
-
56
- const matchesExcludedAgent = (agent: Agent, excludedIds: Set<string>) => {
57
- const identifiers = [(agent as any)?.dbKey, agent?.id]
58
- .filter(Boolean)
59
- .map((value) => String(value));
60
- return identifiers.some((identifier) => excludedIds.has(identifier));
61
- };
62
-
63
- const getAgentIdentifiers = (agent: Partial<Agent> | Record<string, any>) =>
64
- [agent?.dbKey, agent?.id]
65
- .filter(Boolean)
66
- .map((value) => String(value));
67
-
68
- /* -------------------------------------------------------------------------- */
69
- /* 删除策略:最低投入档——误删抑制开关 */
70
- /* -------------------------------------------------------------------------- */
71
-
72
- const PRUNE_ONLY_WHEN_NO_SEARCH = true;
73
- const PRUNE_ONLY_WHEN_SORT_NEWEST = true;
74
- const PRUNE_LIMIT_MULTIPLIER = 5;
75
- const PRUNE_LIMIT_CAP = 500;
76
-
77
- /* -------------------------------------------------------------------------- */
78
- /* 工具函数 */
79
- /* -------------------------------------------------------------------------- */
80
-
81
- // Local helpers removed, using shared utils from ai/agent/utils/sortUtils.ts
82
-
83
- /* -------------------------------------------------------------------------- */
84
- /* 合并 + 差集删除计算 */
85
- /* -------------------------------------------------------------------------- */
86
-
87
- function mergeAgents(localData: Agent[], remoteData: Agent[]) {
88
- const remoteIdSet = new Set(remoteData.map((a) => String(a.id)));
89
- const merged: MAgent[] = [];
90
- const toDelete: string[] = [];
91
-
92
- // 本地优先
93
- for (const local of localData) {
94
- const id = String(local.id);
95
- const remote = remoteIdSet.has(id)
96
- ? remoteData.find((r) => String(r.id) === id)
97
- : undefined;
98
-
99
- if (remote) {
100
- const localTimestamp = getRecordTimestamp(local);
101
- const remoteTimestamp = getRecordTimestamp(remote);
102
- const newest =
103
- remoteTimestamp >= localTimestamp
104
- ? { ...(local as any), ...(remote as any) }
105
- : { ...(remote as any), ...(local as any) };
106
- merged.push({
107
- ...newest,
108
- __sort: buildSortMeta(local, remote),
109
- });
110
- } else {
111
- toDelete.push(id);
112
- merged.push({
113
- ...(local as any),
114
- __sort: buildSortMeta(local, undefined),
115
- });
116
- }
117
- }
118
-
119
- // 再补仅远程有的
120
- for (const r of remoteData) {
121
- const id = String(r.id);
122
- const exists = merged.some((m) => String(m.id) === id);
123
- if (!exists) {
124
- merged.push({ ...(r as any), __sort: buildSortMeta(undefined, r) });
125
- }
126
- }
127
-
128
- return { merged, toDelete };
129
- }
130
-
131
- /* -------------------------------------------------------------------------- */
132
- /* 远程获取(支持 Abort) */
133
- /* -------------------------------------------------------------------------- */
134
-
135
- async function fetchRemoteAgents(
136
- serverUrl: string,
137
- options: UsePublicAgentsOptions,
138
- signal?: AbortSignal
139
- ): Promise<{ data: Agent[] }> {
140
- const response = await fetch(`${serverUrl}/rpc/getPublicAgents`, {
141
- method: "POST",
142
- headers: { "Content-Type": "application/json" },
143
- body: JSON.stringify(options),
144
- signal,
145
- });
146
-
147
- if (!response.ok) {
148
- throw new Error(`Remote fetch failed with status ${response.status}`);
149
- }
150
-
151
- const data = await response.json();
152
- return data as { data: Agent[] };
153
- }
154
-
155
- /* -------------------------------------------------------------------------- */
156
- /* Hook 主体 */
157
- /* -------------------------------------------------------------------------- */
158
-
159
- export function usePublicAgents({
160
- limit = 20,
161
- sortBy = "recommended",
162
- searchName = "",
163
- userId,
164
- imageOutputOnly = false,
165
- toolName,
166
- initialData = [],
167
- reloadMode = "catalog",
168
- }: UsePublicAgentsOptions = {}) {
169
- // Intentionally still uses the raw configured server selectors instead of the
170
- // newer content/runtime helpers. Public-agent discovery is a mixed path:
171
- // local cache hydration + marketplace-style remote aggregation across the
172
- // currently configured peers. Keep it out of the local-first content CRUD
173
- // refactor until the agent marketplace/server-ownership phase.
174
- const currentServer = useAppSelector(selectCurrentServer);
175
- const syncServers = useAppSelector(selectSyncServers);
176
- const currentUserId = useAppSelector(selectUserId);
177
- const dispatch = useAppDispatch();
178
-
179
- const [state, setState] = useState<PublicAgentsState>({
180
- loading: initialData.length === 0,
181
- error: null,
182
- data: initialData,
183
- });
184
-
185
- const requestIdRef = useRef(0);
186
- const abortRef = useRef<AbortController | null>(null);
187
- const pendingExcludedIdsRef = useRef<Set<string>>(new Set());
188
-
189
- const fetchData = useCallback(async () => {
190
- const uiOptions: UsePublicAgentsOptions = {
191
- limit,
192
- sortBy,
193
- searchName,
194
- userId,
195
- imageOutputOnly,
196
- toolName,
197
- };
198
- const myReqId = ++requestIdRef.current;
199
-
200
- // 进入 loading,但保留现有数据;已有数据时不强制 loading,避免 SSR 首屏抖动
201
- setState((prev) => ({
202
- ...prev,
203
- loading: prev.data.length === 0,
204
- error: null,
205
- }));
206
-
207
- const excludedIds = pendingExcludedIdsRef.current;
208
-
209
- /* -------------------------- 1) 本地优先渲染 -------------------------- */
210
-
211
- let localResult: { data: Agent[]; tombstones: Array<Record<string, any>> } = {
212
- data: [],
213
- tombstones: [],
214
- };
215
- let localDataForUi: Agent[] = [];
216
-
217
- try {
218
- localResult = await fetchLocal(uiOptions);
219
- localDataForUi =
220
- excludedIds.size > 0
221
- ? localResult.data.filter((agent) => !matchesExcludedAgent(agent, excludedIds))
222
- : localResult.data;
223
-
224
- if (myReqId !== requestIdRef.current) return;
225
-
226
- const localDecorated = localDataForUi.map((a) => ({
227
- ...(a as any),
228
- __sort: buildSortMeta(a, undefined),
229
- }));
230
-
231
- let localFiltered = localDecorated as Agent[];
232
- if (toolName) {
233
- const kw = toolName.toLowerCase();
234
- localFiltered = localFiltered.filter((a) =>
235
- (a as any).tools?.some((t: string) => t.toLowerCase().includes(kw))
236
- );
237
- }
238
-
239
- const localSorted = sortAgents(localFiltered, sortBy).slice(0, limit);
240
-
241
- setState((prev) => ({ ...prev, data: localSorted }));
242
- } catch {
243
- // 本地失败不阻塞远程
244
- }
245
-
246
- /* -------------------------- 2) 构造远程服务器列表 --------------------- */
247
-
248
- const servers = getAllServers(currentServer, syncServers);
249
-
250
- // 若没有任何可用远程(离线或未配置),则结束(只保留本地)
251
- if (servers.length === 0) {
252
- if (excludedIds.size > 0) {
253
- const stillPending = new Set(
254
- Array.from(excludedIds).filter((identifier) =>
255
- localResult.data.some((agent) =>
256
- matchesExcludedAgent(agent, new Set([identifier]))
257
- )
258
- )
259
- );
260
- pendingExcludedIdsRef.current = stillPending;
261
- }
262
- setState((prev) => ({ ...prev, loading: false }));
263
- return;
264
- }
265
-
266
- /* -------------------------- 3) 远程请求 + 合并 ------------------------ */
267
-
268
- try {
269
- abortRef.current?.abort();
270
- abortRef.current = new AbortController();
271
-
272
- const pruneLimit = Math.min(
273
- PRUNE_LIMIT_CAP,
274
- Math.max(limit, limit * PRUNE_LIMIT_MULTIPLIER)
275
- );
276
- const remoteOptions: UsePublicAgentsOptions = {
277
- ...uiOptions,
278
- limit: pruneLimit,
279
- };
280
-
281
- const remoteResults = await Promise.allSettled(
282
- servers.map((server) =>
283
- fetchRemoteAgents(server, remoteOptions, abortRef.current!.signal)
284
- )
285
- );
286
-
287
- if (myReqId !== requestIdRef.current) return;
288
-
289
- const remoteMap = new Map<string, Agent>();
290
-
291
- remoteResults.forEach((res) => {
292
- if (res.status !== "fulfilled") return;
293
- const list: Agent[] = (res.value?.data ?? []).filter(
294
- (agent: Agent) => !isTombstoneRecord(agent)
295
- );
296
- for (const agent of list) {
297
- const id = String(agent.id);
298
- if (!remoteMap.has(id)) {
299
- remoteMap.set(id, agent);
300
- }
301
- }
302
- });
303
-
304
- const localTombstoneMap = new Map<string, Record<string, any>>();
305
- for (const tombstone of localResult.tombstones ?? []) {
306
- for (const identifier of getAgentIdentifiers(tombstone)) {
307
- const existing = localTombstoneMap.get(identifier);
308
- if (!existing || getRecordTimestamp(tombstone) > getRecordTimestamp(existing)) {
309
- localTombstoneMap.set(identifier, tombstone);
310
- }
311
- }
312
- }
313
-
314
- const remoteData: Agent[] = Array.from(remoteMap.values()).filter((agent) => {
315
- const matchingTombstones = getAgentIdentifiers(agent)
316
- .map((identifier) => localTombstoneMap.get(identifier))
317
- .filter(Boolean) as Array<Record<string, any>>;
318
- if (matchingTombstones.length === 0) return true;
319
- const newestLocalTombstone = matchingTombstones.reduce((latest, current) =>
320
- getRecordTimestamp(current) > getRecordTimestamp(latest) ? current : latest
321
- );
322
- return getRecordTimestamp(agent) > getRecordTimestamp(newestLocalTombstone);
323
- });
324
- const remoteDataForUi =
325
- excludedIds.size > 0
326
- ? remoteData.filter((agent) => !matchesExcludedAgent(agent, excludedIds))
327
- : remoteData;
328
-
329
- const { merged, toDelete } = mergeAgents(
330
- localDataForUi ?? [],
331
- remoteDataForUi
332
- );
333
-
334
- /* -------------------------- 4) 计算删除建议(带保护) -------------------- */
335
-
336
- const toDeleteFiltered = toDelete.filter((id) => {
337
- const localItem = localResult.data.find((a) => String(a.id) === id) as any;
338
-
339
- // 1. 主权保护:如果是我的 Agent,绝对不准自动删除
340
- if (currentUserId && localItem?.userId === currentUserId) return false;
341
-
342
- // 2. 时间宽限期:如果是最近 5 分钟内创建的,处于同步风险期,不准删除
343
- const isRecentlyCreated =
344
- Date.now() - toTimeMs(localItem?.createdAt) < 5 * 60 * 1000;
345
- if (isRecentlyCreated) return false;
346
-
347
- const origin = localItem?.meta?.origin; // "remote" | "local" | "both" | undefined
348
- if (origin === "local") return false;
349
- return true;
350
- });
351
-
352
- const toDeleteFilteredSet = new Set(toDeleteFiltered);
353
- let filteredForUI = (merged as Agent[]).filter(
354
- (a) => !toDeleteFilteredSet.has(String(a.id))
355
- );
356
-
357
- // Client-side toolName filter applied after merge — guards against servers
358
- // that don't yet support the toolName param (e.g. old code still running).
359
- if (toolName) {
360
- const kw = toolName.toLowerCase();
361
- filteredForUI = filteredForUI.filter((a) =>
362
- (a as any).tools?.some((t: string) => t.toLowerCase().includes(kw))
363
- );
364
- }
365
-
366
- const finalSorted = sortAgents(filteredForUI, sortBy).slice(0, limit);
367
-
368
- /* -------------------------- 5) 条件化删除本地缓存 -------------------- */
369
-
370
- const canPruneScene =
371
- (!PRUNE_ONLY_WHEN_NO_SEARCH || !searchName) &&
372
- (!PRUNE_ONLY_WHEN_SORT_NEWEST || sortBy === "newest");
373
-
374
- if (
375
- canPruneScene &&
376
- toDeleteFiltered.length > 0 &&
377
- myReqId === requestIdRef.current
378
- ) {
379
- toDeleteFiltered.forEach((id) => dispatch(remove(id)));
380
- }
381
-
382
- if (myReqId !== requestIdRef.current) return;
383
-
384
- if (excludedIds.size > 0) {
385
- const stillPending = new Set(
386
- Array.from(excludedIds).filter((identifier) => {
387
- const identifierSet = new Set([identifier]);
388
- return (
389
- localResult.data.some((agent) =>
390
- matchesExcludedAgent(agent, identifierSet)
391
- ) ||
392
- remoteData.some((agent) =>
393
- matchesExcludedAgent(agent, identifierSet)
394
- )
395
- );
396
- })
397
- );
398
- pendingExcludedIdsRef.current = stillPending;
399
- }
400
-
401
- setState({ loading: false, error: null, data: finalSorted });
402
- } catch (err: any) {
403
- if (err?.name === "AbortError") return;
404
- if (myReqId !== requestIdRef.current) return;
405
-
406
- // 远程失败:保留本地阶段结果
407
- setState((prev) => ({ ...prev, loading: false, error: null }));
408
- }
409
- }, [
410
- limit,
411
- sortBy,
412
- searchName,
413
- userId,
414
- imageOutputOnly,
415
- toolName,
416
- currentServer,
417
- syncServers,
418
- currentUserId,
419
- dispatch,
420
- ]);
421
-
422
- useEffect(() => {
423
- fetchData();
424
- return () => {
425
- abortRef.current?.abort();
426
- };
427
- }, [
428
- fetchData,
429
- imageOutputOnly,
430
- initialData.length,
431
- reloadMode,
432
- searchName,
433
- sortBy,
434
- toolName,
435
- userId,
436
- ]);
437
-
438
- const retry = useCallback((excludedAgentIds: string[] = []) => {
439
- if (excludedAgentIds.length > 0) {
440
- pendingExcludedIdsRef.current = new Set([
441
- ...pendingExcludedIdsRef.current,
442
- ...excludedAgentIds.map((value) => String(value)),
443
- ]);
444
- }
445
-
446
- setState((prev) => {
447
- const nextData =
448
- excludedAgentIds.length > 0
449
- ? prev.data.filter(
450
- (agent) =>
451
- !matchesExcludedAgent(
452
- agent,
453
- new Set(excludedAgentIds.map((value) => String(value)))
454
- )
455
- )
456
- : prev.data;
457
- return {
458
- ...prev,
459
- data: nextData,
460
- loading:
461
- reloadMode === "catalog" &&
462
- excludedAgentIds.length === 0 &&
463
- nextData.length === 0,
464
- error: null,
465
- };
466
- });
467
- if (reloadMode === "catalog") {
468
- fetchData();
469
- }
470
- }, [fetchData]);
471
-
472
- return { ...state, retry };
473
- }
@@ -1,95 +0,0 @@
1
- export type MachineRunPermissionMode = "read_only" | "full_access";
2
-
3
- export type MachineRunPermissionPolicy = {
4
- mode: MachineRunPermissionMode;
5
- allowFilesystemRead: boolean;
6
- allowFilesystemWrite: boolean;
7
- allowShell: boolean;
8
- writableRoots: string[];
9
- };
10
-
11
- const DEFAULT_POLICY: MachineRunPermissionPolicy = {
12
- mode: "read_only",
13
- allowFilesystemRead: true,
14
- allowFilesystemWrite: false,
15
- allowShell: false,
16
- writableRoots: [],
17
- };
18
-
19
- const WRITE_DENIED =
20
- "Machine permission denied: this bound machine agent is read-only for filesystem writes. Enable machine write permission for this agent before asking it to modify files.";
21
-
22
- const SHELL_DENIED =
23
- "Machine permission denied: this bound machine agent cannot run arbitrary shell commands. Enable machine shell permission for this agent before asking it to execute commands.";
24
-
25
- function asObject(value: unknown): Record<string, any> {
26
- return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, any> : {};
27
- }
28
-
29
- function normalizeWritableRoots(value: unknown): string[] {
30
- if (!Array.isArray(value)) return [];
31
- return value
32
- .filter((item): item is string => typeof item === "string")
33
- .map((item) => item.trim())
34
- .filter(Boolean);
35
- }
36
-
37
- export function resolveMachineRunPermissionPolicy(agentConfig: any): MachineRunPermissionPolicy {
38
- const runtimeBinding = asObject(agentConfig?.runtimeBinding);
39
- const raw = asObject(
40
- agentConfig?.machinePermissions ??
41
- runtimeBinding.permissions ??
42
- runtimeBinding.machinePermissions ??
43
- agentConfig?.boundRuntimeMachine?.permissions
44
- );
45
-
46
- const mode: MachineRunPermissionMode =
47
- raw.mode === "full_access" || raw.allowFilesystemWrite === true || raw.allowShell === true
48
- ? "full_access"
49
- : "read_only";
50
-
51
- if (mode === "full_access") {
52
- return {
53
- mode,
54
- allowFilesystemRead: raw.allowFilesystemRead !== false,
55
- allowFilesystemWrite: true,
56
- allowShell: raw.allowShell !== false,
57
- writableRoots: normalizeWritableRoots(raw.writableRoots),
58
- };
59
- }
60
-
61
- return {
62
- ...DEFAULT_POLICY,
63
- allowFilesystemRead: raw.allowFilesystemRead !== false,
64
- };
65
- }
66
-
67
- const WRITE_INTENT_RE =
68
- /\b(write|overwrite|edit|modify|delete|remove|rename|move|create|save|patch|apply patch|mkdir|touch|rm|rmdir|del|erase|copy-item|move-item|remove-item|set-content|add-content|new-item)\b|[\u5199\u5220\u6539\u4FEE\u4FDD\u5B58\u521B\u5EFA\u79FB\u52A8]/i;
69
-
70
- const SHELL_INTENT_RE =
71
- /\b(run|execute|exec|shell|terminal|powershell|pwsh|bash|zsh|cmd\.exe|npm|bun|node|python|git|curl|wget|ssh|scp|chmod|chown|sudo)\b|[\u8FD0\u884C\u6267\u884C\u547D\u4EE4\u7EC8\u7AEF]/i;
72
-
73
- export function assertMachineRunAllowed(userInput: string, policy: MachineRunPermissionPolicy) {
74
- const task = String(userInput || "");
75
- if (!policy.allowFilesystemWrite && WRITE_INTENT_RE.test(task)) {
76
- throw new Error(WRITE_DENIED);
77
- }
78
- if (!policy.allowShell && SHELL_INTENT_RE.test(task)) {
79
- throw new Error(SHELL_DENIED);
80
- }
81
- }
82
-
83
- export function buildMachinePermissionPromptBlock(policy: MachineRunPermissionPolicy) {
84
- return [
85
- "--- Machine permission policy ---",
86
- `Mode: ${policy.mode}`,
87
- `Filesystem reads are ${policy.allowFilesystemRead ? "allowed" : "not allowed"}.`,
88
- `File writes are ${policy.allowFilesystemWrite ? "allowed" : "not allowed"}.`,
89
- `Arbitrary shell commands are ${policy.allowShell ? "allowed" : "not allowed"}.`,
90
- policy.writableRoots.length
91
- ? `Writable roots: ${policy.writableRoots.join(", ")}`
92
- : "Writable roots: none.",
93
- "If the user asks for an operation outside this policy, refuse instead of attempting it.",
94
- ].join("\n");
95
- }
@@ -1,37 +0,0 @@
1
- import { DataType } from "create/types";
2
- import { write } from "database/dbSlice";
3
- import { addUserMessage } from "chat/messages/messageSlice";
4
- import type { Message } from "chat/messages/types";
5
-
6
- export async function persistMessageWithFixedId(
7
- dispatch: any,
8
- message: Message
9
- ): Promise<void> {
10
- dispatch(addUserMessage(message));
11
-
12
- const { controller, ...messageToWrite } = message;
13
-
14
- try {
15
- const writeRequest = dispatch(
16
- write({
17
- data: {
18
- ...messageToWrite,
19
- type: DataType.MSG,
20
- },
21
- customKey: message.dbKey,
22
- })
23
- );
24
-
25
- if (writeRequest && typeof writeRequest.unwrap === "function") {
26
- await writeRequest.unwrap();
27
- return;
28
- }
29
-
30
- await writeRequest;
31
- } catch (error) {
32
- console.error(
33
- "[persistMessageWithFixedId] Failed to persist fixed-id message:",
34
- error
35
- );
36
- }
37
- }