nolo-cli 0.1.10 → 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 -22
  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 -1079
  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,999 +0,0 @@
1
- // 文件路径: ai/tools/createPlanTool.ts
2
- // 完整的 createPlan 工具,支持普通步骤和反思步骤(reflect step)
3
-
4
- import { createAsyncThunk } from "@reduxjs/toolkit";
5
- import {
6
- setPlan,
7
- setSteps,
8
- updateStep,
9
- setCurrentStep,
10
- selectSteps,
11
- insertStepsAfter,
12
- removeStepsAfter,
13
- setExecutionConfig,
14
- incrementReflectCount,
15
- incrementStepsExecuted,
16
- setStartTime,
17
- selectPlanStats,
18
- selectExecutionConfig,
19
- type Step,
20
- type ToolCall,
21
- type ReflectDecision,
22
- type PlanExecutionConfig,
23
- } from "ai/agent/planSlice";
24
- // ✅ 不再直接在 Plan 里使用 runLlm / runAgent,统一走 toolExecutors
25
- // import { runLlm, runAgent } from "ai/agent/agentSlice";
26
- import { toolExecutors, toolDefinitionsByName } from "ai/tools";
27
- import {
28
- toolRunStarted,
29
- toolRunSucceeded,
30
- toolRunFailed,
31
- createToolRunId,
32
- } from "ai/tools/toolRunSlice";
33
- import type { RootState } from "app/store";
34
- import { selectCurrentDialogConfig } from "chat/dialog/dialogSlice";
35
- import { messageStreamEnd, messageStreaming } from "chat/messages/messageSlice";
36
- import { extractCustomId } from "core/prefix";
37
- import { createDialogMessageKeyAndId } from "database/keys";
38
- import { callAgentFunc } from "./agent/callAgentTool";
39
- const PLAN_EXECUTOR_CYBOT_KEY = "PLAN_EXECUTOR";
40
- const PLAN_EXECUTOR_AGENT_CONFIG = { dbKey: PLAN_EXECUTOR_CYBOT_KEY } as any;
41
-
42
- // --- Schema ---
43
-
44
- export const createPlanFunctionSchema = {
45
- name: "createPlan",
46
- description:
47
- "用于处理需要多个工具协作、有顺序依赖或可并行执行的复杂任务。当你发现一个请求无法通过单次工具调用完成时,应优先使用本工具来制定并执行一个清晰、可靠的多步骤计划。" +
48
- "在 Plan 中,你可以调用任意已注册的工具(例如 youtubeScraper, addTableRow, callAgent, runStreamingAgent 等)," +
49
- "并通过 steps.STEP_ID.result 在步骤之间传递数据。",
50
- parameters: {
51
- type: "object",
52
- properties: {
53
- planTitle: {
54
- type: "string",
55
- description: "为整个计划的目标设定一个简明扼要的标题。",
56
- },
57
- strategy: {
58
- type: "string",
59
- description:
60
- "[至关重要] 详细阐述制定此计划的整体策略和思考过程。解释为什么选择这些步骤、它们如何协同工作、以及数据如何在步骤间传递,以最终达成目标。",
61
- },
62
- steps: {
63
- type: "array",
64
- description:
65
- "一个有序的步骤数组。每个步骤可以是普通工具调用步骤(type: normal)或反思决策步骤(type: reflect)。",
66
- items: {
67
- type: "object",
68
- properties: {
69
- id: {
70
- type: "string",
71
- description:
72
- "步骤的唯一标识符 (例如 'fetch_data', 'step_2', 'reflect_1')。此ID用于在后续步骤中引用本步骤的执行结果。",
73
- },
74
- title: {
75
- type: "string",
76
- description: "对该步骤目标的简短、人类可读的描述。",
77
- },
78
- type: {
79
- type: "string",
80
- enum: ["normal", "reflect"],
81
- description:
82
- "步骤类型。'normal' 是普通工具调用步骤,'reflect' 是反思决策步骤,用于根据前面步骤的结果动态调整计划。默认为 'normal'。",
83
- },
84
- calls: {
85
- type: "array",
86
- description:
87
- "(仅 type='normal' 时使用)一个或多个工具调用的数组,它们将在本步骤内并行执行。",
88
- items: {
89
- type: "object",
90
- properties: {
91
- tool_name: {
92
- type: "string",
93
- description:
94
- "要调用的工具名称(必须是系统中已注册的工具之一,例如 'youtubeScraper', 'addTableRow', 'callAgent', 'runStreamingAgent' 等)。",
95
- },
96
- parameters: {
97
- type: "object",
98
- description:
99
- "调用工具所需的参数对象。要引用先前步骤的结果,请使用占位符 '{{steps.STEP_ID.result}}' 或 '{{steps.STEP_ID.result[INDEX]}}' (当结果是数组时)。",
100
- },
101
- },
102
- required: ["tool_name", "parameters"],
103
- },
104
- },
105
- reflectInput: {
106
- type: "string",
107
- description:
108
- "(仅 type='reflect' 时使用)给反思 LLM 的提示,说明需要检查什么、基于什么条件做决策。反思 LLM 会看到所有已完成步骤的结果摘要,并决定是继续、停止还是插入新步骤。",
109
- },
110
- },
111
- required: ["id", "title"],
112
- },
113
- },
114
- executionConfig: {
115
- type: "object",
116
- description: "(可选)计划执行的边界控制配置。",
117
- properties: {
118
- maxReflectCount: {
119
- type: "integer",
120
- description: "最多允许执行多少次反思步骤。",
121
- },
122
- maxTotalSteps: {
123
- type: "integer",
124
- description: "最多执行多少个步骤(包括动态插入的)。",
125
- },
126
- maxTimeMs: {
127
- type: "integer",
128
- description: "最大执行时间(毫秒)。",
129
- },
130
- },
131
- },
132
- },
133
- required: ["planTitle", "strategy", "steps"],
134
- },
135
- };
136
-
137
- // --- 辅助函数 ---
138
-
139
- /**
140
- * 解析步骤参数中的占位符,替换为实际的步骤结果
141
- */
142
- const resolveParameters = (params: any, allSteps: Step[]): any => {
143
- if (typeof params !== "string") {
144
- if (Array.isArray(params)) {
145
- return params.map((p) => resolveParameters(p, allSteps));
146
- }
147
- if (typeof params === "object" && params !== null) {
148
- return Object.fromEntries(
149
- Object.entries(params).map(([key, value]) => [
150
- key,
151
- resolveParameters(value, allSteps),
152
- ])
153
- );
154
- }
155
- return params;
156
- }
157
-
158
- return params.replace(
159
- /\{\{steps\.([^}]+)\.result(\[\d+\])?\}\}/g,
160
- (match, stepId, indexPart) => {
161
- const referencedStep = allSteps.find((s) => s.id === stepId);
162
- if (
163
- !referencedStep ||
164
- referencedStep.status !== "completed" ||
165
- !referencedStep.result
166
- ) {
167
- console.warn(
168
- `无法解析引用:步骤 "${stepId}" 未完成或没有结果。将返回原始占位符。`
169
- );
170
- return match;
171
- }
172
-
173
- let result = referencedStep.result;
174
- if (indexPart) {
175
- const index = parseInt(indexPart.slice(1, -1), 10);
176
- if (Array.isArray(result) && index < result.length) {
177
- result = result[index];
178
- } else {
179
- console.warn(
180
- `无法解析引用:步骤 "${stepId}" 的结果中没有索引 ${index}。将返回原始占位符。`
181
- );
182
- return match;
183
- }
184
- }
185
-
186
- if (typeof result === "object") {
187
- return JSON.stringify(result);
188
- }
189
- return String(result);
190
- }
191
- );
192
- };
193
-
194
- /**
195
- * 格式化参数用于展示
196
- */
197
- function formatParameters(params: Record<string, any>): string {
198
- if (!params || Object.keys(params).length === 0) return "无";
199
- return Object.entries(params)
200
- .map(([key, value]) => ` - \`${key}\`: \`${JSON.stringify(value)}\``)
201
- .join("\n");
202
- }
203
-
204
- /**
205
- * 对步骤结果生成摘要,用于反思 LLM
206
- */
207
- function summarizeStepResult(result: any[] | undefined): any {
208
- if (!result || result.length === 0) {
209
- return { empty: true };
210
- }
211
-
212
- return result.map((item) => {
213
- if (item === null || item === undefined) {
214
- return { type: "null" };
215
- }
216
-
217
- if (Array.isArray(item)) {
218
- return {
219
- type: "array",
220
- length: item.length,
221
- sample: item.slice(0, 2),
222
- fields:
223
- item[0] && typeof item[0] === "object" ? Object.keys(item[0]) : [],
224
- };
225
- }
226
-
227
- if (typeof item === "object") {
228
- // 检查是否是错误对象
229
- if (item.error) {
230
- return {
231
- type: "error",
232
- message: item.message || item.error,
233
- };
234
- }
235
-
236
- const keys = Object.keys(item);
237
- const preview = JSON.stringify(item);
238
- return {
239
- type: "object",
240
- keys,
241
- preview: preview.length > 300 ? preview.slice(0, 300) + "..." : preview,
242
- };
243
- }
244
-
245
- if (typeof item === "string") {
246
- return {
247
- type: "string",
248
- length: item.length,
249
- preview: item.length > 200 ? item.slice(0, 200) + "..." : item,
250
- };
251
- }
252
-
253
- return {
254
- type: typeof item,
255
- value: item,
256
- };
257
- });
258
- }
259
-
260
- /**
261
- * 构建反思 LLM 的上下文输入
262
- */
263
- function buildReflectContext(
264
- currentStep: Step,
265
- allSteps: Step[],
266
- originalRequest?: string
267
- ): string {
268
- const completedSteps = allSteps
269
- .filter((s) => s.status === "completed" && s.id !== currentStep.id)
270
- .map((s) => ({
271
- id: s.id,
272
- title: s.title,
273
- type: s.type || "normal",
274
- resultSummary: summarizeStepResult(s.result),
275
- }));
276
-
277
- const pendingSteps = allSteps
278
- .filter((s) => s.status === "pending" && s.id !== currentStep.id)
279
- .map((s) => ({
280
- id: s.id,
281
- title: s.title,
282
- type: s.type || "normal",
283
- }));
284
-
285
- const failedSteps = allSteps
286
- .filter((s) => s.status === "failed")
287
- .map((s) => ({
288
- id: s.id,
289
- title: s.title,
290
- result: s.result,
291
- }));
292
-
293
- return `
294
- ## 当前 Plan 执行状态
295
-
296
- ### 已完成的步骤 (${completedSteps.length})
297
- ${completedSteps.length > 0 ? JSON.stringify(completedSteps, null, 2) : "(暂无)"}
298
-
299
- ### 失败的步骤 (${failedSteps.length})
300
- ${failedSteps.length > 0 ? JSON.stringify(failedSteps, null, 2) : "(暂无)"}
301
-
302
- ### 待执行的步骤 (${pendingSteps.length})
303
- ${pendingSteps.length > 0 ? JSON.stringify(pendingSteps, null, 2) : "(暂无)"}
304
-
305
- ### 反思任务
306
- ${currentStep.reflectInput || "请检查当前执行状态,决定下一步行动。"}
307
-
308
- ---
309
-
310
- 请根据以上信息,决定下一步行动。你必须返回一个 JSON 对象,格式如下:
311
-
312
- \`\`\`json
313
- {
314
- "action": "continue" | "stop" | "insert_steps",
315
- "reason": "你的决策原因",
316
- "steps": [] // 仅当 action 是 "insert_steps" 时需要填写新步骤
317
- }
318
- \`\`\`
319
-
320
- **action 说明:**
321
- - "continue":继续执行剩余的待执行步骤
322
- - "stop":停止执行,当前结果已足够或无法继续
323
- - "insert_steps":需要插入新的步骤来完成任务
324
-
325
- **如果 action 是 "insert_steps",steps 数组中的每个步骤格式:**
326
- \`\`\`json
327
- {
328
- "id": "新步骤的唯一ID",
329
- "title": "步骤描述",
330
- "type": "normal",
331
- "calls": [
332
- {
333
- "tool_name": "工具名称",
334
- "parameters": { ... }
335
- }
336
- ]
337
- }
338
- \`\`\`
339
-
340
- 请只返回 JSON,不要有其他内容。
341
- `.trim();
342
- }
343
-
344
- /**
345
- * 解析反思 LLM 的输出
346
- */
347
- function parseReflectDecision(llmOutput: string): ReflectDecision {
348
- // 尝试从输出中提取 JSON
349
- let jsonStr = llmOutput;
350
-
351
- // 如果输出包含 markdown 代码块,提取其中的 JSON
352
- const jsonMatch = llmOutput.match(/```(?:json)?\s*([\s\S]*?)```/);
353
- if (jsonMatch) {
354
- jsonStr = jsonMatch[1].trim();
355
- }
356
-
357
- try {
358
- const parsed = JSON.parse(jsonStr);
359
-
360
- // 验证必需字段
361
- if (
362
- !parsed.action ||
363
- !["continue", "stop", "insert_steps"].includes(parsed.action)
364
- ) {
365
- console.warn("反思 LLM 输出的 action 无效,默认继续执行");
366
- return {
367
- action: "continue",
368
- reason: "反思输出格式无效,默认继续",
369
- };
370
- }
371
-
372
- // 如果是 insert_steps,验证 steps 数组
373
- if (parsed.action === "insert_steps") {
374
- if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) {
375
- console.warn(
376
- "反思 LLM 输出 insert_steps 但没有提供 steps,改为继续执行"
377
- );
378
- return {
379
- action: "continue",
380
- reason: parsed.reason || "未提供新步骤,继续执行原计划",
381
- };
382
- }
383
-
384
- // 确保每个新步骤都有必需字段
385
- const validatedSteps = parsed.steps.map((s: any, index: number) => ({
386
- id: s.id || `inserted_step_${Date.now()}_${index}`,
387
- title: s.title || `插入的步骤 ${index + 1}`,
388
- type: s.type || "normal",
389
- calls: s.calls || [],
390
- status: "pending" as const,
391
- result: [],
392
- }));
393
-
394
- return {
395
- action: "insert_steps",
396
- reason: parsed.reason || "需要插入新步骤",
397
- steps: validatedSteps,
398
- };
399
- }
400
-
401
- return {
402
- action: parsed.action,
403
- reason: parsed.reason || "",
404
- };
405
- } catch (e) {
406
- console.error("解析反思 LLM 输出失败:", e, "原始输出:", llmOutput);
407
- return {
408
- action: "continue",
409
- reason: "解析反思输出失败,默认继续执行",
410
- };
411
- }
412
- }
413
-
414
- /**
415
- * 检查是否超出执行边界
416
- */
417
- function checkExecutionBoundary(
418
- config: PlanExecutionConfig | null,
419
- stats: {
420
- reflectCount: number;
421
- totalStepsExecuted: number;
422
- startTime: number | null;
423
- },
424
- isReflectStep: boolean
425
- ): { exceeded: boolean; reason?: string } {
426
- if (!config) {
427
- return { exceeded: false };
428
- }
429
-
430
- if (config.maxTimeMs && stats.startTime) {
431
- const elapsed = Date.now() - stats.startTime;
432
- if (elapsed > config.maxTimeMs) {
433
- return {
434
- exceeded: true,
435
- reason: `执行时间超过限制 (${config.maxTimeMs}ms)`,
436
- };
437
- }
438
- }
439
-
440
- if (
441
- config.maxTotalSteps &&
442
- stats.totalStepsExecuted >= config.maxTotalSteps
443
- ) {
444
- return {
445
- exceeded: true,
446
- reason: `执行步骤数超过限制 (${config.maxTotalSteps})`,
447
- };
448
- }
449
-
450
- if (
451
- isReflectStep &&
452
- config.maxReflectCount &&
453
- stats.reflectCount >= config.maxReflectCount
454
- ) {
455
- return {
456
- exceeded: true,
457
- reason: `反思次数超过限制 (${config.maxReflectCount})`,
458
- };
459
- }
460
-
461
- return { exceeded: false };
462
- }
463
-
464
- // --- 异步 Thunk: 计划执行器 ---
465
-
466
- interface RunPlanArgs {
467
- dialogKey: string;
468
- planCybotId?: string; // 用于反思的 cybot ID,如果不传则使用当前对话的主 cybot
469
- }
470
-
471
- export const runPlanSteps = createAsyncThunk(
472
- "plan/runPlanSteps",
473
- async ({ dialogKey, planCybotId }: RunPlanArgs, thunkApi) => {
474
- const { getState, dispatch, signal } = thunkApi;
475
-
476
- // 设置开始时间
477
- dispatch(setStartTime(Date.now()));
478
-
479
- const dialogId = extractCustomId(dialogKey);
480
-
481
- // 获取反思用的 cybot ID
482
- const state = getState() as RootState;
483
- const currentDialog = selectCurrentDialogConfig(state);
484
- const reflectCybotId = planCybotId || currentDialog?.cybots?.[0];
485
-
486
- // 使用 while 循环而不是 for,因为 steps 可能会动态变化
487
- while (true) {
488
- if (signal.aborted) {
489
- throw new DOMException("Aborted", "AbortError");
490
- }
491
-
492
- // 每次循环都重新获取最新的 steps
493
- const currentState = getState() as RootState;
494
- const allSteps = selectSteps(currentState);
495
- const config = selectExecutionConfig(currentState);
496
- const stats = selectPlanStats(currentState);
497
-
498
- // 找到下一个待执行的步骤
499
- const nextStep = allSteps.find((s) => s.status === "pending");
500
- if (!nextStep) {
501
- console.log("[runPlanSteps] 所有步骤已完成");
502
- break;
503
- }
504
-
505
- const isReflectStep = nextStep.type === "reflect";
506
-
507
- // 检查执行边界
508
- const boundaryCheck = checkExecutionBoundary(
509
- config,
510
- stats,
511
- isReflectStep
512
- );
513
- if (boundaryCheck.exceeded) {
514
- console.log(`[runPlanSteps] 超出执行边界: ${boundaryCheck.reason}`);
515
-
516
- // 创建一条消息通知用户
517
- const { key: msgKey, messageId: boundaryMessageId } =
518
- createDialogMessageKeyAndId(dialogId);
519
-
520
- dispatch(
521
- messageStreaming({
522
- id: boundaryMessageId,
523
- dialogId,
524
- dbKey: msgKey,
525
- role: "assistant",
526
- content: `⚠️ **计划执行已停止**\n\n原因: ${boundaryCheck.reason}`,
527
- cybotKey: PLAN_EXECUTOR_CYBOT_KEY,
528
- isStreaming: true,
529
- })
530
- );
531
-
532
- await dispatch(
533
- messageStreamEnd({
534
- finalContentBuffer: [
535
- {
536
- type: "text",
537
- text: `⚠️ **计划执行已停止**\n\n原因: ${boundaryCheck.reason}`,
538
- },
539
- ],
540
- msgKey,
541
- dialogId,
542
- dialogKey,
543
- messageId: boundaryMessageId,
544
- totalUsage: null,
545
- agentConfig: PLAN_EXECUTOR_AGENT_CONFIG,
546
- reasoningBuffer: "",
547
- })
548
- );
549
-
550
- break;
551
- }
552
-
553
- // 更新当前步骤状态
554
- dispatch(setCurrentStep(nextStep.id));
555
- dispatch(
556
- updateStep({ id: nextStep.id, updates: { status: "in-progress" } })
557
- );
558
- dispatch(incrementStepsExecuted());
559
-
560
- // 创建步骤执行消息
561
- const { key: msgKey, messageId: stepMessageId } =
562
- createDialogMessageKeyAndId(dialogId);
563
-
564
- if (isReflectStep) {
565
- // ===== 反思步骤 =====
566
- dispatch(incrementReflectCount());
567
-
568
- dispatch(
569
- messageStreaming({
570
- id: stepMessageId,
571
- dialogId,
572
- dbKey: msgKey,
573
- role: "assistant",
574
- content: `🤔 **正在反思: ${nextStep.title}**`,
575
- cybotKey: PLAN_EXECUTOR_CYBOT_KEY,
576
- isStreaming: true,
577
- })
578
- );
579
-
580
- try {
581
- // 构建反思上下文
582
- const reflectContext = buildReflectContext(nextStep, allSteps);
583
-
584
- if (!reflectCybotId) {
585
- throw new Error("无法确定反思 LLM 的 cybot ID");
586
- }
587
-
588
- // 这里仍然可以用 runLlm/ runAgent 封装,暂不改动
589
- // 为了不引入新的依赖,这里可以简单使用全上下文 Agent,
590
- // 也可以在后续将其改造成独立的反思 Agent。
591
- const reflectState = getState() as RootState;
592
- const reflectDialog = selectCurrentDialogConfig(reflectState);
593
- const reflectAgentId = reflectCybotId || reflectDialog?.cybots?.[0];
594
- if (!reflectAgentId) {
595
- throw new Error("反思步骤: 找不到可用的 Agent。");
596
- }
597
-
598
- // 这里简单调用当前 Agent,一次性 LLM(无历史)
599
- // 你也可以改为调用单独的 runLlm / runAgent 封装
600
- const llmResult = await callAgentFunc(
601
- {
602
- agentKey: reflectAgentId,
603
- task: reflectContext,
604
- mode: "subtask",
605
- },
606
- thunkApi,
607
- { parentMessageId: stepMessageId }
608
- ).then((res) => res.rawData ?? "");
609
-
610
-
611
- const decision = parseReflectDecision(llmResult as string);
612
- console.log("[runPlanSteps] 反思决策:", decision);
613
-
614
- if (decision.action === "stop") {
615
- dispatch(
616
- updateStep({
617
- id: nextStep.id,
618
- updates: { status: "completed", result: [decision] },
619
- })
620
- );
621
-
622
- await dispatch(
623
- messageStreamEnd({
624
- finalContentBuffer: [
625
- {
626
- type: "text",
627
- text: `🛑 **反思决定: 停止执行**\n\n原因: ${decision.reason}`,
628
- },
629
- ],
630
- msgKey,
631
- dialogId,
632
- dialogKey,
633
- messageId: stepMessageId,
634
- totalUsage: null,
635
- agentConfig: PLAN_EXECUTOR_AGENT_CONFIG,
636
- reasoningBuffer: "",
637
- })
638
- );
639
-
640
- // 移除后续待执行步骤
641
- dispatch(removeStepsAfter(nextStep.id));
642
- break;
643
- }
644
-
645
- if (
646
- decision.action === "insert_steps" &&
647
- decision.steps &&
648
- decision.steps.length > 0
649
- ) {
650
- const newSteps: Step[] = decision.steps.map((s) => ({
651
- ...s,
652
- status: "pending" as const,
653
- result: [],
654
- }));
655
-
656
- dispatch(insertStepsAfter({ afterStepId: nextStep.id, newSteps }));
657
-
658
- dispatch(
659
- updateStep({
660
- id: nextStep.id,
661
- updates: { status: "completed", result: [decision] },
662
- })
663
- );
664
-
665
- const newStepsSummary = newSteps
666
- .map((s, i) => `${i + 1}. ${s.title}`)
667
- .join("\n");
668
-
669
- await dispatch(
670
- messageStreamEnd({
671
- finalContentBuffer: [
672
- {
673
- type: "text",
674
- text: `🔄 **反思决定: 插入新步骤**\n\n原因: ${decision.reason}\n\n新增步骤:\n${newStepsSummary}`,
675
- },
676
- ],
677
- msgKey,
678
- dialogId,
679
- dialogKey,
680
- messageId: stepMessageId,
681
- totalUsage: null,
682
- agentConfig: PLAN_EXECUTOR_AGENT_CONFIG,
683
- reasoningBuffer: "",
684
- })
685
- );
686
- } else {
687
- dispatch(
688
- updateStep({
689
- id: nextStep.id,
690
- updates: { status: "completed", result: [decision] },
691
- })
692
- );
693
-
694
- await dispatch(
695
- messageStreamEnd({
696
- finalContentBuffer: [
697
- {
698
- type: "text",
699
- text: `✅ **反思完成: 继续执行**\n\n${decision.reason}`,
700
- },
701
- ],
702
- msgKey,
703
- dialogId,
704
- dialogKey,
705
- messageId: stepMessageId,
706
- totalUsage: null,
707
- agentConfig: PLAN_EXECUTOR_AGENT_CONFIG,
708
- reasoningBuffer: "",
709
- })
710
- );
711
- }
712
- } catch (e: any) {
713
- console.error(`反思步骤 ${nextStep.id} 执行失败:`, e);
714
-
715
- dispatch(
716
- updateStep({
717
- id: nextStep.id,
718
- updates: { status: "failed", result: [{ error: e.message }] },
719
- })
720
- );
721
-
722
- await dispatch(
723
- messageStreamEnd({
724
- finalContentBuffer: [
725
- {
726
- type: "text",
727
- text: `❌ **反思失败: ${nextStep.title}**\n\n错误: ${e.message}\n\n将继续执行剩余步骤...`,
728
- },
729
- ],
730
- msgKey,
731
- dialogId,
732
- dialogKey,
733
- messageId: stepMessageId,
734
- totalUsage: null,
735
- agentConfig: PLAN_EXECUTOR_AGENT_CONFIG,
736
- reasoningBuffer: "",
737
- })
738
- );
739
-
740
- // 反思失败不中断整个计划,继续执行
741
- }
742
- } else {
743
- // ===== 普通步骤 =====
744
- const calls = nextStep.calls || [];
745
-
746
- dispatch(
747
- messageStreaming({
748
- id: stepMessageId,
749
- dialogId,
750
- dbKey: msgKey,
751
- role: "assistant",
752
- content: `🔄 **正在执行: ${nextStep.title}** (${calls.length}个任务${calls.length > 1 ? "并行" : ""})`,
753
- cybotKey: PLAN_EXECUTOR_CYBOT_KEY,
754
- isStreaming: true,
755
- })
756
- );
757
-
758
- try {
759
- // 并行执行当前步骤的所有调用
760
- const latestSteps = selectSteps(getState() as RootState);
761
-
762
- const callPromises = calls.map(async (call: ToolCall) => {
763
- const resolvedParameters = resolveParameters(
764
- call.parameters,
765
- latestSteps
766
- );
767
-
768
- const toolRunId = createToolRunId();
769
- const def = toolDefinitionsByName[call.tool_name];
770
- const behavior = def?.behavior;
771
- const inputSummary = JSON.stringify(resolvedParameters).slice(
772
- 0,
773
- 400
774
- );
775
-
776
- // 启动 ToolRun 记录
777
- (dispatch as any)(
778
- toolRunStarted({
779
- id: toolRunId,
780
- messageId: stepMessageId,
781
- toolName: call.tool_name,
782
- behavior,
783
- inputSummary,
784
- })
785
- );
786
-
787
- try {
788
- const executor = toolExecutors[call.tool_name];
789
- if (!executor) {
790
- throw new Error(`未知工具: ${call.tool_name}`);
791
- }
792
-
793
- const toolResult = await executor(
794
- resolvedParameters,
795
- thunkApi,
796
- {
797
- parentMessageId: stepMessageId,
798
- }
799
- );
800
-
801
- const rawData = toolResult?.rawData ?? toolResult;
802
- const displayData =
803
- toolResult?.displayData ||
804
- `**${call.tool_name}**: 执行成功`;
805
-
806
- (dispatch as any)(
807
- toolRunSucceeded({
808
- id: toolRunId,
809
- outputSummary: displayData,
810
- })
811
- );
812
-
813
- return { rawData, displayData };
814
- } catch (e: any) {
815
- (dispatch as any)(
816
- toolRunFailed({
817
- id: toolRunId,
818
- error: e?.message || String(e),
819
- })
820
- );
821
- throw e;
822
- }
823
- });
824
-
825
- const toolResults = await Promise.all(callPromises);
826
-
827
- // 更新步骤状态为 completed 并保存结果
828
- dispatch(
829
- updateStep({
830
- id: nextStep.id,
831
- updates: {
832
- status: "completed",
833
- result: toolResults.map((res) => res.rawData),
834
- },
835
- })
836
- );
837
-
838
- // 构建完成消息
839
- const finalContent = `✅ **${nextStep.title} 完成**\n\n${toolResults
840
- .map((r) => r.displayData || "执行成功")
841
- .join("\n")}`;
842
-
843
- await dispatch(
844
- messageStreamEnd({
845
- finalContentBuffer: [{ type: "text", text: finalContent }],
846
- msgKey,
847
- dialogId,
848
- dialogKey,
849
- messageId: stepMessageId,
850
- totalUsage: null,
851
- agentConfig: PLAN_EXECUTOR_AGENT_CONFIG,
852
- reasoningBuffer: "",
853
- })
854
- );
855
- } catch (e: any) {
856
- console.error(`步骤 ${nextStep.id} 执行失败:`, e);
857
-
858
- dispatch(
859
- updateStep({
860
- id: nextStep.id,
861
- updates: { status: "failed", result: [{ error: e.message }] },
862
- })
863
- );
864
-
865
- await dispatch(
866
- messageStreamEnd({
867
- finalContentBuffer: [
868
- {
869
- type: "text",
870
- text: `❌ **${nextStep.title} 失败**\n\n错误: ${e.message}`,
871
- },
872
- ],
873
- msgKey,
874
- dialogId,
875
- dialogKey,
876
- messageId: stepMessageId,
877
- totalUsage: null,
878
- agentConfig: PLAN_EXECUTOR_AGENT_CONFIG,
879
- reasoningBuffer: "",
880
- })
881
- );
882
-
883
- // 普通步骤失败,中断整个计划
884
- break;
885
- }
886
- }
887
- }
888
-
889
- // 所有步骤执行完毕,重置当前步骤
890
- dispatch(setCurrentStep(null));
891
- }
892
- );
893
-
894
- // --- 工具主函数 ---
895
-
896
- export async function createPlanAndOrchestrateFunc(
897
- args: any,
898
- thunkApi: any
899
- ): Promise<{ rawData: string; displayData: string }> {
900
- const { dispatch, getState } = thunkApi;
901
- const { planTitle, strategy, steps: stepBlueprints, executionConfig } = args;
902
-
903
- if (
904
- !planTitle ||
905
- !strategy ||
906
- !Array.isArray(stepBlueprints) ||
907
- stepBlueprints.length === 0
908
- ) {
909
- throw new Error(
910
- "创建计划需要 'planTitle', 'strategy', 以及至少一个 'steps'。"
911
- );
912
- }
913
-
914
- // 处理步骤,设置默认值
915
- const processedSteps: Step[] = stepBlueprints.map((blueprint: any) => ({
916
- id: blueprint.id,
917
- title: blueprint.title,
918
- type: blueprint.type || "normal",
919
- status: "pending" as const,
920
- calls: blueprint.calls || [],
921
- reflectInput: blueprint.reflectInput,
922
- result: [],
923
- }));
924
-
925
- // TODO: 可以在这里检查当前是否已有 Plan 在执行,必要时只返回 Plan 描述而不自动执行
926
-
927
- // 设置计划
928
- dispatch(setPlan({ planDetails: strategy, currentProgress: 0 }));
929
- dispatch(setSteps(processedSteps));
930
-
931
- // 设置执行配置(如果有)
932
- if (executionConfig) {
933
- dispatch(setExecutionConfig(executionConfig));
934
- }
935
-
936
- // 获取 dialogKey 并启动执行
937
- const state = getState() as RootState;
938
- const dialogKey = (state as any).dialog.currentDialogKey;
939
-
940
- if (dialogKey) {
941
- dispatch(runPlanSteps({ dialogKey }));
942
- } else {
943
- console.error("无法执行计划: 未能获取到 currentDialogKey。");
944
- const errorMarkdown = `\n\n**严重错误:** 找不到当前对话。计划已创建但**不会被执行**。`;
945
- return { rawData: errorMarkdown, displayData: errorMarkdown };
946
- }
947
-
948
- // 构建展示用的 Markdown
949
- const normalSteps = processedSteps.filter((s) => s.type !== "reflect");
950
- const reflectSteps = processedSteps.filter((s) => s.type === "reflect");
951
-
952
- const markdownResult = `
953
- ### 计划已创建: ${planTitle}
954
-
955
- **策略:**
956
- ${strategy}
957
-
958
- ---
959
-
960
- **执行步骤 (${processedSteps.length} 步,其中 ${reflectSteps.length} 个反思点):**
961
-
962
- ${processedSteps
963
- .map((step, index) => {
964
- if (step.type === "reflect") {
965
- return `
966
- **${index + 1}. 🤔 ${step.title}** (\`ID: ${step.id}\`, 类型: 反思)
967
- - **反思任务:** ${step.reflectInput || "检查执行状态并决定下一步"}`;
968
- }
969
-
970
- return `
971
- **${index + 1}. ${step.title}** (\`ID: ${step.id}\`)
972
- ${(step.calls || [])
973
- .map(
974
- (call) => `
975
- - **工具:** \`${call.tool_name}\`
976
- - **参数:**
977
- ${formatParameters(call.parameters)}`
978
- )
979
- .join("")}`;
980
- })
981
- .join("\n---\n")}
982
-
983
- ${executionConfig
984
- ? `
985
- ---
986
- **执行限制:**
987
- ${executionConfig.maxReflectCount ? `- 最大反思次数: ${executionConfig.maxReflectCount}` : ""}
988
- ${executionConfig.maxTotalSteps ? `- 最大步骤数: ${executionConfig.maxTotalSteps}` : ""}
989
- ${executionConfig.maxTimeMs ? `- 最大执行时间: ${executionConfig.maxTimeMs}ms` : ""}
990
- `
991
- : ""
992
- }
993
-
994
- ---
995
- **计划已开始自动执行...**
996
- `;
997
-
998
- return { rawData: markdownResult, displayData: markdownResult };
999
- }