nolo-cli 0.1.41 → 0.1.43

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 (136) hide show
  1. package/README.md +27 -12
  2. package/agent-runtime/agentThread.ts +222 -0
  3. package/agent-runtime/agentThreadAdmission.ts +74 -0
  4. package/agent-runtime/dialogWritePlan.ts +42 -0
  5. package/agent-runtime/hostAdapter.ts +1 -0
  6. package/agent-runtime/index.ts +43 -0
  7. package/agent-runtime/localLoop.ts +31 -2
  8. package/agent-runtime/localToolPolicy.ts +1 -0
  9. package/agent-runtime/localWorkspaceTools.ts +1258 -78
  10. package/agent-runtime/noloWorkspaceTools.ts +20 -1
  11. package/agent-runtime/runtimeToolPolicy.ts +1 -5
  12. package/agent-runtime/runtimeToolSurface.ts +1 -0
  13. package/agentAliases.ts +29 -9
  14. package/agentInternalCommandEntries.ts +11 -3
  15. package/agentMachineCommands.ts +1 -0
  16. package/agentRecordCommands.ts +2 -2
  17. package/agentRecordHelpers.ts +59 -6
  18. package/agentRunCommand.ts +84 -19
  19. package/ai/agent/buildSystemPrompt.ts +14 -0
  20. package/ai/agent/cliExecutor.ts +202 -43
  21. package/ai/agent/createAgentSchema.ts +2 -2
  22. package/ai/agent/liveAudioModel.ts +1 -1
  23. package/ai/agent/streamAgentChatTurn.ts +154 -20
  24. package/ai/agent/streamAgentChatTurnUtils.ts +63 -0
  25. package/ai/ai.locale.ts +70 -0
  26. package/ai/chat/inlineImageUrlsForCustomProvider.ts +7 -2
  27. package/ai/chat/sendOpenAICompletionsRequest.ts +25 -1
  28. package/ai/llm/kimi.ts +0 -1
  29. package/ai/llm/openrouterModels.ts +27 -2
  30. package/ai/memory/policy.ts +49 -0
  31. package/ai/memory/queryShared.ts +10 -4
  32. package/ai/memory/recentRelationshipRecap.ts +4 -0
  33. package/ai/memory/remember.ts +48 -104
  34. package/ai/memory/scope.ts +74 -0
  35. package/ai/memory/types.ts +6 -0
  36. package/ai/memory/understanding.ts +10 -18
  37. package/ai/policy/runtimePolicy.ts +95 -23
  38. package/ai/tools/agent/agentTools.ts +0 -21
  39. package/ai/tools/agent/startAgentDialogTool.ts +2 -1
  40. package/ai/tools/index.ts +2 -20
  41. package/ai/tools/prepareTools.ts +171 -1
  42. package/ai/tools/readXhsProfileTool.ts +80 -69
  43. package/ai/tools/table/createTableTool.ts +11 -0
  44. package/ai/tools/toolPacks.ts +19 -0
  45. package/ai/types.ts +3 -0
  46. package/app/favorite/deletedFavoriteProjection.ts +31 -0
  47. package/app/hooks/deleteDbKey.ts +24 -3
  48. package/app/i18n/translations/interface.locale.ts +48 -16
  49. package/app/types/appSummary.ts +4 -0
  50. package/app/utils/desktopAgentRuntimeTurnClient.ts +2 -0
  51. package/auth/adminPermissions.ts +64 -4
  52. package/auth/routes.ts +5 -0
  53. package/chat/chat.locale.ts +4 -0
  54. package/chat/dialog/actions/handleSendMessageAction.ts +7 -2
  55. package/chat/dialog/dialogAttachmentCleanup.ts +135 -0
  56. package/chat/dialog/dialogSlice.ts +117 -4
  57. package/chat/messages/activityCompletion.ts +97 -0
  58. package/chat/messages/imagePayloadPersistence.ts +22 -0
  59. package/chat/messages/messageContent.ts +20 -16
  60. package/chat/messages/messageSlice.ts +20 -1
  61. package/chat/messages/toolThunks.ts +32 -11
  62. package/chat/messages/types.ts +8 -1
  63. package/chat/messages/web/toolDisplayName.ts +686 -0
  64. package/cli/agentAliases.ts +29 -9
  65. package/cli/agentInternalCommandEntries.ts +11 -3
  66. package/cli/agentMachineCommands.ts +1 -0
  67. package/cli/agentRecordCommands.ts +2 -2
  68. package/cli/agentRecordHelpers.ts +59 -6
  69. package/cli/agentRunCommand.ts +84 -19
  70. package/cli/client/agentRun.ts +65 -253
  71. package/cli/client/localRuntimeAdapter.ts +179 -53
  72. package/cli/commandRegistry.ts +7 -4
  73. package/cli/dialogAttachmentCleanup.ts +151 -0
  74. package/cli/dialogCommands.ts +163 -61
  75. package/cli/dialogInternalCommandEntries.ts +1 -1
  76. package/cli/docCreateCommands.ts +345 -0
  77. package/cli/docInternalCommandEntries.ts +11 -0
  78. package/cli/docPageHelpers.ts +80 -0
  79. package/cli/docSkillHelpers.ts +67 -0
  80. package/cli/docSpaceHelpers.ts +46 -0
  81. package/cli/internalCommandEntries.ts +4 -0
  82. package/cli/machineCommands.ts +18 -34
  83. package/cli/memoryCommands.ts +253 -0
  84. package/cli/memoryInternalCommandEntries.ts +9 -0
  85. package/cli/qoderUsageProbe.ts +252 -0
  86. package/cli/scriptCommandEntries.ts +0 -3
  87. package/cli/secretScan.ts +31 -0
  88. package/cli/tableCommands.ts +248 -13
  89. package/cli/workflowInternalCommandEntries.ts +2 -3
  90. package/client/agentRun.test.ts +68 -84
  91. package/client/agentRun.ts +65 -253
  92. package/client/localRuntimeAdapter.test.ts +505 -74
  93. package/client/localRuntimeAdapter.ts +179 -53
  94. package/commandRegistry.ts +7 -4
  95. package/connector-experimental/capabilities.ts +10 -9
  96. package/create/space/sidebarVisibleTypes.ts +19 -0
  97. package/dialogAttachmentCleanup.ts +151 -0
  98. package/dialogCommands.ts +163 -61
  99. package/dialogInternalCommandEntries.ts +1 -1
  100. package/docCreateCommands.ts +345 -0
  101. package/docInternalCommandEntries.ts +11 -0
  102. package/docPageHelpers.ts +80 -0
  103. package/docSkillHelpers.ts +67 -0
  104. package/docSpaceHelpers.ts +46 -0
  105. package/integrations/google/models.ts +4 -4
  106. package/integrations/openai/generateOpenAIRequestBody.ts +0 -3
  107. package/integrations/xhs-reader/types.ts +36 -3
  108. package/integrations/xhs-reader/url.ts +24 -1
  109. package/internalCommandEntries.ts +4 -0
  110. package/machineCommands.ts +18 -34
  111. package/memoryCommands.ts +253 -0
  112. package/memoryInternalCommandEntries.ts +9 -0
  113. package/package.json +141 -114
  114. package/qoderUsageProbe.ts +252 -0
  115. package/render/contentIcon/types.ts +167 -0
  116. package/render/page/docSlice.ts +30 -3
  117. package/render/page/types.ts +2 -0
  118. package/render/table/createTableAction.ts +4 -0
  119. package/render/table/tableSlice.ts +61 -0
  120. package/render/table/types.ts +10 -0
  121. package/scriptCommandEntries.ts +0 -3
  122. package/secretScan.ts +31 -0
  123. package/server/handlers/agentRun/types.ts +24 -23
  124. package/tableCommands.ts +248 -13
  125. package/workflowInternalCommandEntries.ts +2 -3
  126. package/ai/tools/agent/taskRunTool.ts +0 -112
  127. package/cli/client/taskRunPrompt.ts +0 -27
  128. package/cli/taskRunCommand.ts +0 -265
  129. package/client/taskRunPrompt.ts +0 -27
  130. package/integrations/xhs-reader/analyze/profileAnalyzer.ts +0 -205
  131. package/integrations/xhs-reader/backends/playwrightProfileCollector.ts +0 -624
  132. package/integrations/xhs-reader/bridge/readXhsProfileWithBridge.ts +0 -227
  133. package/integrations/xhs-reader/client/xhsWebApiClient.ts +0 -229
  134. package/integrations/xhs-reader/normalize.ts +0 -390
  135. package/integrations/xhs-reader/orchestrator.ts +0 -178
  136. package/taskRunCommand.ts +0 -265
