@agentscope-ai/agentscope 0.0.2

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/dist/agent/index.d.mts +234 -0
  2. package/dist/agent/index.d.ts +234 -0
  3. package/dist/agent/index.js +1412 -0
  4. package/dist/agent/index.js.map +1 -0
  5. package/dist/agent/index.mjs +1375 -0
  6. package/dist/agent/index.mjs.map +1 -0
  7. package/dist/base-BOx3UzOl.d.mts +41 -0
  8. package/dist/base-BoIps2RL.d.ts +41 -0
  9. package/dist/base-C7jwyH4Z.d.mts +52 -0
  10. package/dist/base-Cwi4bjze.d.ts +127 -0
  11. package/dist/base-DYlBMCy_.d.mts +127 -0
  12. package/dist/base-NX-knWOv.d.ts +52 -0
  13. package/dist/block-VsnHrllL.d.mts +48 -0
  14. package/dist/block-VsnHrllL.d.ts +48 -0
  15. package/dist/event/index.d.mts +181 -0
  16. package/dist/event/index.d.ts +181 -0
  17. package/dist/event/index.js +58 -0
  18. package/dist/event/index.js.map +1 -0
  19. package/dist/event/index.mjs +33 -0
  20. package/dist/event/index.mjs.map +1 -0
  21. package/dist/formatter/index.d.mts +187 -0
  22. package/dist/formatter/index.d.ts +187 -0
  23. package/dist/formatter/index.js +647 -0
  24. package/dist/formatter/index.js.map +1 -0
  25. package/dist/formatter/index.mjs +616 -0
  26. package/dist/formatter/index.mjs.map +1 -0
  27. package/dist/index-BTJDlKvQ.d.mts +195 -0
  28. package/dist/index-BcatlwXQ.d.ts +195 -0
  29. package/dist/index-CAxQAkiP.d.mts +21 -0
  30. package/dist/index-CAxQAkiP.d.ts +21 -0
  31. package/dist/mcp/index.d.mts +9 -0
  32. package/dist/mcp/index.d.ts +9 -0
  33. package/dist/mcp/index.js +432 -0
  34. package/dist/mcp/index.js.map +1 -0
  35. package/dist/mcp/index.mjs +408 -0
  36. package/dist/mcp/index.mjs.map +1 -0
  37. package/dist/message/index.d.mts +10 -0
  38. package/dist/message/index.d.ts +10 -0
  39. package/dist/message/index.js +67 -0
  40. package/dist/message/index.js.map +1 -0
  41. package/dist/message/index.mjs +37 -0
  42. package/dist/message/index.mjs.map +1 -0
  43. package/dist/message-CkN21KaY.d.mts +99 -0
  44. package/dist/message-CzLeTlua.d.ts +99 -0
  45. package/dist/model/index.d.mts +377 -0
  46. package/dist/model/index.d.ts +377 -0
  47. package/dist/model/index.js +1880 -0
  48. package/dist/model/index.js.map +1 -0
  49. package/dist/model/index.mjs +1849 -0
  50. package/dist/model/index.mjs.map +1 -0
  51. package/dist/storage/index.d.mts +68 -0
  52. package/dist/storage/index.d.ts +68 -0
  53. package/dist/storage/index.js +250 -0
  54. package/dist/storage/index.js.map +1 -0
  55. package/dist/storage/index.mjs +212 -0
  56. package/dist/storage/index.mjs.map +1 -0
  57. package/dist/tool/index.d.mts +311 -0
  58. package/dist/tool/index.d.ts +311 -0
  59. package/dist/tool/index.js +1494 -0
  60. package/dist/tool/index.js.map +1 -0
  61. package/dist/tool/index.mjs +1447 -0
  62. package/dist/tool/index.mjs.map +1 -0
  63. package/dist/toolkit-CEpulFi0.d.ts +99 -0
  64. package/dist/toolkit-CGEZSZPa.d.mts +99 -0
  65. package/jest.config.js +11 -0
  66. package/package.json +92 -0
  67. package/src/_utils/common.ts +104 -0
  68. package/src/_utils/index.ts +1 -0
  69. package/src/agent/agent-base.ts +0 -0
  70. package/src/agent/agent.test.ts +1028 -0
  71. package/src/agent/agent.ts +1032 -0
  72. package/src/agent/index.ts +2 -0
  73. package/src/agent/interfaces.ts +23 -0
  74. package/src/agent/test-compression.ts +72 -0
  75. package/src/event/index.ts +250 -0
  76. package/src/formatter/base.ts +133 -0
  77. package/src/formatter/dashscope-chat-formatter.test.ts +372 -0
  78. package/src/formatter/dashscope-chat-formatter.ts +163 -0
  79. package/src/formatter/deepseek-chat-formatter.ts +130 -0
  80. package/src/formatter/index.ts +5 -0
  81. package/src/formatter/ollama-chat-formatter.ts +67 -0
  82. package/src/formatter/openai-chat-formatter.test.ts +263 -0
  83. package/src/formatter/openai-chat-formatter.ts +301 -0
  84. package/src/formatter/openai.md +767 -0
  85. package/src/mcp/base.ts +114 -0
  86. package/src/mcp/http.test.ts +303 -0
  87. package/src/mcp/http.ts +224 -0
  88. package/src/mcp/index.ts +2 -0
  89. package/src/mcp/stdio.test.ts +91 -0
  90. package/src/mcp/stdio.ts +119 -0
  91. package/src/message/block.ts +60 -0
  92. package/src/message/enums.ts +4 -0
  93. package/src/message/index.ts +12 -0
  94. package/src/message/message.test.ts +80 -0
  95. package/src/message/message.ts +131 -0
  96. package/src/model/base.ts +226 -0
  97. package/src/model/dashscope-model.test.ts +335 -0
  98. package/src/model/dashscope-model.ts +441 -0
  99. package/src/model/deepseek-model.test.ts +279 -0
  100. package/src/model/deepseek-model.ts +401 -0
  101. package/src/model/index.ts +7 -0
  102. package/src/model/ollama-model.test.ts +307 -0
  103. package/src/model/ollama-model.ts +356 -0
  104. package/src/model/openai-model.ts +327 -0
  105. package/src/model/response.ts +22 -0
  106. package/src/model/usage.ts +12 -0
  107. package/src/storage/base.ts +52 -0
  108. package/src/storage/file-system.test.ts +587 -0
  109. package/src/storage/file-system.ts +269 -0
  110. package/src/storage/index.ts +2 -0
  111. package/src/tool/base.ts +23 -0
  112. package/src/tool/bash.test.ts +174 -0
  113. package/src/tool/bash.ts +152 -0
  114. package/src/tool/edit.test.ts +83 -0
  115. package/src/tool/edit.ts +95 -0
  116. package/src/tool/glob.test.ts +63 -0
  117. package/src/tool/glob.ts +166 -0
  118. package/src/tool/grep.test.ts +74 -0
  119. package/src/tool/grep.ts +256 -0
  120. package/src/tool/index.ts +10 -0
  121. package/src/tool/read.test.ts +77 -0
  122. package/src/tool/read.ts +117 -0
  123. package/src/tool/response.ts +82 -0
  124. package/src/tool/task.test.ts +299 -0
  125. package/src/tool/task.ts +399 -0
  126. package/src/tool/toolkit.test.ts +636 -0
  127. package/src/tool/toolkit.ts +601 -0
  128. package/src/tool/write.test.ts +52 -0
  129. package/src/tool/write.ts +57 -0
  130. package/src/type/index.ts +52 -0
  131. package/tsconfig.build.json +4 -0
  132. package/tsconfig.cjs.json +11 -0
  133. package/tsconfig.esm.json +10 -0
  134. package/tsconfig.json +14 -0
  135. package/tsup.config.ts +20 -0
  136. package/typedoc.json +52 -0
