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,303 @@
1
+ // File: ai/tools/toolRunSlice.ts
2
+ import {
3
+ createSlice,
4
+ createEntityAdapter,
5
+ EntityState,
6
+ PayloadAction,
7
+ createAsyncThunk,
8
+ createSelector,
9
+ } from "@reduxjs/toolkit";
10
+ import type { RootState } from "app/store";
11
+ import type { ToolBehavior, ToolInteraction } from ".";
12
+ import { getToolResultErrorData } from "./toolResultError";
13
+
14
+ export type ToolRunStatus = "pending" | "running" | "succeeded" | "failed";
15
+ export type ToolRunStepStatus = ToolRunStatus;
16
+
17
+ export interface ToolRunStep {
18
+ id: string;
19
+ label: string;
20
+ status: ToolRunStepStatus;
21
+ detail?: string;
22
+ }
23
+
24
+ export interface ToolRun {
25
+ id: string;
26
+ messageId: string; // 这次工具调用属于哪条消息或步骤消息
27
+ toolName: string;
28
+ behavior?: ToolBehavior;
29
+ inputSummary?: string;
30
+ outputSummary?: string;
31
+ steps?: ToolRunStep[];
32
+ status: ToolRunStatus;
33
+ error?: string;
34
+ startedAt: number;
35
+ finishedAt?: number;
36
+
37
+ // 交互模式(从 ToolDefinition 抄过来)
38
+ interaction?: ToolInteraction;
39
+
40
+ // 保存本次调用的完整参数,后续确认或重放时会用到
41
+ input?: any;
42
+ }
43
+
44
+ const toolRunAdapter = createEntityAdapter<ToolRun>({
45
+ selectId: (run) => run.id,
46
+ sortComparer: (a, b) => a.startedAt - b.startedAt,
47
+ });
48
+
49
+ export interface ToolRunSliceState {
50
+ runs: EntityState<ToolRun>;
51
+ }
52
+
53
+ const initialState: ToolRunSliceState = {
54
+ runs: toolRunAdapter.getInitialState(),
55
+ };
56
+
57
+ export const createToolRunId = () =>
58
+ `toolrun_${Date.now().toString(36)}_${Math.random()
59
+ .toString(36)
60
+ .slice(2, 8)}`;
61
+
62
+ const toolRunSlice = createSlice({
63
+ name: "toolRun",
64
+ initialState,
65
+ reducers: {
66
+ toolRunStarted: (
67
+ state,
68
+ action: PayloadAction<{
69
+ id: string;
70
+ messageId: string;
71
+ toolName: string;
72
+ behavior?: ToolBehavior;
73
+ inputSummary?: string;
74
+ startedAt?: number;
75
+ interaction?: ToolInteraction;
76
+ input?: any;
77
+ }>
78
+ ) => {
79
+ const {
80
+ id,
81
+ messageId,
82
+ toolName,
83
+ behavior,
84
+ inputSummary,
85
+ startedAt,
86
+ interaction,
87
+ input,
88
+ } = action.payload;
89
+
90
+ // 每次开始(包括重试)都清空上一次的 error / 输出 / 结束时间
91
+ toolRunAdapter.upsertOne(state.runs, {
92
+ id,
93
+ messageId,
94
+ toolName,
95
+ behavior,
96
+ inputSummary,
97
+ status: "running",
98
+ startedAt: startedAt ?? Date.now(),
99
+ interaction,
100
+ input,
101
+ error: undefined,
102
+ finishedAt: undefined,
103
+ outputSummary: undefined,
104
+ steps: undefined,
105
+ });
106
+ },
107
+
108
+ // 把某个 ToolRun 状态设为 pending(用于“预览但未执行”的阶段)
109
+ toolRunSetPending: (
110
+ state,
111
+ action: PayloadAction<{
112
+ id: string;
113
+ }>
114
+ ) => {
115
+ const { id } = action.payload;
116
+ toolRunAdapter.updateOne(state.runs, {
117
+ id,
118
+ changes: {
119
+ status: "pending",
120
+ },
121
+ });
122
+ },
123
+
124
+ toolRunSucceeded: (
125
+ state,
126
+ action: PayloadAction<{
127
+ id: string;
128
+ outputSummary?: string;
129
+ steps?: ToolRunStep[];
130
+ finishedAt?: number;
131
+ }>
132
+ ) => {
133
+ const { id, outputSummary, steps, finishedAt } = action.payload;
134
+ toolRunAdapter.updateOne(state.runs, {
135
+ id,
136
+ changes: {
137
+ status: "succeeded",
138
+ outputSummary,
139
+ ...(steps === undefined ? {} : { steps }),
140
+ finishedAt: finishedAt ?? Date.now(),
141
+ },
142
+ });
143
+ },
144
+ toolRunUpdated: (
145
+ state,
146
+ action: PayloadAction<{
147
+ id: string;
148
+ outputSummary?: string;
149
+ steps?: ToolRunStep[];
150
+ }>
151
+ ) => {
152
+ const { id, outputSummary, steps } = action.payload;
153
+ toolRunAdapter.updateOne(state.runs, {
154
+ id,
155
+ changes: {
156
+ ...(outputSummary === undefined ? {} : { outputSummary }),
157
+ ...(steps === undefined ? {} : { steps }),
158
+ },
159
+ });
160
+ },
161
+ toolRunFailed: (
162
+ state,
163
+ action: PayloadAction<{
164
+ id: string;
165
+ error: string;
166
+ outputSummary?: string;
167
+ steps?: ToolRunStep[];
168
+ finishedAt?: number;
169
+ }>
170
+ ) => {
171
+ const { id, error, outputSummary, steps, finishedAt } = action.payload;
172
+ toolRunAdapter.updateOne(state.runs, {
173
+ id,
174
+ changes: {
175
+ status: "failed",
176
+ error,
177
+ ...(outputSummary === undefined ? {} : { outputSummary }),
178
+ ...(steps === undefined ? {} : { steps }),
179
+ finishedAt: finishedAt ?? Date.now(),
180
+ },
181
+ });
182
+ },
183
+ resetToolRunsForMessage: (
184
+ state,
185
+ action: PayloadAction<{ messageId: string }>
186
+ ) => {
187
+ const { messageId } = action.payload;
188
+ const all = state.runs.ids as string[];
189
+ const toRemove = all.filter((id) => {
190
+ const run = state.runs.entities[id];
191
+ return run?.messageId === messageId;
192
+ });
193
+ toolRunAdapter.removeMany(state.runs, toRemove);
194
+ },
195
+ resetAllToolRuns: (state) => {
196
+ toolRunAdapter.removeAll(state.runs);
197
+ },
198
+ },
199
+ });
200
+
201
+ export const {
202
+ toolRunStarted,
203
+ toolRunSetPending,
204
+ toolRunSucceeded,
205
+ toolRunUpdated,
206
+ toolRunFailed,
207
+ resetToolRunsForMessage,
208
+ resetAllToolRuns,
209
+ } = toolRunSlice.actions;
210
+
211
+ export default toolRunSlice.reducer;
212
+
213
+ // ===== selectors =====
214
+ const selectors = toolRunAdapter.getSelectors<RootState>(
215
+ (state) => state.toolRun.runs
216
+ );
217
+
218
+ export const selectAllToolRuns = selectors.selectAll;
219
+
220
+ export const selectToolRunsByMessageId = createSelector(
221
+ [selectors.selectAll, (_state: RootState, messageId: string) => messageId],
222
+ (runs, messageId) => runs.filter((run) => run.messageId === messageId)
223
+ );
224
+
225
+ // 按 id 精确获取(导出给组件用)
226
+ export const selectToolRunById = (
227
+ state: RootState,
228
+ id: string
229
+ ): ToolRun | undefined => selectors.selectById(state, id);
230
+
231
+ // ===== 通用执行 thunk:基于已有 ToolRun.input 再次执行工具(可作为重试) =====
232
+ export const executeToolRun = createAsyncThunk(
233
+ "toolRun/executeToolRun",
234
+ async ({ id }: { id: string }, thunkApi) => {
235
+ const state = thunkApi.getState() as RootState;
236
+ const run = selectToolRunById(state, id);
237
+
238
+ if (!run) {
239
+ throw new Error(`ToolRun not found: ${id}`);
240
+ }
241
+ if (!run.input) {
242
+ throw new Error(`ToolRun ${id} has no input to execute with.`);
243
+ }
244
+
245
+ const { findToolExecutor } = await import(".");
246
+ const { executor } = findToolExecutor(run.toolName);
247
+
248
+ // 点击按钮时,把状态重新置为 running,方便 UI 显示“执行中…”;这同时也清掉旧错误
249
+ thunkApi.dispatch(
250
+ toolRunStarted({
251
+ id: run.id,
252
+ messageId: run.messageId,
253
+ toolName: run.toolName,
254
+ behavior: run.behavior,
255
+ inputSummary: run.inputSummary,
256
+ startedAt: Date.now(),
257
+ interaction: run.interaction,
258
+ input: run.input,
259
+ })
260
+ );
261
+
262
+ try {
263
+ const result = await executor(run.input, thunkApi, {
264
+ parentMessageId: run.messageId,
265
+ });
266
+
267
+ thunkApi.dispatch(
268
+ toolRunSucceeded({
269
+ id: run.id,
270
+ outputSummary: result?.displayData || "",
271
+ })
272
+ );
273
+
274
+ if (run.toolName === "deleteSpaces") {
275
+ const latestState = thunkApi.getState() as RootState;
276
+ const userId = latestState.auth?.currentUser?.userId;
277
+ if (userId) {
278
+ const { fetchUserSpaceMemberships } = await import("create/space/spaceSlice");
279
+ await thunkApi.dispatch(fetchUserSpaceMemberships(userId) as any);
280
+ }
281
+ }
282
+
283
+ return {
284
+ id: run.id,
285
+ rawData: result?.rawData,
286
+ displayData: result?.displayData,
287
+ };
288
+ } catch (e: any) {
289
+ const msg = e?.message || String(e);
290
+ const structured = getToolResultErrorData(e);
291
+ thunkApi.dispatch(
292
+ toolRunFailed({
293
+ id: run.id,
294
+ error: msg,
295
+ outputSummary:
296
+ (typeof structured?.displayData === "string" && structured.displayData.trim()) ||
297
+ undefined,
298
+ })
299
+ );
300
+ throw e;
301
+ }
302
+ }
303
+ );
@@ -0,0 +1,53 @@
1
+ const COMPOSITION_KEYS = ["anyOf", "oneOf", "allOf"] as const;
2
+
3
+ const LIMITED_JSON_SCHEMA_PROVIDERS = new Set([
4
+ "fireworks",
5
+ ]);
6
+
7
+ const isPlainObject = (value: unknown): value is Record<string, any> =>
8
+ !!value && typeof value === "object" && !Array.isArray(value);
9
+
10
+ const sanitizeSchemaNode = (value: unknown): unknown => {
11
+ if (Array.isArray(value)) {
12
+ return value.map((item) => sanitizeSchemaNode(item));
13
+ }
14
+
15
+ if (!isPlainObject(value)) {
16
+ return value;
17
+ }
18
+
19
+ const next: Record<string, any> = {};
20
+ for (const [key, child] of Object.entries(value)) {
21
+ if (COMPOSITION_KEYS.includes(key as (typeof COMPOSITION_KEYS)[number])) {
22
+ continue;
23
+ }
24
+ next[key] = sanitizeSchemaNode(child);
25
+ }
26
+ return next;
27
+ };
28
+
29
+ const shouldSanitizeProviderSchema = (provider: string | undefined): boolean =>
30
+ typeof provider === "string" &&
31
+ LIMITED_JSON_SCHEMA_PROVIDERS.has(provider.trim().toLowerCase());
32
+
33
+ export const sanitizeToolForProvider = (
34
+ tool: any,
35
+ provider: string | undefined
36
+ ) => {
37
+ if (!shouldSanitizeProviderSchema(provider)) {
38
+ return tool;
39
+ }
40
+
41
+ const parameters = tool?.function?.parameters;
42
+ if (!isPlainObject(parameters)) {
43
+ return tool;
44
+ }
45
+
46
+ return {
47
+ ...tool,
48
+ function: {
49
+ ...tool.function,
50
+ parameters: sanitizeSchemaNode(parameters),
51
+ },
52
+ };
53
+ };
@@ -0,0 +1,4 @@
1
+ export const HIDDEN_TOOL_IDS = new Set(["readPage"]);
2
+
3
+ export const isToolVisibleInUi = (toolId: string): boolean =>
4
+ typeof toolId === "string" && toolId.trim().length > 0 && !HIDDEN_TOOL_IDS.has(toolId);
@@ -0,0 +1,20 @@
1
+ // ai/tools/types.ts
2
+
3
+ export interface ToolErrorPayload {
4
+ type: string; // Error / ValidationError / NetworkError ...
5
+ message: string;
6
+ code?: string;
7
+ retryable?: boolean;
8
+ }
9
+
10
+ export interface ToolPayload {
11
+ toolName: string; // 规范化后的名字 canonicalName
12
+ status: "pending" | "running" | "succeeded" | "failed";
13
+ input: any; // clean + JSON.parse 后的 arguments
14
+ rawToolCall?: any; // 模型原始 tool_call
15
+ rawResult?: any; // executor 返回的原始数据
16
+ error?: ToolErrorPayload; // 失败时的结构化错误
17
+ toolRunId?: string; // 可选:与 toolRunSlice 对应
18
+ startedAt?: number;
19
+ finishedAt?: number;
20
+ }
@@ -0,0 +1,104 @@
1
+ // 文件: ai/tools/uiAskChoiceTool.ts
2
+
3
+ export const uiAskChoiceFunctionSchema = {
4
+ name: "ui_ask_choice",
5
+ description: [
6
+ "当你需要让用户在几个互斥的选项之间做选择时,使用本工具。",
7
+ "",
8
+ "这是一个通用的“出选项”工具,适用于多种场景,例如:",
9
+ "1)用户的需求比较宽泛或模糊,你可以给出 2~5 个不同方向的候选方案,让 TA 先选一个方向;",
10
+ "2)一个计划 / 流程到了分支节点,需要用户决定下一步做什么;",
11
+ "3)你想为用户设计一组练习题、测试题或问卷题(如出题练习、人格测试等单选题);",
12
+ "4)在新阶段/新会话中,根据系统提示或用户画像,给出若干“接下来可以尝试的事情”(例如功能导航或使用技巧)。",
13
+ "",
14
+ "使用建议:",
15
+ "- 当你判断“先给出 2~5 个明确选项能显著帮用户理清下一步要做什么”时,可以主动调用本工具;",
16
+ "- 如果用户的目标已经非常具体、清晰,并且你可以直接给出高质量答案,优先直接回答,而不是再弹出选择菜单;",
17
+ "- 默认情况下,不要在完全没有有效上下文的场景(例如用户只说“你好”)立刻调用本工具,除非系统提示中已经明确要求你在新会话开头用它来生成欢迎菜单或功能导航;",
18
+ "- 请把给用户看的问题写在 question 字段中,不要在同一轮 assistant 普通文本里重复这句话;",
19
+ "- 每个选项的 userMessage 建议写成完整的一句话,方便后续理解上下文;如果留空,将自动使用 label 作为 userMessage。",
20
+ "",
21
+ "在代码协作场景下的推荐用法:",
22
+ "- 如果你已经在本轮 assistant 的 content 中给出了分析、说明或多个备选方案,可以在同一轮消息的结尾调用本工具,请用户选择“是否根据上述方案开始实际修改代码”或“优先执行哪一个方案/步骤”。",
23
+ "- 在这种情况下,question 字段通常是一个简短的问题(例如:“接下来你希望我按哪个方案来具体修改代码?”),而详细的解释和方案描述放在 content 中。",
24
+ "- 如果当前对话只需要一个简单的选择,而不需要额外解释,你也可以不输出额外的 content,而只调用本工具,由 question 字段直接向用户提问。"
25
+ ].join("\n"),
26
+ parameters: {
27
+ type: "object",
28
+ properties: {
29
+ question: {
30
+ type: "string",
31
+ description:
32
+ "展示给用户的问题文案,用一句话说明要做什么选择。例如:“接下来你更希望我帮你做哪件事?”。不要在同一轮 assistant 普通文本里重复这句话。"
33
+ },
34
+ choices: {
35
+ type: "array",
36
+ description:
37
+ "备选项列表。每个选项会渲染成一个按钮,供用户点击选择。",
38
+ items: {
39
+ type: "object",
40
+ properties: {
41
+ id: {
42
+ type: "string",
43
+ description:
44
+ "选项内部标识(用于后续逻辑或调试,不会直接展示给用户)。"
45
+ },
46
+ label: {
47
+ type: "string",
48
+ description:
49
+ "显示给用户看的按钮文字。例如:“生成本周周报”。"
50
+ },
51
+ userMessage: {
52
+ type: "string",
53
+ description: [
54
+ "用户点击此选项后,你希望作为下一条 user 消息发送给模型的自然语言内容。",
55
+ "建议写成完整的一句话,例如:“帮我生成一份本周的工作周报”。",
56
+ "如果留空,将使用 label 作为 userMessage。"
57
+ ].join(" ")
58
+ }
59
+ },
60
+ required: ["id", "label"]
61
+ }
62
+ },
63
+ blocking: {
64
+ type: "boolean",
65
+ description: [
66
+ "是否需要等待用户选择之后,再继续当前流程(例如 Plan)。",
67
+ "默认 true:即发出问题后,等待用户点击某个选项再继续。"
68
+ ].join(" "),
69
+ default: true
70
+ }
71
+ },
72
+ required: ["question", "choices"]
73
+ }
74
+ };
75
+ export async function uiAskChoiceFunc(
76
+ args: any,
77
+ _thunkApi: AppThunkApi
78
+ ): Promise<{
79
+ rawData: {
80
+ type: "ui_ask_choice";
81
+ question: string;
82
+ choices: any[];
83
+ blocking: boolean;
84
+ };
85
+ displayData: string;
86
+ }> {
87
+ const question = String(args?.question ?? "").trim();
88
+ const choices = Array.isArray(args?.choices) ? args.choices : [];
89
+ const blocking = args?.blocking !== false;
90
+
91
+ if (!question || choices.length === 0) {
92
+ throw new Error("ui_ask_choice 需要 question 和至少一个 choice。");
93
+ }
94
+
95
+ return {
96
+ rawData: {
97
+ type: "ui_ask_choice",
98
+ question,
99
+ choices,
100
+ blocking,
101
+ },
102
+ displayData: question,
103
+ };
104
+ }
@@ -0,0 +1,84 @@
1
+ import { updateContentTitle } from "create/space/spaceSlice"; // 假设有一个对应的 action
2
+ import { selectCurrentSpaceId } from "create/space/spaceSlice";
3
+
4
+ // Tool definition
5
+ export const updateContentTitleTool = {
6
+ type: "function",
7
+ function: {
8
+ name: "update_content_title",
9
+ description: "更新当前空间中某个内容的标题",
10
+ parameters: {
11
+ type: "object",
12
+ properties: {
13
+ contentId: {
14
+ type: "string",
15
+ description: "要更新的内容ID",
16
+ },
17
+ title: {
18
+ type: "string",
19
+ description: "新的页面标题",
20
+ },
21
+ },
22
+ required: ["contentId", "title"],
23
+ },
24
+ },
25
+ };
26
+
27
+ /**
28
+ * 更新当前空间中某个内容标题的实现
29
+ * @param args 工具参数 { contentId: string, title: string }
30
+ * @param thunkApi Redux Thunk API { dispatch, getState }
31
+ * @returns Promise<{ success: true, id: string, title: string } | never> - 成功时返回包含 id 和新标题的对象,失败时抛出错误
32
+ */
33
+ export const updateContentTitleFunc = async (
34
+ args: { contentId: string; title: string },
35
+ thunkApi: any /* Replace 'any' with your actual ThunkApi type */
36
+ ) => {
37
+ const { dispatch, getState } = thunkApi;
38
+ const state = getState(); // Assuming getState returns RootState
39
+ const spaceId = selectCurrentSpaceId(state); // 获取当前空间ID
40
+ const { contentId, title } = args;
41
+
42
+ console.log(
43
+ `[updateContentTitleFunc] spaceId: ${spaceId}, contentId: ${contentId}, title: ${title}`
44
+ );
45
+
46
+ if (!spaceId) {
47
+ console.error("[updateContentTitleFunc] 更新标题失败:未找到当前空间ID");
48
+ throw new Error("无法更新标题,因为当前空间未设定。");
49
+ }
50
+
51
+ if (!contentId) {
52
+ console.error("[updateContentTitleFunc] 更新标题失败:未提供内容ID");
53
+ throw new Error("无法更新标题,因为内容ID未提供。");
54
+ }
55
+
56
+ try {
57
+ // 调用 updateContentTitle action (直接从 spaceSlice 中导入)
58
+ console.log(
59
+ "[updateContentTitleFunc] Dispatching updateContentTitle action..."
60
+ );
61
+ const updatedContentId = await dispatch(
62
+ updateContentTitle({
63
+ spaceId,
64
+ contentId,
65
+ title: title.trim(), // 确保标题去除首尾空格
66
+ })
67
+ ).unwrap(); // unwrap 会在失败时抛出错误
68
+
69
+ console.log(
70
+ `[updateContentTitleFunc] Content title updated successfully. contentId: ${updatedContentId}`
71
+ );
72
+
73
+ // 返回结构化数据
74
+ return {
75
+ success: true, // 明确表示成功
76
+ id: updatedContentId, // 返回内容ID
77
+ title: title, // 返回使用的新标题
78
+ };
79
+ } catch (error: any) {
80
+ console.error("[updateContentTitleFunc] 更新标题失败:", error);
81
+ const errorMessage = error?.message || JSON.stringify(error) || "未知错误";
82
+ throw new Error(`更新标题时出错: ${errorMessage}`);
83
+ }
84
+ };
@@ -0,0 +1,105 @@
1
+ // ai/tools/updateDocTool.ts
2
+
3
+ import { readAction } from "database/actions/read";
4
+ import { write } from "database/dbSlice";
5
+ import { markdownToSlate } from "create/editor/transforms/markdownToSlate";
6
+ import { slateToRenderMarkdown } from "create/editor/transforms/slateToRenderMarkdown";
7
+ import { extractMentionsFromSlate } from "create/editor/utils/slateUtils";
8
+ import type { PageData } from "render/page/types";
9
+ import { parseSkillDocProtocol } from "ai/skills/skillDocProtocol";
10
+
11
+ export const updateDocFunctionSchema = {
12
+ name: "updateDoc",
13
+ description: "更新指定页面/文档的内容。支持全量覆盖或在末尾追加内容。",
14
+ parameters: {
15
+ type: "object",
16
+ properties: {
17
+ id: {
18
+ type: "string",
19
+ description: "页面/文档的 dbKey,通常以 page- 开头,例如 page-user-01ABC...",
20
+ },
21
+ content: {
22
+ type: "string",
23
+ description: "要更新或追加的 Markdown 格式内容。",
24
+ },
25
+ mode: {
26
+ type: "string",
27
+ enum: ["replace", "append"],
28
+ description: "更新模式:'replace' 表示全量覆盖(默认),'append' 表示在页面末尾追加。",
29
+ default: "replace",
30
+ },
31
+ },
32
+ required: ["id", "content"],
33
+ },
34
+ };
35
+
36
+ /**
37
+ * [Executor] 'updateDoc' 工具的执行函数。
38
+ */
39
+ export async function updateDocFunc(
40
+ args: { id: string; content: string; mode?: "replace" | "append" },
41
+ thunkApi: any
42
+ ): Promise<{ rawData: any; displayData: string }> {
43
+ const { id, content, mode = "replace" } = args;
44
+ const { dispatch } = thunkApi;
45
+
46
+ if (!id.toLowerCase().startsWith("page-")) {
47
+ throw new Error("updateDoc 工具仅支持更新页面 (page-xxx)。");
48
+ }
49
+ try {
50
+ // 1. 读取原页面数据
51
+ const originalData = (await readAction({ dbKey: id }, thunkApi)) as PageData;
52
+ if (!originalData) {
53
+ throw new Error(`未找到 ID 为 ${id} 的页面。`);
54
+ }
55
+
56
+ const currentMarkdown =
57
+ typeof originalData.content === "string" && originalData.content.trim()
58
+ ? originalData.content
59
+ : slateToRenderMarkdown(
60
+ Array.isArray(originalData.slateData) ? originalData.slateData : [],
61
+ );
62
+
63
+ const mergedMarkdown = mode === "append"
64
+ ? [currentMarkdown, content].filter(Boolean).join("\n\n")
65
+ : content;
66
+ const parsedProtocol = parseSkillDocProtocol(
67
+ mergedMarkdown,
68
+ originalData.meta,
69
+ originalData.tools,
70
+ );
71
+ const finalSlateData = markdownToSlate(parsedProtocol.content);
72
+ const tools = extractMentionsFromSlate(finalSlateData as any);
73
+
74
+ // 3. 构造更新后的数据
75
+ const updatedPageData: PageData = {
76
+ ...originalData,
77
+ slateData: finalSlateData,
78
+ content: parsedProtocol.content,
79
+ tools,
80
+ ...(parsedProtocol.meta ? { meta: parsedProtocol.meta } : {}),
81
+ updated_at: new Date().toISOString(),
82
+ };
83
+
84
+ // 4. 写入数据库
85
+ // 4. 写入数据库
86
+ await (dispatch as any)(write({ data: updatedPageData, customKey: id })).unwrap();
87
+
88
+ const displayData = mode === "append"
89
+ ? `已成功在页面《${originalData.title}》末尾追加了内容。`
90
+ : `页面《${originalData.title}》的内容已成功更新。`;
91
+
92
+ return {
93
+ rawData: { success: true, id, title: originalData.title },
94
+ displayData,
95
+ };
96
+ } catch (error: any) {
97
+ console.error("执行 updateDoc 工具时出错:", error);
98
+ throw new Error(`更新页面失败:${error?.message || String(error)}`);
99
+ }
100
+ }
101
+ // ── 向后兼容别名(旧名 updatePage / update_page)────────────────────────────
102
+ /** @deprecated 使用 updateDocFunctionSchema */
103
+ export const updatePageFunctionSchema = updateDocFunctionSchema;
104
+ /** @deprecated 使用 updateDocFunc */
105
+ export const updatePageFunc = updateDocFunc;