@@ -0,0 +1,97 @@
1
+ import { serializeMessageContent } from "./messageContent";
2
+ import {
3
+ buildActivityTimeline,
4
+ type ToolActivityStatus,
5
+ } from "./web/toolDisplayName";
6
+
7
+ type ActivityMessage = Parameters<typeof buildActivityTimeline>[0][number];
8
+
9
+ type AssistantActivityCompletionInput = {
10
+ messages: ActivityMessage[];
11
+ finalContent: unknown;
12
+ };
13
+
14
+ type AssistantActivityCompletionMetadata = {
15
+ activity: {
16
+ phase: {
17
+ id: string;
18
+ title: string;
19
+ index?: number;
20
+ total?: number;
21
+ status: Extract<ToolActivityStatus, "success">;
22
+ };
23
+ };
24
+ };
25
+
26
+ const FINAL_DELIVERY_PHASE_PATTERNS = [
27
+ /汇报/,
28
+ /回复/,
29
+ /总结/,
30
+ /结果/,
31
+ /交付/,
32
+ /可视化/,
33
+ /图表/,
34
+ /report/i,
35
+ /deliver/i,
36
+ /result/i,
37
+ /summary/i,
38
+ /visual/i,
39
+ /chart/i,
40
+ ];
41
+
42
+ const FAILED_FINAL_CONTENT_PATTERNS = [
43
+ /抱歉/,
44
+ /无法/,
45
+ /不能/,
46
+ /失败/,
47
+ /出错/,
48
+ /未完成/,
49
+ /cannot/i,
50
+ /can't/i,
51
+ /failed/i,
52
+ /error/i,
53
+ /unable/i,
54
+ ];
55
+
56
+ function isLikelyFinalDeliveryPhase(title: string): boolean {
57
+ return FINAL_DELIVERY_PHASE_PATTERNS.some((pattern) => pattern.test(title));
58
+ }
59
+
60
+ function isLikelyFailedFinalContent(text: string): boolean {
61
+ return FAILED_FINAL_CONTENT_PATTERNS.some((pattern) => pattern.test(text));
62
+ }
63
+
64
+ export function inferAssistantActivityCompletionMetadata({
65
+ messages,
66
+ finalContent,
67
+ }: AssistantActivityCompletionInput): AssistantActivityCompletionMetadata | undefined {
68
+ const finalText = serializeMessageContent(finalContent, "[图片]")?.trim();
69
+ if (!finalText || isLikelyFailedFinalContent(finalText)) return undefined;
70
+
71
+ const timeline = buildActivityTimeline(messages);
72
+ if (timeline.totalPhases <= 1 || timeline.completedPhases >= timeline.totalPhases) {
73
+ return undefined;
74
+ }
75
+
76
+ const finalPhase = timeline.phases[timeline.phases.length - 1];
77
+ if (!finalPhase || finalPhase.status !== "pending") return undefined;
78
+
79
+ const priorPhases = timeline.phases.slice(0, -1);
80
+ if (priorPhases.length === 0 || priorPhases.some((phase) => phase.status !== "success")) {
81
+ return undefined;
82
+ }
83
+
84
+ if (!isLikelyFinalDeliveryPhase(finalPhase.title)) return undefined;
85
+
86
+ return {
87
+ activity: {
88
+ phase: {
89
+ id: finalPhase.id,
90
+ title: finalPhase.title,
91
+ ...(finalPhase.index !== undefined ? { index: finalPhase.index } : {}),
92
+ ...(finalPhase.total !== undefined ? { total: finalPhase.total } : {}),
93
+ status: "success",
94
+ },
95
+ },
96
+ };
97
+ }
@@ -0,0 +1,22 @@
1
+ type ImagePayloadPart = Record<string, any>;
2
+
3
+ export const stripDurableImageInlinePayload = <T extends ImagePayloadPart>(
4
+ part: T,
5
+ ): T => {
6
+ if (!part || typeof part !== "object") return part;
7
+
8
+ const { original_data_url: _originalDataUrl, ...withoutOriginalDataUrl } =
9
+ part;
10
+
11
+ if (
12
+ withoutOriginalDataUrl.type !== "image_url" ||
13
+ !withoutOriginalDataUrl.google_native ||
14
+ typeof withoutOriginalDataUrl.google_native !== "object"
15
+ ) {
16
+ return withoutOriginalDataUrl as T;
17
+ }
18
+
19
+ const { google_native: _googleNative, ...durablePart } =
20
+ withoutOriginalDataUrl;
21
+ return durablePart as T;
22
+ };
@@ -10,10 +10,12 @@
10
10
  import type { RootState } from "../../app/store";
