nolo-cli 0.1.13 → 0.1.14

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 (320) hide show
  1. package/README.md +9 -2
  2. package/agent-runtime/hostAdapter.ts +53 -0
  3. package/agent-runtime/index.ts +28 -0
  4. package/agent-runtime/localLoop.ts +62 -0
  5. package/agent-runtime/runtimeDecision.ts +70 -0
  6. package/agent-runtime/types.ts +87 -0
  7. package/agentRuntimeCommands.ts +139 -22
  8. package/agentRuntimeLocal.ts +7 -0
  9. package/ai/agent/_executeModel.ts +118 -0
  10. package/ai/agent/agentSlice.ts +544 -1
  11. package/ai/agent/appWorkingMemory.ts +126 -0
  12. package/ai/agent/avatarUtils.ts +24 -0
  13. package/ai/agent/buildEditingContext.ts +373 -0
  14. package/ai/agent/buildSystemPrompt.ts +532 -0
  15. package/ai/agent/cleanAgentMessages.ts +140 -0
  16. package/ai/agent/cliChatClient.ts +119 -0
  17. package/ai/agent/contextCompiler.ts +107 -0
  18. package/ai/agent/contextLayerContract.ts +44 -0
  19. package/ai/agent/createAgentSchema.ts +234 -0
  20. package/ai/agent/executeToolCall.ts +58 -0
  21. package/ai/agent/fetchAgentContexts.ts +42 -0
  22. package/ai/agent/generatePrompt.ts +3 -0
  23. package/ai/agent/getFullChatContextKeys.ts +168 -0
  24. package/ai/agent/hooks/fetchPublicAgents.ts +133 -0
  25. package/ai/agent/hooks/useAgentConfig.ts +61 -0
  26. package/ai/agent/hooks/useAgentDialog.ts +35 -0
  27. package/ai/agent/hooks/useAgentFormValidation.ts +202 -0
  28. package/ai/agent/hooks/usePublicAgents.ts +473 -0
  29. package/ai/agent/persistMessageWithFixedId.ts +37 -0
  30. package/ai/agent/planSlice.ts +259 -0
  31. package/ai/agent/referenceUtils.ts +229 -0
  32. package/ai/agent/runAgentBackground.ts +238 -0
  33. package/ai/agent/runAgentClientLoop.ts +138 -0
  34. package/ai/agent/runtimeGuidance.ts +97 -0
  35. package/ai/agent/runtimeServerBase.ts +37 -0
  36. package/ai/agent/server/fetchPublicAgents.ts +128 -0
  37. package/ai/agent/startParallelAgentStreams.ts +424 -0
  38. package/ai/agent/startupProtocol.ts +53 -0
  39. package/ai/agent/streamAgentChatTurn.ts +1299 -0
  40. package/ai/agent/streamAgentChatTurnUtils.ts +738 -0
  41. package/ai/agent/types.ts +71 -0
  42. package/ai/agent/utils/imageOutput.ts +39 -0
  43. package/ai/agent/utils/publicImageAgentMode.ts +26 -0
  44. package/ai/agent/utils/sortUtils.ts +250 -0
  45. package/ai/agent/web/referencePickerUtils.ts +146 -0
  46. package/ai/ai.locale.ts +1083 -0
  47. package/ai/chat/accumulateToolCallChunks.ts +95 -0
  48. package/ai/chat/fetchUtils.native.ts +276 -0
  49. package/ai/chat/fetchUtils.ts +153 -0
  50. package/ai/chat/inlineImageUrlsForCustomProvider.ts +117 -0
  51. package/ai/chat/parseApiError.ts +64 -0
  52. package/ai/chat/parseMultilineSSE.ts +95 -0
  53. package/ai/chat/sendOpenAICompletionsRequest.native.ts +682 -0
  54. package/ai/chat/sendOpenAICompletionsRequest.ts +712 -0
  55. package/ai/chat/sendOpenAIResponseRequest.ts +512 -0
  56. package/ai/chat/shouldUseServerProxy.ts +18 -0
  57. package/ai/chat/sseClient.native.ts +91 -0
  58. package/ai/chat/sseClient.ts +67 -0
  59. package/ai/chat/streamReader.native.ts +31 -0
  60. package/ai/chat/streamReader.ts +62 -0
  61. package/ai/chat/updateTotalUsage.ts +72 -0
  62. package/ai/context/buildReferenceContext.ts +437 -0
  63. package/ai/context/calculateContextUsage.ts +133 -0
  64. package/ai/context/retention.ts +165 -0
  65. package/ai/context/tokenUtils.ts +78 -0
  66. package/ai/index.ts +1 -1
  67. package/ai/llm/agentCapabilities.ts +74 -0
  68. package/ai/llm/calculateGeminiImageTokens.ts +57 -0
  69. package/ai/llm/deepinfra.ts +28 -0
  70. package/ai/llm/fireworks.ts +68 -0
  71. package/ai/llm/generateRequestBody.ts +165 -0
  72. package/ai/llm/getModelContextWindow.ts +84 -0
  73. package/ai/llm/getNoloKey.ts +37 -0
  74. package/ai/llm/getPricing.ts +232 -0
  75. package/ai/llm/hooks/useModelPricing.ts +75 -0
  76. package/ai/llm/imagePricing.ts +66 -0
  77. package/ai/llm/isResponseAPIModel.ts +13 -0
  78. package/ai/llm/kimi.ts +18 -0
  79. package/ai/llm/mimo.ts +71 -0
  80. package/ai/llm/mistral.ts +22 -0
  81. package/ai/llm/modelAvatar.ts +427 -0
  82. package/ai/llm/models.ts +45 -0
  83. package/ai/llm/openrouterModels.ts +141 -0
  84. package/ai/llm/providers.ts +307 -0
  85. package/ai/llm/reasoningModels.ts +28 -0
  86. package/ai/llm/types.ts +59 -0
  87. package/ai/llm/usageRequestOptions.ts +59 -0
  88. package/ai/memory/capture.ts +148 -0
  89. package/ai/memory/consolidate.ts +104 -0
  90. package/ai/memory/delete.ts +147 -0
  91. package/ai/memory/overlay.ts +84 -0
  92. package/ai/memory/query.ts +38 -0
  93. package/ai/memory/queryShared.ts +160 -0
  94. package/ai/memory/rank.ts +105 -0
  95. package/ai/memory/recentRelationshipRecap.ts +247 -0
  96. package/ai/memory/remember.ts +167 -0
  97. package/ai/memory/runtime.ts +76 -0
  98. package/ai/memory/store.ts +20 -0
  99. package/ai/memory/storeShared.ts +76 -0
  100. package/ai/memory/types.ts +46 -0
  101. package/ai/memory/understanding.ts +349 -0
  102. package/ai/memory/understandingGreeting.ts +264 -0
  103. package/ai/messages/type.ts +20 -0
  104. package/ai/policy/personalizationDialog.ts +333 -0
  105. package/ai/policy/runtimePolicy.ts +440 -0
  106. package/ai/policy/selfUpdateFields.ts +48 -0
  107. package/ai/policy/types.ts +64 -0
  108. package/ai/skills/referenceRuntime.ts +274 -0
  109. package/ai/skills/skillDiagnostics.ts +251 -0
  110. package/ai/skills/skillDocBuilder.ts +139 -0
  111. package/ai/skills/skillDocProtocol.ts +434 -0
  112. package/ai/skills/skillReferenceSummary.ts +63 -0
  113. package/ai/skills/skillSummaryMarker.ts +26 -0
  114. package/ai/token/calculatePrice.ts +546 -0
  115. package/ai/token/db.ts +98 -0
  116. package/ai/token/externalToolCost.ts +321 -0
  117. package/ai/token/hooks/useRecords.ts +65 -0
  118. package/ai/token/missingUsageEstimate.ts +42 -0
  119. package/ai/token/modelUsageQuery.ts +252 -0
  120. package/ai/token/normalizeUsage.ts +84 -0
  121. package/ai/token/openaiImageGenerationUsage.ts +56 -0
  122. package/ai/token/prepareTokenUsageData.ts +88 -0
  123. package/ai/token/query.ts +88 -0
  124. package/ai/token/queryUserTokens.ts +59 -0
  125. package/ai/token/resolveBillingTarget.ts +52 -0
  126. package/ai/token/saveTokenRecord.ts +53 -0
  127. package/ai/token/serverDialogProjection.ts +78 -0
  128. package/ai/token/serverTokenWriter.ts +143 -0
  129. package/ai/token/stats.ts +21 -0
  130. package/ai/token/tokenThunks.ts +24 -0
  131. package/ai/token/types.ts +93 -0
  132. package/ai/tools/agent/agentTools.ts +176 -0
  133. package/ai/tools/agent/agentUpdateShared.ts +311 -0
  134. package/ai/tools/agent/callAgentTool.ts +139 -0
  135. package/ai/tools/agent/createAgentTool.ts +512 -0
  136. package/ai/tools/agent/createDialogTool.ts +69 -0
  137. package/ai/tools/agent/createSkillAgentTool.ts +62 -0
  138. package/ai/tools/agent/parallelBudget.ts +221 -0
  139. package/ai/tools/agent/presets/appBuilderPreset.ts +147 -0
  140. package/ai/tools/agent/runLlmTool.ts +96 -0
  141. package/ai/tools/agent/runStreamingAgentTool.ts +73 -0
  142. package/ai/tools/agent/skillAgentArgs.ts +106 -0
  143. package/ai/tools/agent/skillAgentPreset.ts +89 -0
  144. package/ai/tools/agent/streamParallelAgentsTool.ts +122 -0
  145. package/ai/tools/agent/updateAgentTool.ts +96 -0
  146. package/ai/tools/agent/updateSelfTool.ts +113 -0
  147. package/ai/tools/amazonProductScraperTool.ts +86 -0
  148. package/ai/tools/apifyActorClient.ts +45 -0
  149. package/ai/tools/appEditGuard.ts +372 -0
  150. package/ai/tools/appReadSnapshot.ts +153 -0
  151. package/ai/tools/appTools.ts +1549 -0
  152. package/ai/tools/applyEditTool.ts +256 -0
  153. package/ai/tools/applyLineEditsTool.ts +312 -0
  154. package/ai/tools/browserTools/click.ts +33 -0
  155. package/ai/tools/browserTools/closeSession.ts +29 -0
  156. package/ai/tools/browserTools/common.ts +27 -0
  157. package/ai/tools/browserTools/openSession.ts +48 -0
  158. package/ai/tools/browserTools/readContent.ts +38 -0
  159. package/ai/tools/browserTools/selectOption.ts +46 -0
  160. package/ai/tools/browserTools/typeText.ts +42 -0
  161. package/ai/tools/category/createCategoryTool.ts +66 -0
  162. package/ai/tools/category/queryContentsByCategoryTool.ts +69 -0
  163. package/ai/tools/category/updateContentCategoryTool.ts +75 -0
  164. package/ai/tools/cfBrowserTools.ts +319 -0
  165. package/ai/tools/cfSpeechToTextTool.ts +49 -0
  166. package/ai/tools/checkEnvTool.ts +65 -0
  167. package/ai/tools/cloudflareCrawlTool.ts +289 -0
  168. package/ai/tools/codeSearchTool.ts +111 -0
  169. package/ai/tools/codeTools.ts +101 -0
  170. package/ai/tools/createDocTool.ts +132 -0
  171. package/ai/tools/createPlanTool.ts +999 -0
  172. package/ai/tools/createSkillDocTool.ts +155 -0
  173. package/ai/tools/createWorkflowTool.ts +154 -0
  174. package/ai/tools/deepseekOcrTool.ts +34 -0
  175. package/ai/tools/delayTool.ts +31 -0
  176. package/ai/tools/deleteSpacesTool.ts +325 -0
  177. package/ai/tools/deleteSpacesToolModel.ts +159 -0
  178. package/ai/tools/devReloadUtils.ts +29 -0
  179. package/ai/tools/dialogMessageSearch.ts +137 -0
  180. package/ai/tools/doctorSkillTool.ts +72 -0
  181. package/ai/tools/ecommerceScraperTool.ts +86 -0
  182. package/ai/tools/emailTools.ts +549 -0
  183. package/ai/tools/evalSkillTool.ts +92 -0
  184. package/ai/tools/exaSearchTool.ts +64 -0
  185. package/ai/tools/execBashTool.ts +379 -0
  186. package/ai/tools/executeSqlTool.ts +192 -0
  187. package/ai/tools/fetchWebpageSupport.ts +309 -0
  188. package/ai/tools/fetchWebpageTool.ts +84 -0
  189. package/ai/tools/geminiImagePreviewTool.ts +361 -0
  190. package/ai/tools/generateDocxTool.ts +215 -0
  191. package/ai/tools/googleSearchScraperTool.ts +106 -0
  192. package/ai/tools/importDataTool.ts +133 -0
  193. package/ai/tools/importSkillTool.ts +162 -0
  194. package/ai/tools/index.ts +1927 -0
  195. package/ai/tools/listFilesTool.ts +82 -0
  196. package/ai/tools/listUserSpacesTool.ts +113 -0
  197. package/ai/tools/modelUsageTools.ts +199 -0
  198. package/ai/tools/olmOcrTool.ts +34 -0
  199. package/ai/tools/openaiImageTool.ts +267 -0
  200. package/ai/tools/prepareTools.ts +23 -0
  201. package/ai/tools/readDocTool.ts +84 -0
  202. package/ai/tools/readFileTool.ts +211 -0
  203. package/ai/tools/readTool.ts +163 -0
  204. package/ai/tools/readXPostTool.ts +233 -0
  205. package/ai/tools/rememberMemoryTool.ts +84 -0
  206. package/ai/tools/remotionVideoTool.ts +151 -0
  207. package/ai/tools/searchDialogMessagesTool.ts +222 -0
  208. package/ai/tools/searchRepoTool.ts +115 -0
  209. package/ai/tools/searchWorkspaceTool.ts +259 -0
  210. package/ai/tools/skillFollowup.ts +86 -0
  211. package/ai/tools/surfWeatherTool.ts +169 -0
  212. package/ai/tools/table/addTableRowTool.ts +217 -0
  213. package/ai/tools/table/createTableTool.ts +315 -0
  214. package/ai/tools/table/rowTools.ts +366 -0
  215. package/ai/tools/table/schemaTools.ts +244 -0
  216. package/ai/tools/table/shareTableTool.ts +148 -0
  217. package/ai/tools/table/toolShared.ts +129 -0
  218. package/ai/tools/toolApiClient.ts +198 -0
  219. package/ai/tools/toolNameAliases.ts +57 -0
  220. package/ai/tools/toolResultError.ts +42 -0
  221. package/ai/tools/toolRunSlice.ts +303 -0
  222. package/ai/tools/toolSchemaCompatibility.ts +53 -0
  223. package/ai/tools/toolVisibility.ts +4 -0
  224. package/ai/tools/types.ts +20 -0
  225. package/ai/tools/uiAskChoiceTool.ts +104 -0
  226. package/ai/tools/updateContentTitleTool.ts +84 -0
  227. package/ai/tools/updateDocTool.ts +105 -0
  228. package/ai/tools/updateUserPreferenceProfileTool.ts +145 -0
  229. package/ai/tools/whisperTool.ts +77 -0
  230. package/ai/tools/writeFileTool.ts +210 -0
  231. package/ai/tools/youtubeScraperTool.ts +116 -0
  232. package/ai/tools/ziweiChartTool.ts +678 -0
  233. package/ai/types.ts +55 -0
  234. package/ai/workflow/workflowExecutor.ts +323 -0
  235. package/ai/workflow/workflowSlice.ts +73 -0
  236. package/ai/workflow/workflowTypes.ts +106 -0
  237. package/client/agentRun.test.ts +240 -0
  238. package/client/agentRun.ts +182 -19
  239. package/client/compactDialog.test.ts +238 -0
  240. package/client/localRuntimeAdapter.test.ts +135 -0
  241. package/client/localRuntimeAdapter.ts +244 -0
  242. package/client/profileConfig.test.ts +40 -0
  243. package/client/streamingOutput.test.ts +22 -0
  244. package/client/streamingOutput.ts +38 -0
  245. package/commandRegistry.ts +9 -2
  246. package/connector-experimental/index.ts +5 -0
  247. package/database/actions/cacheMergedUserData.ts +64 -0
  248. package/database/actions/common.ts +242 -0
  249. package/database/actions/deleteFile.ts +40 -0
  250. package/database/actions/fetchUserData.ts +16 -0
  251. package/database/actions/fileContent.ts +125 -0
  252. package/database/actions/patch.ts +155 -0
  253. package/database/actions/read.ts +337 -0
  254. package/database/actions/readAndWait.ts +224 -0
  255. package/database/actions/readRequestManager.ts +120 -0
  256. package/database/actions/remove.ts +94 -0
  257. package/database/actions/replication.ts +366 -0
  258. package/database/actions/upload.ts +174 -0
  259. package/database/actions/upsert.ts +56 -0
  260. package/database/actions/write.ts +126 -0
  261. package/database/client/db.native.ts +73 -0
  262. package/database/client/db.ts +51 -0
  263. package/database/client/fetchUserData.ts +61 -0
  264. package/database/client/handleError.ts +19 -0
  265. package/database/client/queryRequest.ts +21 -0
  266. package/database/config.ts +21 -0
  267. package/database/dbActionThunks.ts +1 -0
  268. package/database/dbSlice.ts +149 -0
  269. package/database/email.ts +42 -0
  270. package/database/fileRing.ts +51 -0
  271. package/database/fileSharding.ts +70 -0
  272. package/database/fileStorage.native.ts +92 -0
  273. package/database/fileStorage.ts +232 -0
  274. package/database/fileUrl.ts +34 -0
  275. package/database/hooks/useUserData.ts +489 -0
  276. package/database/index.ts +1 -0
  277. package/database/keys.ts +765 -0
  278. package/database/queryPrefixes.ts +14 -0
  279. package/database/requests.ts +443 -0
  280. package/database/runtimeServerContext.ts +35 -0
  281. package/database/server/MemoryDB.ts +76 -0
  282. package/database/server/actorAccess.ts +76 -0
  283. package/database/server/agentDelegation.ts +124 -0
  284. package/database/server/coreDataOwnership.ts +13 -0
  285. package/database/server/coreDataProxy.ts +76 -0
  286. package/database/server/cybotReadonly.ts +18 -0
  287. package/database/server/dataHandlers.ts +111 -0
  288. package/database/server/db.ts +118 -0
  289. package/database/server/dbPath.ts +20 -0
  290. package/database/server/delete.ts +499 -0
  291. package/database/server/emailRepository.ts +1480 -0
  292. package/database/server/ensureDbOpen.ts +12 -0
  293. package/database/server/fileRead.ts +337 -0
  294. package/database/server/fileService.ts +436 -0
  295. package/database/server/handleTransaction.ts +86 -0
  296. package/database/server/patch.ts +282 -0
  297. package/database/server/query.ts +138 -0
  298. package/database/server/read.ts +325 -0
  299. package/database/server/resourceAccess.ts +211 -0
  300. package/database/server/routes.ts +110 -0
  301. package/database/server/spaceMemberAuthority.ts +67 -0
  302. package/database/server/upload.ts +159 -0
  303. package/database/server/write.ts +494 -0
  304. package/database/server/writeAuthority.ts +133 -0
  305. package/database/sqliteDb.ts +46 -0
  306. package/database/table/deleteTable.ts +120 -0
  307. package/database/tenantPlacement.ts +57 -0
  308. package/database/tombstones.ts +52 -0
  309. package/database/userDataLoadDecision.ts +17 -0
  310. package/database/userDataMerge.ts +95 -0
  311. package/database/userPreferenceRegister.ts +108 -0
  312. package/database/utils/dbPath.ts +47 -0
  313. package/database/utils/ulid.native.ts +6 -0
  314. package/database/utils/ulid.ts +1 -0
  315. package/index.ts +25 -15
  316. package/localRuntimeDb.ts +28 -0
  317. package/package.json +16 -4
  318. package/runtimeModeArgs.ts +33 -0
  319. package/tui/readlineWorkspace.ts +1 -0
  320. package/tui/session.ts +22 -0