@@ -0,0 +1,2 @@
1
+ export { Agent, AgentOptions, CompressionConfig } from './agent';
2
+ export { ReplyOptions, ActingOptions, ReasoningOptions } from './interfaces';
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+
3
+ import { ExternalExecutionResultEvent, UserConfirmResultEvent } from '../event';
4
+ import { Msg, ToolCallBlock } from '../message';
5
+ import { ToolChoice } from '../type';
6
+
7
+ export interface ReplyOptions {
8
+ msgs?: Msg | Msg[];
9
+ event?: UserConfirmResultEvent | ExternalExecutionResultEvent;
10
+ structuredModel?: z.ZodObject;
11
+ }
12
+
13
+ export interface ReasoningOptions {
14
+ toolChoice?: ToolChoice;
15
+ }
16
+
17
+ export interface ActingOptions {
18
+ toolCall: ToolCallBlock;
19
+ }
20
+
21
+ export interface ObserveOptions {
22
+ msg?: Msg | Msg[];
23
+ }
@@ -0,0 +1,72 @@
1
+ import * as readline from 'readline';
2
+
3
+ import { Agent } from './agent';
4
+ import { createMsg } from '../message';
5
+ import { DashScopeChatModel } from '../model';
6
+ import { Bash, Glob, Grep, Toolkit } from '../tool';
7
+
8
+ // Enable debug logging
9
+ process.env.DEBUG = '*';
10
+ console.debug('Debug logging enabled');
11
+
12
+ const agent = new Agent({
13
+ name: 'Friday',
14
+ sysPrompt: 'You are a helpful assistant named Friday.',
15
+ model: new DashScopeChatModel({
16
+ modelName: 'qwen3-max',
17
+ apiKey: process.env.DASHSCOPE_API_KEY || '',
18
+ }),
19
+ toolkit: new Toolkit({
20
+ tools: [Bash(), Glob(), Grep()],
21
+ }),
22
+ compressionConfig: {
23
+ enabled: true,
24
+ triggerThreshold: 2100,
25
+ },
26
+ });
27
+
28
+ const rl = readline.createInterface({
29
+ input: process.stdin,
30
+ output: process.stdout,
31
+ });
32
+
33
+ const getUserInput = (): Promise<string> => {
34
+ return new Promise(resolve => {
35
+ rl.question('User: ', answer => {
36
+ resolve(answer);
37
+ });
38
+ });
39
+ };
40
+
41
+ /**
42
+ *
43
+ */
44
+ async function main() {
45
+ console.log('Compression test started. Type "exit" to quit.\n');
46
+
47
+ while (true) {
48
+ const userInput = await getUserInput();
49
+ if (userInput.toLowerCase() === 'exit') {
50
+ rl.close();
51
+ break;
52
+ } else if (userInput.toLowerCase() === '/context') {
53
+ console.log(JSON.stringify(agent.context, null, 2));
54
+ continue;
55
+ }
56
+
57
+ const res = agent.replyStream({
58
+ msgs: createMsg({
59
+ name: 'user',
60
+ content: [{ id: crypto.randomUUID(), type: 'text', text: userInput }],
61
+ role: 'user',
62
+ }),
63
+ });
64
+
65
+ for await (const event of res) {
66
+ console.log(event);
67
+ }
68
+ console.log('\n');
69
+ }
70
+ }
71
+
72
+ main().catch(console.error);
@@ -0,0 +1,250 @@
1
+ import { ToolCallBlock, ToolResultBlock } from '../message';
2
+
3
+ export enum EventType {
4
+ RUN_STARTED = 'RUN_STARTED',
5
+ RUN_FINISHED = 'RUN_FINISHED',
6
+
7
+ MODEL_CALL_STARTED = 'MODEL_CALL_STARTED',
8
+ MODEL_CALL_ENDED = 'MODEL_CALL_ENDED',
9
+
10
+ TEXT_BLOCK_START = 'TEXT_BLOCK_START',
11
+ TEXT_BLOCK_DELTA = 'TEXT_BLOCK_DELTA',
12
+ TEXT_BLOCK_END = 'TEXT_BLOCK_END',
13
+
14
+ BINARY_BLOCK_START = 'BINARY_BLOCK_START',
15
+ BINARY_BLOCK_DELTA = 'BINARY_BLOCK_DELTA',
16
+ BINARY_BLOCK_END = 'BINARY_BLOCK_END',
17
+
18
+ THINKING_BLOCK_START = 'THINKING_BLOCK_START',
19
+ THINKING_BLOCK_DELTA = 'THINKING_BLOCK_DELTA',
20
+ THINKING_BLOCK_END = 'THINKING_BLOCK_END',
21
+
22
+ TOOL_CALL_START = 'TOOL_CALL_START',
23
+ TOOL_CALL_DELTA = 'TOOL_CALL_DELTA',
24
+ TOOL_CALL_END = 'TOOL_CALL_END',
25
+
26
+ TOOL_RESULT_START = 'TOOL_RESULT_START',
27
+ TOOL_RESULT_TEXT_DELTA = 'TOOL_RESULT_TEXT_DELTA',
28
+ TOOL_RESULT_BINARY_DELTA = 'TOOL_RESULT_BINARY_DELTA',
29
+ TOOL_RESULT_END = 'TOOL_RESULT_END',
30
+
31
+ EXCEED_MAX_ITERS = 'EXCEED_MAX_ITERS',
32
+
33
+ REQUIRE_USER_CONFIRM = 'REQUIRE_USER_CONFIRM',
34
+ REQUIRE_EXTERNAL_EXECUTION = 'REQUIRE_EXTERNAL_EXECUTION',
35
+
36
+ USER_CONFIRM_RESULT = 'USER_CONFIRM_RESULT',
37
+ EXTERNAL_EXECUTION_RESULT = 'EXTERNAL_EXECUTION_RESULT',
38
+ }
39
+
40
+ export interface EventBase {
41
+ id: string;
42
+ createdAt: string;
43
+ }
44
+
45
+ export interface RunStartedEvent extends EventBase {
46
+ type: EventType.RUN_STARTED;
47
+ sessionId: string;
48
+ replyId: string;
49
+
50
+ // Extra fields for AG-UI protocol
51
+ name: string;
52
+ role: 'user' | 'assistant' | 'system';
53
+ }
54
+
55
+ export interface RunFinishedEvent extends EventBase {
56
+ type: EventType.RUN_FINISHED;
57
+ sessionId: string;
58
+ replyId: string;
59
+ }
60
+
61
+ export interface ModelCallStartedEvent extends EventBase {
62
+ type: EventType.MODEL_CALL_STARTED;
63
+ replyId: string;
64
+ modelName: string;
65
+ }
66
+
67
+ export interface ModelCallEndedEvent extends EventBase {
68
+ type: EventType.MODEL_CALL_ENDED;
69
+ replyId: string;
70
+ inputTokens: number;
71
+ outputTokens: number;
72
+ }
73
+
74
+ export interface TextBlockStartEvent extends EventBase {
75
+ type: EventType.TEXT_BLOCK_START;
76
+ blockId: string;
77
+ replyId: string;
78
+ }
79
+
80
+ export interface TextBlockDeltaEvent extends EventBase {
81
+ type: EventType.TEXT_BLOCK_DELTA;
82
+ replyId: string;
83
+ blockId: string;
84
+ delta: string;
85
+ }
86
+
87
+ export interface TextBlockEndEvent extends EventBase {
88
+ type: EventType.TEXT_BLOCK_END;
89
+ replyId: string;
90
+ blockId: string;
91
+ }
92
+
93
+ export interface BinaryBlockStartEvent extends EventBase {
94
+ type: EventType.BINARY_BLOCK_START;
95
+ replyId: string;
96
+ blockId: string;
97
+ mediaType: string;
98
+ }
99
+
100
+ export interface BinaryBlockDeltaEvent extends EventBase {
101
+ type: EventType.BINARY_BLOCK_DELTA;
102
+ replyId: string;
103
+ blockId: string;
104
+ data: string;
105
+ mediaType: string;
106
+ }
107
+
108
+ export interface BinaryBlockEndEvent extends EventBase {
109
+ type: EventType.BINARY_BLOCK_END;
110
+ replyId: string;
111
+ blockId: string;
112
+ }
113
+
114
+ export interface ThinkingBlockStartEvent extends EventBase {
115
+ type: EventType.THINKING_BLOCK_START;
116
+ replyId: string;
117
+ blockId: string;
118
+ }
119
+
120
+ export interface ThinkingBlockDeltaEvent extends EventBase {
121
+ type: EventType.THINKING_BLOCK_DELTA;
122
+ replyId: string;
123
+ blockId: string;
124
+ delta: string;
125
+ }
126
+
127
+ export interface ThinkingBlockEndEvent extends EventBase {
128
+ type: EventType.THINKING_BLOCK_END;
129
+ replyId: string;
130
+ blockId: string;
131
+ }
132
+
133
+ export interface ToolCallStartEvent extends EventBase {
134
+ type: EventType.TOOL_CALL_START;
135
+ replyId: string;
136
+ toolCallId: string;
137
+ toolCallName: string;
138
+ }
139
+
140
+ export interface ToolCallDeltaEvent extends EventBase {
141
+ type: EventType.TOOL_CALL_DELTA;
142
+ replyId: string;
143
+ toolCallId: string;
144
+ delta: string;
145
+ }
146
+
147
+ export interface ToolCallEndEvent extends EventBase {
148
+ type: EventType.TOOL_CALL_END;
149
+ replyId: string;
150
+ toolCallId: string;
151
+ }
152
+
153
+ export interface ToolResultStartEvent extends EventBase {
154
+ type: EventType.TOOL_RESULT_START;
155
+ replyId: string;
156
+ toolCallId: string;
157
+ toolCallName: string;
158
+ }
159
+
160
+ export interface ToolResultTextDeltaEvent extends EventBase {
161
+ type: EventType.TOOL_RESULT_TEXT_DELTA;
162
+ replyId: string;
163
+ toolCallId: string;
164
+ delta: string;
165
+ }
166
+
167
+ export interface ToolResultBinaryDeltaEvent extends EventBase {
168
+ type: EventType.TOOL_RESULT_BINARY_DELTA;
169
+ replyId: string;
170
+ toolCallId: string;
171
+ mediaType: string;
172
+ data?: string;
173
+ url?: string;
174
+ }
175
+
176
+ export interface ToolResultEndEvent extends EventBase {
177
+ type: EventType.TOOL_RESULT_END;
178
+ replyId: string;
179
+ toolCallId: string;
180
+ state: ToolResultBlock['state'];
181
+ }
182
+
183
+ export interface ExceedMaxItersEvent extends EventBase {
184
+ type: EventType.EXCEED_MAX_ITERS;
185
+
186
+ replyId: string;
187
+ agentId: string;
188
+ name: string;
189
+ }
190
+
191
+ export interface RequireUserConfirmEvent extends EventBase {
192
+ type: EventType.REQUIRE_USER_CONFIRM;
193
+
194
+ replyId: string;
195
+ toolCalls: ToolCallBlock[];
196
+ }
197
+
198
+ export interface RequireExternalExecutionEvent extends EventBase {
199
+ type: EventType.REQUIRE_EXTERNAL_EXECUTION;
200
+
201
+ replyId: string;
202
+ toolCalls: ToolCallBlock[];
203
+ }
204
+
205
+ export interface UserConfirmResultEvent extends EventBase {
206
+ type: EventType.USER_CONFIRM_RESULT;
207
+
208
+ replyId: string;
209
+ confirmResults: {
210
+ confirmed: boolean;
211
+ toolCall: ToolCallBlock;
212
+ }[];
213
+ }
214
+
215
+ export interface ExternalExecutionResultEvent extends EventBase {
216
+ type: EventType.EXTERNAL_EXECUTION_RESULT;
217
+
218
+ replyId: string;
219
+ executionResults: ToolResultBlock[];
220
+ }
221
+
222
+ export type AgentEvent =
223
+ // The control events for the whole run
224
+ | RunStartedEvent
225
+ | RunFinishedEvent
226
+ | ExceedMaxItersEvent
227
+ | RequireUserConfirmEvent
228
+ | RequireExternalExecutionEvent
229
+ | ModelCallStartedEvent
230
+ | ModelCallEndedEvent
231
+ // The data events for different block types
232
+ | TextBlockStartEvent
233
+ | TextBlockDeltaEvent
234
+ | TextBlockEndEvent
235
+ | BinaryBlockStartEvent
236
+ | BinaryBlockDeltaEvent
237
+ | BinaryBlockEndEvent
238
+ | ThinkingBlockStartEvent
239
+ | ThinkingBlockDeltaEvent
240
+ | ThinkingBlockEndEvent
241
+ | ToolCallStartEvent
242
+ | ToolCallDeltaEvent
243
+ | ToolCallEndEvent
244
+ | ToolResultStartEvent
245
+ | ToolResultTextDeltaEvent
246
+ | ToolResultBinaryDeltaEvent
247
+ | ToolResultEndEvent
248
+ // The events from the external execution or user confirmation
249
+ | UserConfirmResultEvent
250
+ | ExternalExecutionResultEvent;
@@ -0,0 +1,133 @@
1
+ import { Msg, TextBlock, DataBlock, createMsg } from '../message';
2
+
3
+ /**
4
+ * Base class for message formatters.
5
+ */
6
+ export abstract class FormatterBase {
7
+ /**
8
+ * Format the input message objects into the required format by the API.
9
+ *
10
+ * @param root0
11
+ * @param root0.msgs - An array of message objects to be formatted.
12
+ * @returns A promise that resolves to an array of formatted message objects.
13
+ */
14
+ abstract format({ msgs }: { msgs: Array<Msg> }): Promise<Record<string, unknown>[]>;
15
+
16
+ /**
17
+ * Convert the tool output to string format for the LLM APIs that only accept text input. If
18
+ * `promoteMultimodalToolResult` is true, the multimodal content will be promoted to be a user message with
19
+ * "<system-info></system-info>" tags. Otherwise, the multimodal content will be saved to a storage and a URL link
20
+ * will be provided in the text output.
21
+ *
22
+ * @param output - The tool output, which can be a string or an array of content blocks.
23
+ * @param promoteMultimodalToolResult - Whether to promote the multimodal content to the prompt messages.
24
+ * @returns An object containing the text output and an optional promoted message.
25
+ */
26
+ convertToolOutputToString(
27
+ output: string | (TextBlock | DataBlock)[],
28
+ promoteMultimodalToolResult: boolean | { image?: boolean; audio?: boolean; video?: boolean }
29
+ ) {
30
+ if (typeof output === 'string') return { text: output, promotedMsg: null };
31
+
32
+ let textualOutput = [];
33
+
34
+ const promotedData: { id: string; block: DataBlock }[] = [];
35
+
36
+ for (const block of output) {
37
+ switch (block.type) {
38
+ case 'text':
39
+ textualOutput.push(block.text);
40
+ break;
41
+ default:
42
+ const type = block.source.mediaType.split('/')[0];
43
+ if (type !== 'image' && type !== 'audio' && type !== 'video') {
44
+ console.log(
45
+ `Unsupported media type '${block.source.mediaType}' in tool output. Only image, audio and video are supported.`
46
+ );
47
+ break;
48
+ }
49
+ if (block.source.type === 'url') {
50
+ textualOutput.push(
51
+ `<system-info>One returned ${type} can be found at: ${block.source.url}</system-info>`
52
+ );
53
+ } else {
54
+ // If we should promote the multimodal content to the prompt messages
55
+ const shouldPromote =
56
+ promoteMultimodalToolResult === true ||
57
+ (typeof promoteMultimodalToolResult === 'object' &&
58
+ promoteMultimodalToolResult[type]);
59
+
60
+ if (shouldPromote) {
61
+ // Create an ID for the multimodal content first, which should less than 10 characters
62
+ const dataID = Math.random().toString(36).substring(2, 10);
63
+ textualOutput.push(
64
+ `<system-info>One returned ${type} is embedded with ID '${dataID}' and will be attached within '<system-info></system-info>' tags later.</system-info>`
65
+ );
66
+
67
+ // Record the promoted data
68
+ promotedData.push({ id: dataID, block });
69
+ } else {
70
+ // TODO: save locally
71
+
72
+ // Save to storage and provide URL link
73
+ textualOutput.push(`The returned ${block.type} is stored locally.`);
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ // Attach prefix and suffix system-info tags if there are promoted blocks
80
+ const promotedBlocks: (TextBlock | DataBlock)[] = [];
81
+ promotedData.forEach(({ id, block }) => {
82
+ const type = block.source.mediaType.split('/')[0];
83
+ promotedBlocks.push({
84
+ id: crypto.randomUUID(),
85
+ type: 'text',
86
+ text: `<${type}_data id='${id}'>`,
87
+ });
88
+ promotedBlocks.push(block);
89
+ promotedBlocks.push({
90
+ id: crypto.randomUUID(),
91
+ type: 'text',
92
+ text: `</${type}_data>\n`,
93
+ });
94
+ });
95
+
96
+ if (promotedBlocks.length > 0) {
97
+ // The prefix
98
+ const prefix =
99
+ '<system-info>The multimodal contents returned from the tool call are as follows:\n';
100
+
101
+ if (promotedBlocks[0].type === 'text') {
102
+ promotedBlocks[0].text = `${prefix}${promotedBlocks[0].text}`;
103
+ } else {
104
+ promotedBlocks.unshift({
105
+ id: crypto.randomUUID(),
106
+ type: 'text',
107
+ text: `${prefix}`,
108
+ });
109
+ }
110
+
111
+ // The suffix
112
+ const lastBlock = promotedBlocks[promotedBlocks.length - 1];
113
+ if (lastBlock.type === 'text') {
114
+ promotedBlocks[promotedBlocks.length - 1] = {
115
+ id: crypto.randomUUID(),
116
+ type: 'text',
117
+ text: `${lastBlock.text}</system-info>`,
118
+ };
119
+ } else {
120
+ promotedBlocks.push({
121
+ id: crypto.randomUUID(),
122
+ type: 'text',
123
+ text: `</system-info>`,
124
+ });
125
+ }
126
+ }
127
+
128
+ return {
129
+ text: textualOutput.join('\n'),
130
+ promotedMsg: createMsg({ name: 'user', content: promotedBlocks, role: 'user' }),
131
+ };
132
+ }
133
+ }