11
11
  import { upload } from "../../database/dbSlice";
12
12
  import { getRuntimeServerContext } from "../../database/runtimeServerContext";
13
+ import { dataURLtoFile, waitForFileReady } from "../../app/utils/imageUtils";
13
14
  import { buildMessageFileContentUrl } from "./fileUrl";
14
15
 
15
16
  import { ContentType } from "../../app/types";
16
17
  import { addContentAction } from "../../create/space/content/addContentAction";
18
+ import { stripDurableImageInlinePayload } from "./imagePayloadPersistence";
17
19
 
18
20
  /** 判断 URL 是否为 data:image 开头的 dataURL */
19
21
  const isDataUrlImage = (url: unknown): url is string =>
@@ -21,7 +23,7 @@ const isDataUrlImage = (url: unknown): url is string =>
21
23
 
22
24
  /**
23
25
  * 将生成的 dataURL 图片上传为文件,并返回最终 URL。
24
- * 失败时返回原始 dataURL,避免打断主流程。
26
+ * 失败时返回 null,避免把大 base64 图片持久化进 message。
25
27
  */
26
28
  const uploadGeneratedImageDataUrl = async (
27
29
  url: string,
@@ -31,16 +33,15 @@ const uploadGeneratedImageDataUrl = async (
31
33
  dispatch: any,
32
34
  getState: () => RootState,
33
35
  options?: { spaceId?: string; agentName?: string }
34
- ): Promise<string> => {
36
+ ): Promise<string | null> => {
35
37
  const fileName = `generated-image-${dialogId}-${messageId}-${index}.png`;
36
- const { dataURLtoFile, waitForFileReady } = await import("../../app/utils/imageUtils");
37
38
  const file = dataURLtoFile(url, fileName);
38
39
 
39
40
  if (!file) {
40
41
  console.warn(
41
- "[messageContent] dataURLtoFile failed, keep dataURL for generated image"
42
+ "[messageContent] dataURLtoFile failed, drop generated image inline payload"
42
43
  );
43
- return url;
44
+ return null;
44
45
  }
45
46
 
46
47
  const customKey = `generated-image-${dialogId}-${messageId}-${index}`;
@@ -50,10 +51,10 @@ const uploadGeneratedImageDataUrl = async (
50
51
  metadata = await dispatch(upload({ file, customKey }) as any).unwrap();
51
52
  } catch (err) {
52
53
  console.warn(
53
- "[messageContent] upload generated image failed, keep dataURL:",
54
+ "[messageContent] upload generated image failed, drop inline payload:",
54
55
  err
55
56
  );
56
- return url;
57
+ return null;
57
58
  }
58
59
 
59
60
  const state = getState() as RootState;
@@ -62,10 +63,10 @@ const uploadGeneratedImageDataUrl = async (
62
63
 
63
64
  if (!currentServer || !fileId) {
64
65
  console.warn(
65
- "[messageContent] missing currentServer or fileId, keep dataURL",
66
+ "[messageContent] missing currentServer or fileId, drop inline payload",
66
67
  { currentServer, fileId }
67
68
  );
68
- return url;
69
+ return null;
69
70
  }
70
71
 
71
72
  // 如果提供了 spaceId,尝试保存到空间内容
@@ -89,16 +90,16 @@ const uploadGeneratedImageDataUrl = async (
89
90
 
90
91
  const imageUrl = buildMessageFileContentUrl(currentServer, fileId);
91
92
  if (!imageUrl) {
92
- return url;
93
+ return null;
93
94
  }
94
95
  const ready = await waitForFileReady(imageUrl);
95
96
 
96
97
  if (!ready) {
97
98
  console.warn(
98
- "[messageContent] uploaded generated image not ready, keep dataURL:",
99
+ "[messageContent] uploaded generated image not ready, drop inline payload:",
99
100
  imageUrl
100
101
  );
101
- return url;
102
+ return null;
102
103
  }
103
104
 
104
105
  return imageUrl;
@@ -144,17 +145,20 @@ export const normalizeAssistantContentBuffer = async (
144
145
  options
145
146
  );
146
147
 
147
- if (newUrl === part.image_url.url) {
148
- return part;
148
+ if (!newUrl) {
149
+ return {
150
+ type: "text",
151
+ text: "[图片保存失败,请重试生成图片]",
152
+ };
149
153
  }
150
154
 
151
- return {
155
+ return stripDurableImageInlinePayload({
152
156
  ...part,
153
157
  image_url: {
154
158
  ...part.image_url,
155
159
  url: newUrl,
156
160
  },
157
- };
161
+ });
158
162
  })
159
163
  );
160
164
 
@@ -35,6 +35,7 @@ import {
35
35
  appendSaveFailureToContent,
36
36
  finalizeAssistantMessageContent,
37
37
  } from "./messageContract";
38
+ import { inferAssistantActivityCompletionMetadata } from "./activityCompletion";
38
39
  import { estimateMissingUsage } from "../../ai/token/missingUsageEstimate";
39
40
  import {
40
41
  countImageGenerationOutputsInContent,
@@ -837,6 +838,23 @@ export const messageSlice = createSliceWithThunks({
837
838
  const agentName = rawName || undefined;
838
839
  const { imageGenerationState: _transientImageGenerationState, ...persistedMessageMetadata } =
839
840
  payload.messageMetadata ?? {};
841
+ const {
842
+ metadata: persistedMetadata,
843
+ ...otherPersistedMessageMetadata
844
+ } = persistedMessageMetadata;
845
+ const shouldInferActivityCompletion =
846
+ !(persistedMetadata as Record<string, unknown> | undefined)?.activity &&
847
+ (!toolCalls || toolCalls.length === 0);
848
+ const inferredActivityCompletionMetadata = shouldInferActivityCompletion
849
+ ? inferAssistantActivityCompletionMetadata({
850
+ messages: selectAllMsgs(getState() as RootState, dialogId),
851
+ finalContent: finalVisibleContent,
852
+ })
853
+ : undefined;
854
+ const finalMetadata =
855
+ inferredActivityCompletionMetadata
856
+ ? { ...(persistedMetadata ?? {}), ...inferredActivityCompletionMetadata }
857
+ : persistedMetadata;
840
858
 
841
859
  const finalMessage: Message = {
842
860
  id: messageId,
@@ -848,7 +866,8 @@ export const messageSlice = createSliceWithThunks({
848
866
  cybotKey: agentConfig.dbKey,
849
867
  usage: finalUsageData,
850
868
  isStreaming: false,
851
- ...persistedMessageMetadata,
869
+ ...otherPersistedMessageMetadata,
870
+ ...(finalMetadata ? { metadata: finalMetadata } : {}),
852
871
  ...(agentName ? { agentName } : {}),
853
872
  ...(toolCalls && toolCalls.length > 0
854
873
  ? { tool_calls: toolCalls }
@@ -107,7 +107,23 @@ const processToolData = createAsyncThunk(
107
107
  }
108
108
  }
109
109
 
110
- const inputSummary = JSON.stringify(toolArgs).slice(0, 400);
110
+ const activity =
111
+ toolArgs &&
112
+ typeof toolArgs === "object" &&
113
+ !Array.isArray(toolArgs) &&
114
+ toolArgs._activity &&
115
+ typeof toolArgs._activity === "object"
116
+ ? toolArgs._activity
117
+ : undefined;
118
+ const executionToolArgs =
119
+ toolArgs &&
120
+ typeof toolArgs === "object" &&
121
+ !Array.isArray(toolArgs) &&
122
+ Object.prototype.hasOwnProperty.call(toolArgs, "_activity")
123
+ ? (({ _activity: _ignored, ...rest }) => rest)(toolArgs)
124
+ : toolArgs;
125
+
126
+ const inputSummary = JSON.stringify(executionToolArgs).slice(0, 400);
111
127
 
112
128
  dispatch(
113
129
  toolRunStarted({
@@ -117,7 +133,7 @@ const processToolData = createAsyncThunk(
117
133
  behavior,
118
134
  inputSummary,
119
135
  interaction,
120
- input: toolArgs,
136
+ input: executionToolArgs,
121
137
  })
122
138
  );
123
139
 
@@ -128,7 +144,7 @@ const processToolData = createAsyncThunk(
128
144
 
129
145
  const previewExecutor = def?.previewExecutor;
130
146
  const previewResult = previewExecutor
131
- ? await previewExecutor(toolArgs, thunkApi, { parentMessageId })
147
+ ? await previewExecutor(executionToolArgs, thunkApi, { parentMessageId })
132
148
  : {
133
149
  rawData: {
134
150
  previewOnly: true,
@@ -149,10 +165,11 @@ const processToolData = createAsyncThunk(
149
165
  const toolPayload: ToolPayload = {
150
166
  toolName: canonicalName,
151
167
  status: "pending",
152
- input: toolArgs,
168
+ input: executionToolArgs,
153
169
  rawToolCall: toolCall,
154
170
  toolRunId,
155
171
  summary,
172
+ ...(activity ? { activity } : {}),
156
173
  };
157
174
 
158
175
  return {
@@ -191,11 +208,12 @@ const processToolData = createAsyncThunk(
191
208
  const toolPayload: ToolPayload = {
192
209
  toolName: canonicalName,
193
210
  status: "failed",
194
- input: toolArgs,
211
+ input: executionToolArgs,
195
212
  rawToolCall: toolCall,
196
213
  error: errorPayload,
197
214
  toolRunId,
198
215
  summary,
216
+ ...(activity ? { activity } : {}),
199
217
  };
200
218
 
201
219
  return rejectWithValue({
@@ -212,7 +230,7 @@ const processToolData = createAsyncThunk(
212
230
 
213
231
  // ========= 分支二:auto 工具(包括 ui_ask_choice / readFile / createPlan 等) =========
214
232
  try {
215
- const toolResult = await found.executor(toolArgs, thunkApi, {
233
+ const toolResult = await found.executor(executionToolArgs, thunkApi, {
216
234
  parentMessageId,
217
235
  toolRunId,
218
236
  });
@@ -239,18 +257,19 @@ const processToolData = createAsyncThunk(
239
257
  const toolPayload: ToolPayload = {
240
258
  toolName: canonicalName,
241
259
  status: "succeeded",
242
- input: toolArgs,
260
+ input: executionToolArgs,
243
261
  rawToolCall: toolCall,
244
262
  toolRunId,
245
263
  summary,
246
264
  ...(llmContext ? { llmContext } : {}),
265
+ ...(activity ? { activity } : {}),
247
266
  };
248
267
 
249
268
  // ✅ 关键:ui_ask_choice(blocking=true) 也视作“暂停点”
250
269
  const isUiAskChoice = canonicalName === "ui_ask_choice";
251
270
  const blocking =
252
- typeof toolArgs?.blocking === "boolean"
253
- ? toolArgs.blocking
271
+ typeof executionToolArgs?.blocking === "boolean"
272
+ ? executionToolArgs.blocking
254
273
  : true; // schema 默认 true
255
274
 
256
275
  const hasPendingInteraction =
@@ -274,7 +293,7 @@ const processToolData = createAsyncThunk(
274
293
 
275
294
  if (requiresConfirmation) {
276
295
  const confirmedInput = {
277
- ...(toolArgs ?? {}),
296
+ ...(executionToolArgs ?? {}),
278
297
  __confirmedSelfEvolution: true,
279
298
  };
280
299
  const summary =
@@ -302,6 +321,7 @@ const processToolData = createAsyncThunk(
302
321
  rawToolCall: toolCall,
303
322
  toolRunId,
304
323
  summary,
324
+ ...(activity ? { activity } : {}),
305
325
  };
306
326
 
307
327
  return {
@@ -342,11 +362,12 @@ const processToolData = createAsyncThunk(
342
362
  const toolPayload: ToolPayload = {
343
363
  toolName: canonicalName,
344
364
  status: "failed",
345
- input: toolArgs,
365
+ input: executionToolArgs,
346
366
  rawToolCall: toolCall,
347
367
  error: errorPayload,
348
368
  toolRunId,
349
369
  summary,
370
+ ...(activity ? { activity } : {}),
350
371
  };
351
372
 
352
373
  return rejectWithValue({
@@ -16,7 +16,7 @@ export interface OpenAIImageContent {
16
16
  detail?: "low" | "high" | "auto";
17
17
  };
18
18
  google_native?: {
19
- inlineData: {
19
+ inlineData?: {
20
20
  mimeType: string;
21
21
  data: string;
22
22
  };
@@ -112,6 +112,12 @@ export interface ToolPayload {
112
112
  */
113
113
  summary?: string;
114
114
 
115
+ /**
116
+ * Human-readable tool activity hint for UI projection.
117
+ * Execution output remains in message.content; this is display metadata only.
118
+ */
119
+ activity?: unknown;
120
+
115
121
  /**
116
122
  * 提供给下一轮 LLM 的结构化上下文补充。
117
123
  * 典型场景:工具真实产物(如 fileId / 可复用 URL)不能只靠 summary 传达。
@@ -153,6 +159,7 @@ export interface Message {
153
159
  imageGenerationState?: ImageGenerationState;
154
160
  userId?: string;
155
161
  usage?: any;
162
+ metadata?: Record<string, unknown>;
156
163
 
157
164
  controller?: AbortController;
158
165