@@ -0,0 +1,168 @@
1
+
2
+ // packages/ai/agent/getFullChatContextKeys.ts
3
+ import { RootState } from "app/store";
4
+ import { selectAllMsgs } from "chat/messages/messageSlice";
5
+ import type { DialogConfig } from "app/types";
6
+ import { extractCustomId } from "core/prefix";
7
+
8
+ /** 简单的数组差集工具:返回 arrA 中不在 arrB 里的元素 */
9
+ const difference = <T>(arrA: T[], arrB: T[]): T[] => {
10
+ if (!arrA.length) return [];
11
+ if (!arrB.length) return [...arrA];
12
+
13
+ const exclude = new Set(arrB);
14
+ return arrA.filter((item) => !exclude.has(item));
15
+ };
16
+
17
+ /**
18
+ * Collect all possible reference keys for this chat turn:
19
+ * - botInstructionKeys: keys from agentConfig.references of type "instruction"
20
+ * - botKnowledgeKeys: keys from agentConfig.references (non-instruction)
21
+ * - currentInputKeys: keys referenced directly by the user's current input (array parts with pageKey)
22
+ * - historyKeys: keys from all previous messages' content parts
23
+ */
24
+ export const getFullChatContextKeys = async (
25
+ state: RootState,
26
+ dispatch: any,
27
+ agentConfig: any,
28
+ userInput: string | any[],
29
+ dialogConfig?: DialogConfig
30
+ ): Promise<Record<string, Set<string>>> => {
31
+ const msgs = selectAllMsgs(
32
+ state,
33
+ dialogConfig?.dbKey
34
+ ? extractCustomId(dialogConfig.dbKey)
35
+ : dialogConfig?.id
36
+ );
37
+
38
+ const botInstructionKeys = new Set<string>();
39
+ const botKnowledgeKeys = new Set<string>();
40
+
41
+ if (Array.isArray(agentConfig.references)) {
42
+ for (const ref of agentConfig.references as Array<{
43
+ dbKey: string;
44
+ type: string;
45
+ }>) {
46
+ if (!ref?.dbKey) continue;
47
+ if (ref.type === "instruction") {
48
+ botInstructionKeys.add(ref.dbKey);
49
+ } else {
50
+ botKnowledgeKeys.add(ref.dbKey);
51
+ }
52
+ }
53
+ }
54
+
55
+ const currentInputKeys = new Set<string>();
56
+ if (Array.isArray(userInput)) {
57
+ for (const part of userInput) {
58
+ if (part?.pageKey) currentInputKeys.add(part.pageKey);
59
+ if (part?.dialogKey) currentInputKeys.add(part.dialogKey);
60
+ }
61
+ }
62
+
63
+ const historyKeys = new Set<string>();
64
+
65
+ // 1. 从 DialogConfig.referenceKeys 读取(这是主要的、持久化的引用来源)
66
+ // 即使消息被压缩,这里的 keys 也会保留
67
+ const savedKeys = dialogConfig?.referenceKeys;
68
+ if (Array.isArray(savedKeys)) {
69
+ savedKeys.forEach((k: string) => historyKeys.add(k));
70
+ }
71
+
72
+ // 2. 仅扫描尚未被压缩的近期消息
73
+ // 已压缩的消息(summarizedBeforeId 之前的部分,包含该条本身)的 keys
74
+ // 已在压缩时存入 dialogConfig.referenceKeys,步骤 1 已覆盖,无需重复扫描。
75
+ const scanContentParts = (msg: any) => {
76
+ if (!msg.content) return;
77
+ const contentParts = Array.isArray(msg.content) ? msg.content : [msg.content];
78
+ for (const part of contentParts) {
79
+ if (part && typeof part === 'object') {
80
+ if (part?.pageKey) historyKeys.add(part.pageKey);
81
+ if (part?.dialogKey) historyKeys.add(part.dialogKey);
82
+ }
83
+ }
84
+ };
85
+
86
+ if (msgs && msgs.length > 0) {
87
+ const summarizedBeforeId = dialogConfig?.summarizedBeforeId;
88
+
89
+ if (!summarizedBeforeId) {
90
+ // 无压缩记录,扫描全部消息
91
+ for (const msg of (msgs as any[])) scanContentParts(msg);
92
+ } else {
93
+ let foundMarker = false;
94
+ let startScan = false;
95
+
96
+ for (const msg of (msgs as any[])) {
97
+ if (!startScan) {
98
+ if (msg.id === summarizedBeforeId) {
99
+ foundMarker = true;
100
+ startScan = true;
101
+ // summarizedBeforeId 那条消息本身已被压缩,keys 在 referenceKeys 里,跳过
102
+ }
103
+ continue;
104
+ }
105
+ scanContentParts(msg);
106
+ }
107
+
108
+ // marker 找不到说明 Redux 中的消息都是新的,应该全扫
109
+ if (!foundMarker) {
110
+ console.warn(`[getFullChatContextKeys] marker ${summarizedBeforeId} not found, scanning all`);
111
+ for (const msg of (msgs as any[])) scanContentParts(msg);
112
+ }
113
+ }
114
+ }
115
+
116
+ return {
117
+ botInstructionKeys,
118
+ currentInputKeys,
119
+ historyKeys,
120
+ botKnowledgeKeys,
121
+ };
122
+ };
123
+
124
+ /**
125
+ * Deduplicate keys across priority levels.
126
+ * Priority order (high -> low):
127
+ * 1) botInstructionKeys
128
+ * 2) currentInputKeys
129
+ * 3) historyKeys
130
+ * 4) botKnowledgeKeys
131
+ *
132
+ * Return field names match context block identifiers expected downstream.
133
+ */
134
+ export const deduplicateContextKeys = (
135
+ keys: Record<string, Set<string>>
136
+ ): Record<string, string[]> => {
137
+ const {
138
+ botInstructionKeys,
139
+ currentInputKeys,
140
+ historyKeys,
141
+ botKnowledgeKeys,
142
+ } = keys;
143
+
144
+ const finalBotInstructionKeys = Array.from(botInstructionKeys);
145
+
146
+ const finalCurrentInputKeys = difference(
147
+ Array.from(currentInputKeys),
148
+ finalBotInstructionKeys
149
+ );
150
+
151
+ const finalHistoryKeys = difference(Array.from(historyKeys), [
152
+ ...finalBotInstructionKeys,
153
+ ...finalCurrentInputKeys,
154
+ ]);
155
+
156
+ const finalBotKnowledgeKeys = difference(Array.from(botKnowledgeKeys), [
157
+ ...finalBotInstructionKeys,
158
+ ...finalCurrentInputKeys,
159
+ ...finalHistoryKeys,
160
+ ]);
161
+
162
+ return {
163
+ botInstructionsContext: finalBotInstructionKeys,
164
+ currentInputContext: finalCurrentInputKeys,
165
+ historyContext: finalHistoryKeys,
166
+ botKnowledgeContext: finalBotKnowledgeKeys,
167
+ };
168
+ };
@@ -0,0 +1,133 @@
1
+ import { getDb } from "database/client/db";
2
+ import { pino } from "pino";
3
+ import { pubAgentKeys } from "database/keys";
4
+ import { Agent } from "app/types";
5
+ import { supportsImageGeneration } from "ai/agent/utils/imageOutput";
6
+ import { getRecordTimestamp, isTombstoneRecord } from "database/tombstones";
7
+ import { buildSortMeta, sortAgents } from "ai/agent/utils/sortUtils";
8
+
9
+ const logger = pino({ name: "fetchPublicAgents" });
10
+
11
+ interface FetchPublicAgentsOptions {
12
+ limit?: number;
13
+ sortBy?:
14
+ | "recommended"
15
+ | "newest"
16
+ | "popular"
17
+ | "rating"
18
+ | "outputPriceAsc"
19
+ | "outputPriceDesc"
20
+ | "favorite";
21
+ searchName?: string;
22
+ userId?: string;
23
+ imageOutputOnly?: boolean;
24
+ toolName?: string;
25
+ }
26
+
27
+ interface PublicAgentTombstone {
28
+ id?: string;
29
+ dbKey?: string;
30
+ deletedAt?: string | number;
31
+ updatedAt?: string | number;
32
+ createdAt?: string | number;
33
+ }
34
+
35
+ export interface FetchPublicAgentsResult {
36
+ data: Agent[];
37
+ total: number;
38
+ hasMore: boolean;
39
+ tombstones: PublicAgentTombstone[];
40
+ }
41
+
42
+ export async function fetchPublicAgents(
43
+ options: FetchPublicAgentsOptions = {}
44
+ ): Promise<FetchPublicAgentsResult> {
45
+ const {
46
+ limit = 20,
47
+ sortBy = "recommended",
48
+ searchName,
49
+ userId,
50
+ imageOutputOnly = false,
51
+ toolName,
52
+ } = options;
53
+
54
+ try {
55
+ const ranges = pubAgentKeys.allPublicRanges();
56
+ let results: Agent[] = [];
57
+ let tombstones: PublicAgentTombstone[] = [];
58
+
59
+ const db = getDb();
60
+ if (!db) return { data: [], total: 0, hasMore: false };
61
+
62
+ for (const { start, end } of ranges) {
63
+ const iterator = await db.iterator({
64
+ gte: start,
65
+ lte: end,
66
+ });
67
+ for await (const [, value] of iterator) {
68
+ if (!value?.isPublic) continue;
69
+ if (isTombstoneRecord(value)) {
70
+ tombstones.push(value as PublicAgentTombstone);
71
+ continue;
72
+ }
73
+ results.push(value as Agent);
74
+ }
75
+ }
76
+
77
+ if (searchName) {
78
+ const kw = searchName.toLowerCase();
79
+ results = results.filter((agent) =>
80
+ agent.name?.toLowerCase().includes(kw)
81
+ );
82
+ }
83
+
84
+ if (userId) {
85
+ results = results.filter((agent) => agent.userId === userId);
86
+ }
87
+
88
+ if (imageOutputOnly) {
89
+ results = results.filter((agent) => supportsImageGeneration(agent));
90
+ }
91
+
92
+ if (toolName) {
93
+ const kw = toolName.toLowerCase();
94
+ results = results.filter((agent) =>
95
+ agent.tools?.some((t) => t.toLowerCase().includes(kw))
96
+ );
97
+ }
98
+
99
+ results = sortAgents(
100
+ results.map((agent) => ({
101
+ ...(agent as any),
102
+ __sort: buildSortMeta(agent),
103
+ })),
104
+ sortBy
105
+ );
106
+
107
+ const paginatedResults = results.slice(0, limit);
108
+
109
+ logger.debug(
110
+ {
111
+ total: results.length,
112
+ returned: paginatedResults.length,
113
+ sortBy,
114
+ limit,
115
+ imageOutputOnly,
116
+ firstItemCreatedAt: paginatedResults[0]?.createdAt,
117
+ },
118
+ "Fetched public agents (local)"
119
+ );
120
+
121
+ return {
122
+ data: paginatedResults,
123
+ total: results.length,
124
+ hasMore: limit < results.length,
125
+ tombstones: tombstones.sort(
126
+ (left, right) => getRecordTimestamp(right) - getRecordTimestamp(left)
127
+ ),
128
+ };
129
+ } catch (error) {
130
+ logger.error({ error }, "Failed to fetch public agents (local)");
131
+ throw error;
132
+ }
133
+ }
@@ -0,0 +1,61 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ import type { Agent } from "app/types";
4
+ import { useAppDispatch, useAppSelector } from "app/store";
5
+ import { read } from "database/dbSlice";
6
+
7
+ import { selectCurrentDialogConfig } from "chat/dialog/dialogSlice";
8
+ import { getPrimaryDialogAgentId } from "chat/dialog/dialogAgents";
9
+
10
+ interface UseAgentConfigResult {
11
+ agentConfig: Agent | null;
12
+ isLoading: boolean;
13
+ }
14
+
15
+ const useAgentConfig = () => {
16
+ const dispatch = useAppDispatch();
17
+ const [agentConfig, setAgentConfig] = useState<Agent | null>(null);
18
+ const [isLoading, setIsLoading] = useState(false);
19
+
20
+ const currentDialogConfig = useAppSelector(selectCurrentDialogConfig);
21
+ const agentKey = getPrimaryDialogAgentId(currentDialogConfig);
22
+
23
+ useEffect(() => {
24
+ if (!agentKey) {
25
+ setAgentConfig(null);
26
+ setIsLoading(false);
27
+ return;
28
+ }
29
+
30
+ let cancelled = false;
31
+ setAgentConfig(null);
32
+ setIsLoading(true);
33
+
34
+ void (async () => {
35
+ try {
36
+ const result = (await dispatch(read({ dbKey: agentKey })).unwrap()) as Agent | null;
37
+ if (cancelled) return;
38
+ setAgentConfig(result);
39
+ } catch (error) {
40
+ if (cancelled) return;
41
+ console.warn("[useAgentConfig] Failed to load agent config:", error);
42
+ setAgentConfig(null);
43
+ } finally {
44
+ if (!cancelled) {
45
+ setIsLoading(false);
46
+ }
47
+ }
48
+ })();
49
+
50
+ return () => {
51
+ cancelled = true;
52
+ };
53
+ }, [agentKey, dispatch]);
54
+
55
+ return {
56
+ agentConfig,
57
+ isLoading,
58
+ } satisfies UseAgentConfigResult;
59
+ };
60
+
61
+ export default useAgentConfig;
@@ -0,0 +1,35 @@
1
+ // ai/agent/hooks/useAgentDialog.ts
2
+ import { useCallback } from "react";
3
+ import { useTranslation } from "react-i18next";
4
+ import toast from "react-hot-toast";
5
+ import { useCreateDialog } from "chat/dialog/useCreateDialog";
6
+
7
+ interface UseAgentDialogOptions {
8
+ spaceId?: string | null;
9
+ }
10
+
11
+ export function useAgentDialog(
12
+ agentKey: string,
13
+ options: UseAgentDialogOptions = {}
14
+ ) {
15
+ const { t } = useTranslation("ai");
16
+ const { isLoading, createNewDialog } = useCreateDialog();
17
+ const { spaceId } = options;
18
+
19
+ const startDialog = useCallback(async () => {
20
+ if (isLoading) return;
21
+ try {
22
+ await createNewDialog({
23
+ agents: [agentKey],
24
+ ...(spaceId ? { spaceId } : {}),
25
+ });
26
+ } catch (err: any) {
27
+ const msg = err?.message
28
+ ? `${t("createDialogError")}: ${err.message}`
29
+ : t("createDialogError");
30
+ toast.error(msg);
31
+ }
32
+ }, [agentKey, createNewDialog, isLoading, spaceId, t]);
33
+
34
+ return { isStarting: isLoading, startDialog };
35
+ }
@@ -0,0 +1,202 @@
1
+ // 路径: app/features/ai/agent/hooks/useAgentValidation.ts
2
+
3
+ import { useForm } from "react-hook-form";
4
+ import { zodResolver } from "@hookform/resolvers/zod";
5
+ import { useCallback } from "react";
6
+ import { useAppDispatch } from "app/store";
7
+ import { useAuth } from "auth/hooks/useAuth";
8
+ import { useCreateDialog } from "chat/dialog/useCreateDialog";
9
+ import { createAgentKey } from "database/keys";
10
+ import { useTranslation } from "react-i18next";
11
+ import { useAppSelector } from "app/store";
12
+ import {
13
+ addContentToSpace,
14
+ selectCurrentSpace,
15
+ selectCurrentSpaceId,
16
+ updateContentTitle,
17
+ } from "create/space/spaceSlice";
18
+ import {
19
+ getCreateAgentSchema,
20
+ FormData,
21
+ normalizeReferences,
22
+ } from "../createAgentSchema";
23
+ import { createAgent, updateAgent } from "ai/agent/agentSlice";
24
+ import { ContentType } from "app/types";
25
+ import { DEFAULT_MODEL } from "ai/llm/providers";
26
+
27
+ type AgentEditIdentityInput = Partial<ExtendedFormData> & {
28
+ dbKey?: string;
29
+ contentKey?: string;
30
+ };
31
+
32
+ // extractAgentId 函数:兼容 id 是路径或纯 id 的老数据 (包括 cybot 和 agent)
33
+ export const extractAgentId = (value: string): string => {
34
+ const raw = value.trim();
35
+ if (raw.startsWith("agent-") || raw.startsWith("cybot-")) {
36
+ const parts = raw.split("-");
37
+ if (parts.length >= 3) return parts[parts.length - 1];
38
+ }
39
+ return raw;
40
+ };
41
+
42
+ // ExtendedFormData:在原有表单数据上加上一些 meta 字段
43
+ interface ExtendedFormData extends FormData {
44
+ id?: string;
45
+ createdAt?: number;
46
+ dialogCount?: number;
47
+ messageCount?: number;
48
+ tokenCount?: number;
49
+ }
50
+
51
+ export const resolveAgentEditIdentity = (
52
+ initialValues?: AgentEditIdentityInput
53
+ ) => {
54
+ const rawAgentKey =
55
+ typeof initialValues?.dbKey === "string" && initialValues.dbKey.trim()
56
+ ? initialValues.dbKey.trim()
57
+ : typeof initialValues?.contentKey === "string" && initialValues.contentKey.trim()
58
+ ? initialValues.contentKey.trim()
59
+ : undefined;
60
+
61
+ const rawAgentId =
62
+ typeof initialValues?.id === "string" && initialValues.id.trim()
63
+ ? initialValues.id.trim()
64
+ : rawAgentKey;
65
+
66
+ const agentId = rawAgentId ? extractAgentId(rawAgentId) : undefined;
67
+
68
+ return {
69
+ agentKey: rawAgentKey,
70
+ agentId,
71
+ isEditing: Boolean(agentId),
72
+ };
73
+ };
74
+
75
+ export const useAgentValidation = (initialValues?: ExtendedFormData) => {
76
+ const dispatch = useAppDispatch();
77
+ const { createNewDialog } = useCreateDialog();
78
+ const auth = useAuth();
79
+ const { t } = useTranslation("ai");
80
+ const currentSpaceId = useAppSelector(selectCurrentSpaceId);
81
+ const currentSpace = useAppSelector(selectCurrentSpace);
82
+ const { agentId: resolvedAgentId, isEditing } =
83
+ resolveAgentEditIdentity(initialValues);
84
+
85
+ const form = useForm<FormData>({
86
+ resolver: zodResolver(getCreateAgentSchema(t)),
87
+ defaultValues: isEditing
88
+ ? {
89
+ ...initialValues,
90
+ // 如果老数据里没有 apiSource,则默认 platform
91
+ apiSource: initialValues.apiSource ?? "platform",
92
+ machineId: (initialValues as any).machineId ?? (initialValues as any).runtimeBinding?.machineId ?? "",
93
+ tags: Array.isArray(initialValues.tags)
94
+ ? initialValues.tags.join(", ")
95
+ : (initialValues.tags as any) || "",
96
+ references: normalizeReferences(initialValues.references || []),
97
+ whitelist: initialValues.whitelist || [],
98
+ }
99
+ : {
100
+ greeting: t("form.defaults.greeting"),
101
+ useServerProxy: true,
102
+ isPublic: false,
103
+ whitelist: [],
104
+ // 新建时默认为平台 API
105
+ apiSource: "platform",
106
+ provider: DEFAULT_MODEL.provider,
107
+ model: DEFAULT_MODEL.name,
108
+ },
109
+ });
110
+
111
+ const { watch } = form;
112
+
113
+ const onSubmit = useCallback(
114
+ async (data: FormData) => {
115
+ if (!auth.user?.userId) throw new Error(t("errors.noUserId"));
116
+
117
+ // -------- 编辑模式:走 updateAgent thunk --------
118
+ if (isEditing && resolvedAgentId) {
119
+ await dispatch(
120
+ updateAgent({
121
+ userId: auth.user.userId,
122
+ agentId: resolvedAgentId,
123
+ formData: data,
124
+ previousAgent: initialValues as any,
125
+ })
126
+ ).unwrap();
127
+
128
+ const contentKey = (initialValues as any).dbKey as string | undefined;
129
+ const nextName = String(data.name ?? "").trim();
130
+ const previousName = String(initialValues.name ?? "").trim();
131
+ if (
132
+ currentSpaceId &&
133
+ contentKey &&
134
+ currentSpace?.contents?.[contentKey] &&
135
+ nextName &&
136
+ nextName !== previousName
137
+ ) {
138
+ await dispatch(
139
+ updateContentTitle({
140
+ spaceId: currentSpaceId,
141
+ contentKey,
142
+ title: nextName,
143
+ })
144
+ ).unwrap();
145
+ }
146
+
147
+ return;
148
+ }
149
+
150
+ // -------- 新建模式:走 createAgent thunk,并在成功后创建默认对话 --------
151
+ const createdAgent = await dispatch(
152
+ createAgent({
153
+ userId: auth.user.userId,
154
+ formData: data,
155
+ spaceId: currentSpaceId || undefined, // 传入当前空间 ID
156
+ })
157
+ ).unwrap();
158
+
159
+ const agentDbKey = createdAgent.isPublic
160
+ ? createAgentKey.public(createdAgent.id)
161
+ : createAgentKey.private(auth.user.userId, createdAgent.id);
162
+
163
+ // 如果有当前空间,则将 Agent 添加到空间内容中,使其在侧边栏显示
164
+ if (currentSpaceId) {
165
+ try {
166
+ await dispatch((addContentToSpace as any)({
167
+ spaceId: currentSpaceId,
168
+ title: createdAgent.name || "未命名智能体",
169
+ type: ContentType.AGENT,
170
+ contentKey: agentDbKey,
171
+ })).unwrap();
172
+ } catch (error) {
173
+ console.error("Failed to add agent to space sidebar:", error);
174
+ }
175
+ }
176
+
177
+ await createNewDialog({
178
+ agents: [agentDbKey],
179
+ });
180
+ },
181
+ [
182
+ auth.user,
183
+ isEditing,
184
+ initialValues,
185
+ resolvedAgentId,
186
+ dispatch,
187
+ createNewDialog,
188
+ t,
189
+ currentSpaceId,
190
+ currentSpace,
191
+ ]
192
+ );
193
+
194
+ return {
195
+ form,
196
+ provider: watch("provider"),
197
+ useServerProxy: watch("useServerProxy"),
198
+ isPublic: watch("isPublic"),
199
+ onSubmit,
200
+ isEditing,
201
+ };
202
+ };