@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,1412 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/agent/index.ts
31
+ var agent_exports = {};
32
+ __export(agent_exports, {
33
+ Agent: () => Agent
34
+ });
35
+ module.exports = __toCommonJS(agent_exports);
36
+
37
+ // src/agent/agent.ts
38
+ var import_zod9 = require("zod");
39
+
40
+ // src/message/message.ts
41
+ function createMsg({
42
+ name,
43
+ content,
44
+ role,
45
+ metadata = {},
46
+ id = crypto.randomUUID(),
47
+ timestamp = (/* @__PURE__ */ new Date()).toISOString(),
48
+ usage
49
+ }) {
50
+ return { id, name, role, content, metadata, timestamp, usage };
51
+ }
52
+ function getContentBlocks(msg, blockType) {
53
+ if (!blockType) return msg.content;
54
+ return msg.content.filter((block) => block.type === blockType);
55
+ }
56
+
57
+ // src/tool/response.ts
58
+ function createToolResponse({
59
+ content,
60
+ state,
61
+ id = crypto.randomUUID(),
62
+ createdAt = (/* @__PURE__ */ new Date()).toISOString(),
63
+ metadata = {},
64
+ stream = false,
65
+ isLast = true,
66
+ isInterrupted = false
67
+ }) {
68
+ return {
69
+ content,
70
+ id,
71
+ createdAt,
72
+ metadata,
73
+ state,
74
+ stream,
75
+ isLast,
76
+ isInterrupted
77
+ };
78
+ }
79
+ function isToolResponse(obj) {
80
+ return obj && typeof obj === "object" && typeof obj.id === "string" && typeof obj.createdAt === "string" && Array.isArray(obj.content) && typeof obj.metadata === "object" && typeof obj.stream === "boolean" && typeof obj.isLast === "boolean" && typeof obj.isInterrupted === "boolean" && ["success", "error", "interrupted", "running"].includes(obj.state);
81
+ }
82
+
83
+ // src/tool/toolkit.ts
84
+ var fs = __toESM(require("fs"));
85
+ var path = __toESM(require("path"));
86
+ var import_json_schema = require("@cfworker/json-schema");
87
+ var import_gray_matter = __toESM(require("gray-matter"));
88
+ var import_zod = require("zod");
89
+
90
+ // src/_utils/common.ts
91
+ var import_jsonrepair = require("jsonrepair");
92
+ function _jsonLoadsWithRepair(input) {
93
+ try {
94
+ const jsonObj = JSON.parse(input);
95
+ if (typeof jsonObj === "object" && jsonObj !== null && !Array.isArray(jsonObj)) {
96
+ return jsonObj;
97
+ } else {
98
+ return {};
99
+ }
100
+ } catch {
101
+ try {
102
+ const repairedString = (0, import_jsonrepair.jsonrepair)(input);
103
+ const jsonObj = JSON.parse(repairedString);
104
+ if (typeof jsonObj === "object" && jsonObj !== null && !Array.isArray(jsonObj)) {
105
+ return jsonObj;
106
+ } else {
107
+ return {};
108
+ }
109
+ } catch (e) {
110
+ console.error(`Failed to parse JSON "${input}" with error:`, e);
111
+ return {};
112
+ }
113
+ }
114
+ }
115
+
116
+ // src/tool/toolkit.ts
117
+ var Toolkit = class {
118
+ tools;
119
+ skills;
120
+ skillDirs;
121
+ // The cache mapping from the skill name to its corresponding tool name in the toolkit.
122
+ _skillCache;
123
+ /**
124
+ * Initializes a new instance of the Toolkit class.
125
+ * @param config - The configuration object for initializing the toolkit, which can include an array of tools, an array of skill paths, an array of skill directory paths, and a boolean indicating whether to include the built-in skill tool for reading SKILL.md files.
126
+ * @param config.tools - An array of tool definitions to register in the toolkit.
127
+ * @param config.skills - An array of file paths pointing to individual skills.
128
+ * @param config.skillDirs - An array of directory paths, where each directory can contain multiple skills in its subdirectories.
129
+ * @param config.builtInSkillTool - A boolean flag indicating whether to include the built-in skill tool for reading SKILL.md files.
130
+ */
131
+ constructor(config) {
132
+ const { tools = [], skills = [], skillDirs = [], builtInSkillTool = true } = config || {};
133
+ this.tools = [];
134
+ if (builtInSkillTool) {
135
+ this.tools.push({
136
+ type: "function",
137
+ name: "Skill",
138
+ description: `Retrieves the full content of a skill by reading its SKILL.md file. Skills are packages of domain expertise that extend agent capabilities. Use this tool to access detailed instructions, examples, and guidelines for a specific skill.
139
+
140
+ Usage:
141
+ - Provide the skill name as the input parameter
142
+ - The tool will return the complete SKILL.md file content for that skill
143
+ - If the skill is not found, an error message with available skills will be returned
144
+ - Available skills are listed in the skills-system section of the agent prompt`,
145
+ inputSchema: import_zod.z.object({ name: import_zod.z.string().describe("The name of the skill") }),
146
+ call: this._skillTool.bind(this),
147
+ requireUserConfirm: false
148
+ });
149
+ }
150
+ tools.map((tool) => {
151
+ this.tools.push({
152
+ type: "function",
153
+ ...tool
154
+ });
155
+ });
156
+ this.skills = skills;
157
+ this.skillDirs = skillDirs;
158
+ this._skillCache = {};
159
+ }
160
+ /**
161
+ * Registers a tool function to the toolkit. The function can be either a plain function that adheres to the ToolFunction type, or an instance of a class that extends ToolBase. When registering a plain function, the name, description, and input schema must be provided explicitly. When registering a ToolBase instance, these properties will be extracted from the instance itself.
162
+ *
163
+ * @params tool - The tool function to register, which can be either a plain function with explicit properties or an instance of a class that extends ToolBase.
164
+ * @returns The Toolkit instance with the new tool function registered
165
+ * @param tool
166
+ */
167
+ registerToolFunction(tool) {
168
+ this.tools.push({
169
+ type: "function",
170
+ ...tool
171
+ });
172
+ return this;
173
+ }
174
+ /**
175
+ * Registers functions from a given MCP client.
176
+ *
177
+ * @param root0
178
+ * @param root0.client
179
+ * @param root0.enabledTools
180
+ * @param root0.disabledTools
181
+ * @param root0.requireUserConfirm
182
+ * @returns The Toolkit instance with the new tools registered
183
+ */
184
+ async registerMCPClient({
185
+ client,
186
+ enabledTools,
187
+ disabledTools = [],
188
+ requireUserConfirm = false
189
+ }) {
190
+ const tools = await client.listTools();
191
+ const appendTools = [];
192
+ tools.filter(
193
+ (tool) => !(enabledTools && !enabledTools.includes(tool.name)) && !disabledTools.includes(tool.name)
194
+ ).forEach((tool) => {
195
+ this.tools.push({
196
+ type: "mcp",
197
+ mcpName: client.name,
198
+ ...tool,
199
+ requireUserConfirm
200
+ });
201
+ appendTools.push(tool.name);
202
+ });
203
+ console.log(`Registered tools from MCP client '${client.name}': ${appendTools.join(", ")}`);
204
+ return this;
205
+ }
206
+ /**
207
+ * Executes a registered tool function based on the provided ToolUseBlock.
208
+ * Note this method always returns an AsyncGenerator of ToolResponse, regardless of the tool function type.
209
+ *
210
+ * @param toolCall - The ToolUseBlock containing the tool name and input arguments
211
+ * @yields Incremental ToolResponse objects as they are produced by the tool function
212
+ * @returns The final complete ToolResponse after the tool function execution is finished
213
+ */
214
+ async *callToolFunction(toolCall) {
215
+ const tool = this.tools.find((tool2) => tool2.name === toolCall.name);
216
+ if (!tool) {
217
+ const notFoundRes = createToolResponse({
218
+ content: [
219
+ {
220
+ id: crypto.randomUUID(),
221
+ type: "text",
222
+ text: `FunctionNotFoundError: Cannot find the function named ${toolCall.name}`
223
+ }
224
+ ],
225
+ state: "error"
226
+ });
227
+ yield notFoundRes;
228
+ return notFoundRes;
229
+ }
230
+ let parsedInput;
231
+ try {
232
+ parsedInput = _jsonLoadsWithRepair(toolCall.input);
233
+ if (tool.inputSchema instanceof import_zod.z.ZodObject) {
234
+ tool.inputSchema.parse(parsedInput);
235
+ } else {
236
+ const validator = new import_json_schema.Validator(tool.inputSchema);
237
+ const validation = validator.validate(parsedInput);
238
+ if (!validation.valid) {
239
+ throw new Error(`Invalid input arguments: ${validation.errors}`);
240
+ }
241
+ }
242
+ } catch (error) {
243
+ const parseErrorRes = createToolResponse({
244
+ content: [
245
+ {
246
+ id: crypto.randomUUID(),
247
+ type: "text",
248
+ text: `InvalidArgumentError: ${String(error)}`
249
+ }
250
+ ],
251
+ state: "error"
252
+ });
253
+ yield parseErrorRes;
254
+ return parseErrorRes;
255
+ }
256
+ if (!tool.call) {
257
+ throw new Error(
258
+ `Cannot execute external tool '${toolCall.name}' because no call method is defined for it in the toolkit.`
259
+ );
260
+ }
261
+ let finalRes = null;
262
+ try {
263
+ const res = await tool.call(parsedInput);
264
+ if (typeof res === "string") {
265
+ const textRes = createToolResponse({
266
+ content: [
267
+ {
268
+ id: crypto.randomUUID(),
269
+ type: "text",
270
+ text: res
271
+ }
272
+ ],
273
+ state: "success"
274
+ });
275
+ yield textRes;
276
+ finalRes = textRes;
277
+ } else if (isToolResponse(res)) {
278
+ yield res;
279
+ finalRes = res;
280
+ } else if (Symbol.asyncIterator in res) {
281
+ const accContent = [];
282
+ let nextResult = await res.next();
283
+ while (!nextResult.done) {
284
+ const currentValue = nextResult.value;
285
+ nextResult = await res.next();
286
+ const isLastValue = nextResult.done;
287
+ if (typeof currentValue === "string") {
288
+ const itemRes = createToolResponse({
289
+ content: [
290
+ {
291
+ id: crypto.randomUUID(),
292
+ type: "text",
293
+ text: currentValue
294
+ }
295
+ ],
296
+ isLast: isLastValue,
297
+ state: "running"
298
+ });
299
+ yield itemRes;
300
+ accContent.push({
301
+ id: crypto.randomUUID(),
302
+ type: "text",
303
+ text: currentValue
304
+ });
305
+ } else if (isToolResponse(currentValue)) {
306
+ currentValue.isLast = currentValue.isLast ?? isLastValue;
307
+ yield currentValue;
308
+ accContent.push(...currentValue.content);
309
+ }
310
+ }
311
+ finalRes = createToolResponse({
312
+ content: accContent,
313
+ state: "success"
314
+ });
315
+ } else if (Symbol.iterator in res) {
316
+ const accContent = [];
317
+ let nextResult = res.next();
318
+ while (!nextResult.done) {
319
+ const currentValue = nextResult.value;
320
+ nextResult = res.next();
321
+ const isLastValue = nextResult.done;
322
+ if (typeof currentValue === "string") {
323
+ const itemRes = createToolResponse({
324
+ content: [
325
+ {
326
+ id: crypto.randomUUID(),
327
+ type: "text",
328
+ text: currentValue
329
+ }
330
+ ],
331
+ isLast: isLastValue,
332
+ state: "running"
333
+ });
334
+ yield itemRes;
335
+ accContent.push({
336
+ id: crypto.randomUUID(),
337
+ type: "text",
338
+ text: currentValue
339
+ });
340
+ } else if (isToolResponse(currentValue)) {
341
+ currentValue.isLast = currentValue.isLast ?? isLastValue;
342
+ yield currentValue;
343
+ accContent.push(...currentValue.content);
344
+ }
345
+ }
346
+ finalRes = createToolResponse({
347
+ content: accContent,
348
+ state: "success"
349
+ });
350
+ } else {
351
+ const invalidRes = createToolResponse({
352
+ content: [
353
+ {
354
+ id: crypto.randomUUID(),
355
+ type: "text",
356
+ text: String(res)
357
+ }
358
+ ],
359
+ state: "running"
360
+ });
361
+ yield invalidRes;
362
+ finalRes = invalidRes;
363
+ }
364
+ } catch (error) {
365
+ const errorRes = createToolResponse({
366
+ content: [
367
+ {
368
+ id: crypto.randomUUID(),
369
+ type: "text",
370
+ text: `ToolExecutionError: ${String(error)}`
371
+ }
372
+ ],
373
+ state: "error"
374
+ });
375
+ yield errorRes;
376
+ finalRes = errorRes;
377
+ }
378
+ if (!finalRes) {
379
+ return createToolResponse({
380
+ content: [
381
+ {
382
+ id: crypto.randomUUID(),
383
+ type: "text",
384
+ text: `Tool ${toolCall.name} executed successfully.`
385
+ }
386
+ ],
387
+ state: "success"
388
+ });
389
+ }
390
+ const cleanedContent = [];
391
+ let textBuffer = "";
392
+ for (const block of finalRes.content) {
393
+ if (block.type === "text") {
394
+ textBuffer += block.text;
395
+ } else {
396
+ if (textBuffer) {
397
+ cleanedContent.push({
398
+ id: crypto.randomUUID(),
399
+ type: "text",
400
+ text: textBuffer
401
+ });
402
+ textBuffer = "";
403
+ }
404
+ cleanedContent.push(block);
405
+ }
406
+ }
407
+ if (textBuffer) {
408
+ cleanedContent.push({
409
+ id: crypto.randomUUID(),
410
+ type: "text",
411
+ text: textBuffer
412
+ });
413
+ }
414
+ return {
415
+ ...finalRes,
416
+ content: cleanedContent
417
+ };
418
+ }
419
+ /**
420
+ * Returns the JSON schemas for all registered tools in a format compatible with LLM APIs.
421
+ *
422
+ * @returns An array of ToolJSONSchema objects
423
+ */
424
+ getJSONSchemas() {
425
+ return this.tools.map((tool) => {
426
+ const inputSchema = tool.inputSchema instanceof import_zod.z.ZodObject ? tool.inputSchema.toJSONSchema({ target: "openapi-3.0" }) : tool.inputSchema;
427
+ return {
428
+ type: "function",
429
+ function: {
430
+ name: tool.name,
431
+ description: tool.description,
432
+ parameters: inputSchema
433
+ }
434
+ };
435
+ });
436
+ }
437
+ /**
438
+ * Get the instruction prompt for the agent to use the skills.
439
+ *
440
+ * @returns A string containing the instruction prompt of the available skills and how to use them.
441
+ */
442
+ getSkillsPrompt() {
443
+ this._skillCache = {};
444
+ if (this.skills.length === 0 && this.skillDirs.length === 0) return "";
445
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
446
+ const skillsInfo = [];
447
+ this.skills.forEach((skillPath) => {
448
+ const absSkillPath = path.resolve(skillPath);
449
+ if (!fs.existsSync(absSkillPath) || !fs.statSync(absSkillPath).isDirectory()) {
450
+ return;
451
+ }
452
+ const skillMdPath = path.join(absSkillPath, "SKILL.md");
453
+ if (!fs.existsSync(skillMdPath)) return;
454
+ try {
455
+ const content = fs.readFileSync(skillMdPath, "utf-8");
456
+ const { data } = (0, import_gray_matter.default)(content);
457
+ const name = data.name || path.basename(skillPath);
458
+ const description = data.description || "No description provided";
459
+ skillsInfo.push({
460
+ name,
461
+ description,
462
+ location: absSkillPath
463
+ });
464
+ this._skillCache[name] = absSkillPath;
465
+ } catch (e) {
466
+ console.error(`Error reading SKILL.md for skill at ${skillPath}:`, e);
467
+ }
468
+ });
469
+ this.skillDirs.forEach((skillDir) => {
470
+ const absSkillDir = path.resolve(skillDir);
471
+ if (!fs.existsSync(absSkillDir) || !fs.statSync(absSkillDir).isDirectory()) {
472
+ return;
473
+ }
474
+ const subdirs = fs.readdirSync(absSkillDir).filter((subdir) => {
475
+ const subdirPath = path.join(absSkillDir, subdir);
476
+ return fs.statSync(subdirPath).isDirectory();
477
+ });
478
+ subdirs.forEach((subdir) => {
479
+ const skillMdPath = path.join(absSkillDir, subdir, "SKILL.md");
480
+ if (!fs.existsSync(skillMdPath)) return;
481
+ try {
482
+ const content = fs.readFileSync(skillMdPath, "utf-8");
483
+ const { data } = (0, import_gray_matter.default)(content);
484
+ const name = data.name || subdir;
485
+ const description = data.description || "No description provided";
486
+ skillsInfo.push({
487
+ name,
488
+ description,
489
+ location: path.join(skillDir, subdir)
490
+ });
491
+ this._skillCache[name] = path.join(absSkillDir, subdir);
492
+ } catch (e) {
493
+ console.error(
494
+ `Error reading SKILL.md for skill at ${path.join(skillDir, subdir)}:`,
495
+ e
496
+ );
497
+ }
498
+ });
499
+ });
500
+ if (skillsInfo.length === 0) return "";
501
+ const skillsXml = skillsInfo.map(
502
+ (skill) => `<skill>
503
+ <name>${skill.name}</name>
504
+ <description>${skill.description}</description>
505
+ <location>${skill.location}</location>
506
+ </skill>`
507
+ ).reduce((acc, skillInfo) => acc + `
508
+ ${skillInfo}
509
+ `, "");
510
+ return `<skills-system>
511
+ ## What are Skills?
512
+ Skills are packages of domain expertise that extend your capabilities.
513
+
514
+ ## Important: How to Use Skills
515
+ **Skill names are NOT callable functions.** You cannot call a skill directly by its name.
516
+ ${skillsXml}
517
+ </skills-system>`;
518
+ }
519
+ return "";
520
+ }
521
+ /**
522
+ * The agent skill tool to read SKILL.md file content based on the skill name.
523
+ * @param root0
524
+ * @param root0.name
525
+ * @returns The content of the SKILL.md file for the specified skill, or an error message if the skill is not
526
+ * found or the SKILL.md file cannot be read.
527
+ */
528
+ async _skillTool({ name }) {
529
+ if (this._skillCache[name]) {
530
+ const skillDir = this._skillCache[name];
531
+ const skillMdPath = path.join(skillDir, "SKILL.md");
532
+ if (!fs.existsSync(skillMdPath)) {
533
+ try {
534
+ const fileContent = fs.readFileSync(skillMdPath, "utf-8");
535
+ return createToolResponse({
536
+ content: [
537
+ {
538
+ id: crypto.randomUUID(),
539
+ type: "text",
540
+ text: fileContent
541
+ }
542
+ ],
543
+ state: "success"
544
+ });
545
+ } catch {
546
+ }
547
+ }
548
+ }
549
+ this.getSkillsPrompt();
550
+ const refreshedSkillDir = this._skillCache[name];
551
+ if (refreshedSkillDir) {
552
+ const skillMdPath = path.join(refreshedSkillDir, "SKILL.md");
553
+ try {
554
+ const fileContent = fs.readFileSync(skillMdPath, "utf-8");
555
+ return createToolResponse({
556
+ content: [
557
+ {
558
+ id: crypto.randomUUID(),
559
+ type: "text",
560
+ text: fileContent
561
+ }
562
+ ],
563
+ state: "success"
564
+ });
565
+ } catch {
566
+ }
567
+ }
568
+ return createToolResponse({
569
+ content: [
570
+ {
571
+ id: crypto.randomUUID(),
572
+ type: "text",
573
+ text: `SkillNotFoundError: Cannot find the skill named ${name}, current available skills are ${Object.keys(this._skillCache).join(", ")}`
574
+ }
575
+ ],
576
+ state: "error"
577
+ });
578
+ }
579
+ /**
580
+ * Checks if a tool requires user confirmation before execution based on its name.
581
+ * @param toolName The name of the tool to check for user confirmation requirement.
582
+ * @returns A boolean indicating whether the specified tool requires user confirmation before execution. If the tool is not found, it returns false.
583
+ */
584
+ requireUserConfirm(toolName) {
585
+ const tool = this.tools.find((tool2) => tool2.name === toolName);
586
+ return tool ? tool.requireUserConfirm ?? false : false;
587
+ }
588
+ /**
589
+ * Checks if a tool requires external execution (e.g., by an MCP client) based on its name.
590
+ * @param toolName
591
+ * @returns A boolean indicating whether the specified tool requires external execution. If the tool is not found, it returns false.
592
+ */
593
+ requireExternalExecution(toolName) {
594
+ const tool = this.tools.find((tool2) => tool2.name === toolName);
595
+ return tool ? !tool.call : false;
596
+ }
597
+ };
598
+
599
+ // src/tool/bash.ts
600
+ var import_child_process = require("child_process");
601
+ var import_util = require("util");
602
+ var import_zod2 = require("zod");
603
+ var execAsync = (0, import_util.promisify)(import_child_process.exec);
604
+
605
+ // src/tool/read.ts
606
+ var import_zod3 = require("zod");
607
+
608
+ // src/tool/write.ts
609
+ var import_zod4 = require("zod");
610
+
611
+ // src/tool/edit.ts
612
+ var import_zod5 = require("zod");
613
+
614
+ // src/tool/glob.ts
615
+ var import_zod6 = require("zod");
616
+
617
+ // src/tool/grep.ts
618
+ var import_zod7 = require("zod");
619
+
620
+ // src/tool/task.ts
621
+ var import_zod8 = require("zod");
622
+
623
+ // src/agent/agent.ts
624
+ var DEFAULT_COMPRESSION_PROMPT = "<system-hint>You have been working on the task described above but have not yet completed it. Now write a continuation summary that will allow you to resume work efficiently in a future context window where the conversation history will be replaced with this summary. Your summary should be structured, concise, and actionable.</system-hint>";
625
+ var DEFAULT_SUMMARY_SCHEMA = import_zod9.z.object({
626
+ task_overview: import_zod9.z.string().max(300).describe(
627
+ "The user's core request and success criteria. Any clarifications or constraints they specified"
628
+ ),
629
+ current_state: import_zod9.z.string().max(300).describe(
630
+ "What has been completed so far. File created, modified, or analyzed (with paths if relevant). Key outputs or artifacts produced."
631
+ ),
632
+ important_discoveries: import_zod9.z.string().max(300).describe(
633
+ "Technical constraints or requirements uncovered. Decisions made and their rationale. Errors encountered and how they were resolved. What approaches were tried that didn't work (and why)"
634
+ ),
635
+ next_steps: import_zod9.z.string().max(200).describe(
636
+ "Specific actions needed to complete the task. Any blockers or open questions to resolve. Priority order if multiple steps remain"
637
+ ),
638
+ context_to_preserve: import_zod9.z.string().max(300).describe(
639
+ "User preferences or style requirements. Domain-specific details that aren't obvious. Any promises made to the user"
640
+ )
641
+ });
642
+ var Agent = class {
643
+ // Agent configuration
644
+ name;
645
+ model;
646
+ maxIters;
647
+ toolkit;
648
+ storage;
649
+ context;
650
+ _loaded;
651
+ _sysPrompt;
652
+ compressionConfig;
653
+ // Agent state
654
+ replyId;
655
+ curIter;
656
+ confirmedToolCallIds;
657
+ curSummary;
658
+ /**
659
+ * Initialize an agent instance with the given parameters.
660
+ *
661
+ * @param options - The agent configuration options.
662
+ * @param options.name - The name of the agent.
663
+ * @param options.sysPrompt - The system prompt for the agent.
664
+ * @param options.model - The chat model to use.
665
+ * @param options.maxIters - Maximum iterations (default: 5).
666
+ * @param options.memory - Memory storage (default: InMemoryMemory).
667
+ * @param options.toolkit - Toolkit for tools (default: Toolkit).
668
+ */
669
+ constructor(options) {
670
+ if (options.maxIters !== void 0 && options.maxIters <= 0) {
671
+ throw new Error("maxIters must be greater than 0");
672
+ }
673
+ this.name = options.name;
674
+ this._sysPrompt = options.sysPrompt;
675
+ this.model = options.model;
676
+ this.maxIters = options.maxIters ?? 20;
677
+ this.context = [];
678
+ this.toolkit = options.toolkit ?? new Toolkit();
679
+ this.storage = options.storage;
680
+ this.compressionConfig = options.compressionConfig;
681
+ this._loaded = false;
682
+ this.replyId = "";
683
+ this.curIter = 0;
684
+ this.confirmedToolCallIds = [];
685
+ this.curSummary = "";
686
+ }
687
+ /**
688
+ * Load the state from the storage if storage is provided and not loaded yet.
689
+ */
690
+ async loadState() {
691
+ if (this._loaded || !this.storage) return;
692
+ const { context, metadata } = await this.storage.loadAgentState({ agentId: this.name });
693
+ console.log(`Load state for agent "${this.name}" from storage:`, { context, metadata });
694
+ this.context = context;
695
+ this.replyId = metadata.replyId || "";
696
+ this.curIter = metadata.curIter || 0;
697
+ this.curSummary = metadata.curSummary || "";
698
+ this._loaded = true;
699
+ }
700
+ /**
701
+ * Save the state of the current reply session to storage if storage is provided.
702
+ */
703
+ async saveState() {
704
+ if (!this.storage) return;
705
+ await this.storage.saveAgentState({
706
+ agentId: this.name,
707
+ context: this.context,
708
+ metadata: {
709
+ replyId: this.replyId,
710
+ curIter: this.curIter,
711
+ curSummary: this.curSummary
712
+ }
713
+ });
714
+ }
715
+ /**
716
+ * Get the system prompt of the agent.
717
+ *
718
+ * @returns The system prompt string.
719
+ */
720
+ get sysPrompt() {
721
+ const skillsPrompt = this.toolkit.getSkillsPrompt();
722
+ if (skillsPrompt.length > 0) {
723
+ return this._sysPrompt + "\n\n" + skillsPrompt;
724
+ }
725
+ return this._sysPrompt;
726
+ }
727
+ /**
728
+ * Reply to the given message and stream agent events as they are generated.
729
+ *
730
+ * @param options - The reply options containing the incoming message.
731
+ * @returns An async generator that yields agent events and resolves to the final reply message.
732
+ */
733
+ async *replyStream(options) {
734
+ await this.loadState();
735
+ try {
736
+ return yield* this._reply(options);
737
+ } finally {
738
+ await this.saveState();
739
+ }
740
+ }
741
+ /**
742
+ * Reply to the given message, consuming all streamed events internally.
743
+ *
744
+ * @param options - The reply options containing the incoming message.
745
+ * @param options.msgs - The incoming message(s) to reply to.
746
+ * @returns A promise that resolves to the final reply message.
747
+ */
748
+ async reply(options) {
749
+ await this.loadState();
750
+ try {
751
+ const res = this._reply(options);
752
+ while (true) {
753
+ const { value, done } = await res.next();
754
+ if (done) {
755
+ return value;
756
+ }
757
+ }
758
+ } finally {
759
+ await this.saveState();
760
+ }
761
+ }
762
+ /**
763
+ * Save the given content blocks into the context as a new block in the last assistant message,
764
+ * or create a new assistant message if the last message is not from the assistant or has a different name.
765
+ * @param blocks
766
+ * @param usage
767
+ */
768
+ _saveToContext(blocks, usage) {
769
+ const lastMsg = this.context.at(-1);
770
+ if (this.context.length === 0) {
771
+ this.context.push(
772
+ createMsg({ name: this.name, content: blocks, role: "assistant", usage })
773
+ );
774
+ } else if (lastMsg && lastMsg.role === "assistant" && lastMsg.name === this.name) {
775
+ lastMsg.content.push(...blocks);
776
+ if (usage) {
777
+ if (!lastMsg.usage) {
778
+ lastMsg.usage = {
779
+ inputTokens: 0,
780
+ outputTokens: 0
781
+ };
782
+ }
783
+ lastMsg.usage.inputTokens = lastMsg.usage.inputTokens + usage.inputTokens;
784
+ lastMsg.usage.outputTokens = lastMsg.usage.outputTokens + usage.outputTokens;
785
+ }
786
+ } else {
787
+ this.context.push(
788
+ createMsg({ name: this.name, content: blocks, role: "assistant", usage })
789
+ );
790
+ }
791
+ }
792
+ /**
793
+ * Get the pending tool calls that have no results yet in the context.
794
+ * @returns An array of pending `ToolCallBlock`s that are waiting for execution results.
795
+ */
796
+ _getPendingToolCalls() {
797
+ if (this.context.length === 0) return [];
798
+ const lastMsg = this.context.at(-1);
799
+ if (!lastMsg) return [];
800
+ if (lastMsg.role === "assistant") {
801
+ const toolCalls = getContentBlocks(lastMsg, "tool_call");
802
+ const toolResults = getContentBlocks(lastMsg, "tool_result");
803
+ return toolCalls.filter((toolCall) => !toolResults.some((tr) => tr.id === toolCall.id));
804
+ }
805
+ return [];
806
+ }
807
+ /**
808
+ * Get the awaiting tool calls that require user confirmation or external execution.
809
+ * @returns An array of `ToolCallBlock`s that are waiting for user confirmation or external execution.
810
+ */
811
+ _getAwaitingToolCalls() {
812
+ const pendingToolCalls = this._getPendingToolCalls();
813
+ const preToolCalls = [];
814
+ for (const [index, toolCall] of pendingToolCalls.entries()) {
815
+ if (this.toolkit.requireUserConfirm(toolCall.name) && !this.confirmedToolCallIds.includes(toolCall.id)) {
816
+ toolCall.awaitUserConfirmation = true;
817
+ let i = index + 1;
818
+ for (; i < pendingToolCalls.length; i++) {
819
+ const nextToolCall = pendingToolCalls[i];
820
+ if (!this.toolkit.requireUserConfirm(nextToolCall.name) || this.confirmedToolCallIds.includes(nextToolCall.id))
821
+ break;
822
+ nextToolCall.awaitUserConfirmation = true;
823
+ }
824
+ return {
825
+ awaitingType: "REQUIRE_USER_CONFIRM" /* REQUIRE_USER_CONFIRM */,
826
+ expectedEventType: "USER_CONFIRM_RESULT" /* USER_CONFIRM_RESULT */,
827
+ awaitingToolCalls: pendingToolCalls.slice(index, i),
828
+ preToolCalls
829
+ };
830
+ }
831
+ if (this.toolkit.requireExternalExecution(toolCall.name)) {
832
+ let i = index + 1;
833
+ for (; i < pendingToolCalls.length; i++) {
834
+ const nextToolCall = pendingToolCalls[i];
835
+ if (!this.toolkit.requireExternalExecution(nextToolCall.name)) break;
836
+ }
837
+ return {
838
+ awaitingType: "REQUIRE_EXTERNAL_EXECUTION" /* REQUIRE_EXTERNAL_EXECUTION */,
839
+ expectedEventType: "EXTERNAL_EXECUTION_RESULT" /* EXTERNAL_EXECUTION_RESULT */,
840
+ awaitingToolCalls: pendingToolCalls.slice(index, i),
841
+ preToolCalls
842
+ };
843
+ }
844
+ preToolCalls.push(toolCall);
845
+ }
846
+ return { awaitingToolCalls: [], preToolCalls };
847
+ }
848
+ /**
849
+ * Core reply logic without middlewares. Observes the incoming message, runs
850
+ * reasoning/acting iterations up to `maxIters`, and returns the final response.
851
+ *
852
+ * @param options - The reply options containing the incoming message.
853
+ * @returns An async generator that yields agent events and resolves to the final reply message.
854
+ */
855
+ async *_reply(options) {
856
+ const { expectedEventType } = this._getAwaitingToolCalls();
857
+ if (expectedEventType) {
858
+ if (!options || !options.event || options.event.type !== expectedEventType) {
859
+ throw new Error(
860
+ `Agent is awaiting for '${expectedEventType}' confirmation, but received event of type '${options?.event?.type ?? "none"}'.`
861
+ );
862
+ }
863
+ const event = options.event;
864
+ if (event.type === "EXTERNAL_EXECUTION_RESULT" /* EXTERNAL_EXECUTION_RESULT */) {
865
+ this._saveToContext(event.executionResults);
866
+ } else if (event.type === "USER_CONFIRM_RESULT" /* USER_CONFIRM_RESULT */) {
867
+ for (const result of event.confirmResults) {
868
+ if (result.confirmed) {
869
+ this.confirmedToolCallIds.push(result.toolCall.id);
870
+ } else {
871
+ const rejectionRes = `<system-info>**Note** the user rejected the execution of tool "${result.toolCall.name}"!</system-info>`;
872
+ yield {
873
+ id: crypto.randomUUID(),
874
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
875
+ type: "TOOL_RESULT_START" /* TOOL_RESULT_START */,
876
+ replyId: this.replyId,
877
+ toolCallId: result.toolCall.id
878
+ };
879
+ yield {
880
+ id: crypto.randomUUID(),
881
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
882
+ type: "TOOL_RESULT_TEXT_DELTA" /* TOOL_RESULT_TEXT_DELTA */,
883
+ replyId: this.replyId,
884
+ toolCallId: result.toolCall.id,
885
+ delta: rejectionRes
886
+ };
887
+ yield {
888
+ id: crypto.randomUUID(),
889
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
890
+ type: "TOOL_RESULT_END" /* TOOL_RESULT_END */,
891
+ replyId: this.replyId,
892
+ toolCallId: result.toolCall.id,
893
+ state: "interrupted"
894
+ };
895
+ this._saveToContext([
896
+ {
897
+ type: "tool_result",
898
+ id: result.toolCall.id,
899
+ name: result.toolCall.name,
900
+ output: [
901
+ {
902
+ id: crypto.randomUUID(),
903
+ type: "text",
904
+ text: `<system-info>**Note** the user rejected the execution of tool "${result.toolCall.name}"!</system-info>`
905
+ }
906
+ ],
907
+ state: "interrupted"
908
+ }
909
+ ]);
910
+ }
911
+ }
912
+ const processedToolCallIds = event.confirmResults.map((result) => result.toolCall.id);
913
+ this.context.at(-1)?.content.forEach((content) => {
914
+ if (content.type === "tool_call" && processedToolCallIds.includes(content.id)) {
915
+ delete content.awaitUserConfirmation;
916
+ }
917
+ });
918
+ }
919
+ } else {
920
+ this.curIter = 0;
921
+ this.replyId = crypto.randomUUID();
922
+ this.confirmedToolCallIds = [];
923
+ yield {
924
+ id: crypto.randomUUID(),
925
+ type: "RUN_STARTED" /* RUN_STARTED */,
926
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
927
+ sessionId: "",
928
+ replyId: this.replyId,
929
+ name: this.name,
930
+ role: "assistant"
931
+ };
932
+ }
933
+ if (Array.isArray(options?.msgs)) {
934
+ this.context.push(...options.msgs);
935
+ } else if (options?.msgs) {
936
+ this.context.push(options.msgs);
937
+ }
938
+ while (this.curIter < this.maxIters) {
939
+ const pendingToolCalls = this._getPendingToolCalls();
940
+ if (pendingToolCalls.length === 0) {
941
+ await this.compressMemoryIfNeeded();
942
+ const reasoningResponse = yield* this._reasoning({ toolChoice: "auto" });
943
+ this._saveToContext(reasoningResponse.content, reasoningResponse.usage);
944
+ }
945
+ const { awaitingType, awaitingToolCalls, preToolCalls } = this._getAwaitingToolCalls();
946
+ for (const toolCall of preToolCalls) {
947
+ const actingContent = yield* this._acting({ toolCall });
948
+ this._saveToContext([actingContent]);
949
+ this.confirmedToolCallIds = this.confirmedToolCallIds.filter(
950
+ (id) => id !== toolCall.id
951
+ );
952
+ }
953
+ if (awaitingType) {
954
+ yield {
955
+ id: crypto.randomUUID(),
956
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
957
+ type: awaitingType,
958
+ replyId: this.replyId,
959
+ toolCalls: awaitingToolCalls
960
+ };
961
+ return createMsg({
962
+ name: this.name,
963
+ content: [
964
+ {
965
+ id: crypto.randomUUID(),
966
+ type: "text",
967
+ text: awaitingType === "REQUIRE_USER_CONFIRM" /* REQUIRE_USER_CONFIRM */ ? "Waiting for user confirmation ..." : "Waiting for external execution ..."
968
+ }
969
+ ],
970
+ role: "assistant"
971
+ });
972
+ }
973
+ if (preToolCalls.length === 0) break;
974
+ this.curIter += 1;
975
+ }
976
+ if (this.context.at(-1)?.content.at(-1)?.type !== "text") {
977
+ const summaryResponse = yield* this._reasoning({ toolChoice: "none" });
978
+ this._saveToContext(summaryResponse.content, summaryResponse.usage);
979
+ }
980
+ yield {
981
+ id: crypto.randomUUID(),
982
+ type: "RUN_FINISHED" /* RUN_FINISHED */,
983
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
984
+ sessionId: "",
985
+ replyId: this.replyId
986
+ };
987
+ return createMsg({
988
+ id: this.replyId,
989
+ name: this.name,
990
+ // Must be a string for the final output message
991
+ content: [this.context.at(-1).content.at(-1)],
992
+ role: "assistant"
993
+ });
994
+ }
995
+ /**
996
+ * Core reasoning logic without middlewares. Calls the model with the current
997
+ * memory and system prompt, converts the response to agent events, and saves
998
+ * the resulting message to memory.
999
+ *
1000
+ * @param options - The reasoning options, including tool choice strategy.
1001
+ * @returns An async generator that yields agent events and resolves to the content blocks of the model response.
1002
+ */
1003
+ async *_reasoning(options) {
1004
+ const tools = this.toolkit.getJSONSchemas();
1005
+ yield {
1006
+ id: crypto.randomUUID(),
1007
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1008
+ type: "MODEL_CALL_STARTED" /* MODEL_CALL_STARTED */,
1009
+ replyId: this.replyId,
1010
+ modelName: this.model.modelName
1011
+ };
1012
+ const res = await this.model.call({
1013
+ messages: [
1014
+ createMsg({
1015
+ name: "system",
1016
+ content: [{ type: "text", text: this.sysPrompt, id: crypto.randomUUID() }],
1017
+ role: "system"
1018
+ }),
1019
+ ...this.curSummary ? [
1020
+ createMsg({
1021
+ name: "user",
1022
+ content: [
1023
+ { type: "text", text: this.curSummary, id: crypto.randomUUID() }
1024
+ ],
1025
+ role: "user"
1026
+ })
1027
+ ] : [],
1028
+ ...this.context
1029
+ ],
1030
+ tools,
1031
+ toolChoice: options.toolChoice
1032
+ });
1033
+ let blockIds = {
1034
+ textBlockId: null,
1035
+ thinkingBlockId: null,
1036
+ toolCallIds: []
1037
+ };
1038
+ let completedResponse;
1039
+ if (this.model.stream) {
1040
+ while (true) {
1041
+ const { value, done } = await res.next();
1042
+ if (done) {
1043
+ completedResponse = value;
1044
+ break;
1045
+ }
1046
+ const chunk = value;
1047
+ yield* this.convertChatResponseToEvent(blockIds, chunk);
1048
+ }
1049
+ } else {
1050
+ completedResponse = res;
1051
+ yield* this.convertChatResponseToEvent(blockIds, res);
1052
+ }
1053
+ if (blockIds.textBlockId) {
1054
+ yield {
1055
+ id: crypto.randomUUID(),
1056
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1057
+ type: "TEXT_BLOCK_END" /* TEXT_BLOCK_END */,
1058
+ replyId: this.replyId,
1059
+ blockId: blockIds.textBlockId
1060
+ };
1061
+ }
1062
+ if (blockIds.thinkingBlockId) {
1063
+ yield {
1064
+ id: crypto.randomUUID(),
1065
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1066
+ type: "THINKING_BLOCK_END" /* THINKING_BLOCK_END */,
1067
+ replyId: this.replyId,
1068
+ blockId: blockIds.thinkingBlockId
1069
+ };
1070
+ }
1071
+ if (blockIds.toolCallIds.length > 0) {
1072
+ for (const toolCallId of blockIds.toolCallIds) {
1073
+ yield {
1074
+ id: crypto.randomUUID(),
1075
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1076
+ type: "TOOL_CALL_END" /* TOOL_CALL_END */,
1077
+ replyId: this.replyId,
1078
+ toolCallId
1079
+ };
1080
+ }
1081
+ }
1082
+ yield {
1083
+ id: crypto.randomUUID(),
1084
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1085
+ type: "MODEL_CALL_ENDED" /* MODEL_CALL_ENDED */,
1086
+ replyId: this.replyId,
1087
+ inputTokens: completedResponse.usage?.inputTokens || 0,
1088
+ outputTokens: completedResponse.usage?.outputTokens || 0
1089
+ };
1090
+ return completedResponse;
1091
+ }
1092
+ /**
1093
+ * Core acting logic without middlewares. Executes the given tool call, streams
1094
+ * intermediate tool result events, and saves the final tool response to memory.
1095
+ *
1096
+ * @param options - The acting options containing the tool call to execute.
1097
+ * @returns An async generator that yields tool result events.
1098
+ */
1099
+ async *_acting(options) {
1100
+ const res = this.toolkit.callToolFunction(options.toolCall);
1101
+ yield {
1102
+ type: "TOOL_RESULT_START" /* TOOL_RESULT_START */,
1103
+ id: crypto.randomUUID(),
1104
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1105
+ replyId: this.replyId,
1106
+ toolCallId: options.toolCall.id,
1107
+ toolCallName: options.toolCall.name
1108
+ };
1109
+ while (true) {
1110
+ const { value, done } = await res.next();
1111
+ if (done) {
1112
+ return {
1113
+ type: "tool_result",
1114
+ id: options.toolCall.id,
1115
+ name: options.toolCall.name,
1116
+ output: value.content,
1117
+ state: value.state
1118
+ };
1119
+ }
1120
+ yield* this.convertToolResponseToEvent(options.toolCall, value);
1121
+ }
1122
+ }
1123
+ /**
1124
+ * Receive external observation message(s) and save them into memory.
1125
+ *
1126
+ * @param options - The observe options containing the message to store.
1127
+ * @returns A promise that resolves when the message has been saved to memory.
1128
+ */
1129
+ async _observe(options) {
1130
+ await this.loadState();
1131
+ if (Array.isArray(options.msg)) {
1132
+ this.context.push(...options.msg);
1133
+ } else if (options.msg) {
1134
+ this.context.push(options.msg);
1135
+ }
1136
+ }
1137
+ /**
1138
+ * Convert a `ChatResponse` chunk into a sequence of typed agent events.
1139
+ * Tracks message IDs across calls via the mutable `responseId` object so that
1140
+ * start/content/end events are correctly correlated.
1141
+ *
1142
+ * @param responseId - Mutable object tracking IDs for the current text, thinking, and tool-call messages.
1143
+ * @param responseId.textMessageId - ID of the in-progress text message, or `null` if not yet started.
1144
+ * @param responseId.thinkingMessageId - ID of the in-progress thinking message, or `null` if not yet started.
1145
+ * @param responseId.textBlockId
1146
+ * @param responseId.thinkingBlockId
1147
+ * @param responseId.toolCallIds - List of tool-call IDs seen so far in this response.
1148
+ * @param chunk - The chat response chunk to convert.
1149
+ * @returns An async generator that yields the corresponding agent events.
1150
+ */
1151
+ async *convertChatResponseToEvent(responseId, chunk) {
1152
+ for (const block of chunk.content) {
1153
+ switch (block.type) {
1154
+ case "text":
1155
+ if (responseId.textBlockId === null) {
1156
+ responseId.textBlockId = crypto.randomUUID();
1157
+ yield {
1158
+ id: crypto.randomUUID(),
1159
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1160
+ type: "TEXT_BLOCK_START" /* TEXT_BLOCK_START */,
1161
+ replyId: this.replyId,
1162
+ blockId: responseId.textBlockId
1163
+ };
1164
+ }
1165
+ yield {
1166
+ id: crypto.randomUUID(),
1167
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1168
+ type: "TEXT_BLOCK_DELTA" /* TEXT_BLOCK_DELTA */,
1169
+ replyId: this.replyId,
1170
+ blockId: responseId.textBlockId,
1171
+ delta: block.text
1172
+ };
1173
+ break;
1174
+ case "thinking":
1175
+ if (responseId.thinkingBlockId === null) {
1176
+ responseId.thinkingBlockId = crypto.randomUUID();
1177
+ yield {
1178
+ id: crypto.randomUUID(),
1179
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1180
+ type: "THINKING_BLOCK_START" /* THINKING_BLOCK_START */,
1181
+ replyId: this.replyId,
1182
+ blockId: responseId.thinkingBlockId
1183
+ };
1184
+ }
1185
+ yield {
1186
+ id: crypto.randomUUID(),
1187
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1188
+ type: "THINKING_BLOCK_DELTA" /* THINKING_BLOCK_DELTA */,
1189
+ replyId: this.replyId,
1190
+ blockId: responseId.thinkingBlockId,
1191
+ delta: block.thinking
1192
+ };
1193
+ break;
1194
+ case "tool_call":
1195
+ if (!responseId.toolCallIds.includes(block.id)) {
1196
+ responseId.toolCallIds.push(block.id);
1197
+ yield {
1198
+ id: crypto.randomUUID(),
1199
+ type: "TOOL_CALL_START" /* TOOL_CALL_START */,
1200
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1201
+ replyId: this.replyId,
1202
+ toolCallId: block.id,
1203
+ toolCallName: block.name
1204
+ };
1205
+ }
1206
+ yield {
1207
+ id: crypto.randomUUID(),
1208
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1209
+ type: "TOOL_CALL_DELTA" /* TOOL_CALL_DELTA */,
1210
+ delta: block.input,
1211
+ replyId: this.replyId,
1212
+ toolCallId: block.id
1213
+ };
1214
+ }
1215
+ }
1216
+ }
1217
+ /**
1218
+ * Convert a `ToolResponse` into a sequence of typed agent events, followed by
1219
+ * a final `TOOL_RESULT_END` event.
1220
+ *
1221
+ * @param toolCall - The original tool-use block that triggered this response.
1222
+ * @param toolRes - The tool response containing result content blocks.
1223
+ * @returns An async generator that yields tool result events.
1224
+ */
1225
+ async *convertToolResponseToEvent(toolCall, toolRes) {
1226
+ for (const block of toolRes.content) {
1227
+ switch (block.type) {
1228
+ case "text":
1229
+ yield {
1230
+ id: crypto.randomUUID(),
1231
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1232
+ type: "TOOL_RESULT_TEXT_DELTA" /* TOOL_RESULT_TEXT_DELTA */,
1233
+ replyId: this.replyId,
1234
+ toolCallId: toolCall.id,
1235
+ delta: block.text
1236
+ };
1237
+ break;
1238
+ case "data":
1239
+ if (block.source.type === "base64") {
1240
+ yield {
1241
+ id: crypto.randomUUID(),
1242
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1243
+ type: "TOOL_RESULT_BINARY_DELTA" /* TOOL_RESULT_BINARY_DELTA */,
1244
+ replyId: this.replyId,
1245
+ toolCallId: toolCall.id,
1246
+ mediaType: block.source.mediaType,
1247
+ data: block.source.data
1248
+ };
1249
+ } else if (block.source.type === "url") {
1250
+ yield {
1251
+ id: crypto.randomUUID(),
1252
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1253
+ type: "TOOL_RESULT_BINARY_DELTA" /* TOOL_RESULT_BINARY_DELTA */,
1254
+ replyId: this.replyId,
1255
+ toolCallId: toolCall.id,
1256
+ mediaType: block.source.mediaType,
1257
+ url: block.source.url
1258
+ };
1259
+ }
1260
+ break;
1261
+ }
1262
+ }
1263
+ yield {
1264
+ id: crypto.randomUUID(),
1265
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1266
+ type: "TOOL_RESULT_END" /* TOOL_RESULT_END */,
1267
+ replyId: this.replyId,
1268
+ toolCallId: toolCall.id,
1269
+ state: toolRes.state
1270
+ };
1271
+ }
1272
+ /**
1273
+ * Convert the agent instance to a JSON-serializable object.
1274
+ * @returns An object containing the agent's name and system prompt.
1275
+ */
1276
+ async toJSON() {
1277
+ return {
1278
+ replyId: this.replyId,
1279
+ confirmedToolCallIds: this.confirmedToolCallIds,
1280
+ curIter: this.curIter
1281
+ };
1282
+ }
1283
+ /**
1284
+ * Split the current context into two parts: one part that needs to be compressed and another part that should be reserved based on the compression configuration. The method calculates how many recent "units" (blocks or tool call pairs) to keep uncompressed according to the `keepRecent` setting in the compression configuration, and ensures that tool calls and their corresponding results are not separated during the split.
1285
+ * @returns An object containing the `toCompressedContext` which includes the messages that need to be compressed, and the `reservedContext` which includes the recent messages that should be kept uncompressed.
1286
+ */
1287
+ _splitContextForCompression() {
1288
+ let toCompressedContext = [];
1289
+ let reservedContext = [];
1290
+ const keepRecent = this.compressionConfig.keepRecent ?? 0;
1291
+ const nBlocks = this.context.map((msg) => msg.content.length).reduce((a, b) => a + b, 0);
1292
+ const toCompressedBlockNumber = nBlocks - keepRecent > 0 ? nBlocks - keepRecent : 0;
1293
+ let currentCompressedBlocks = 0;
1294
+ for (const [index, msg] of this.context.entries()) {
1295
+ if (currentCompressedBlocks + msg.content.length <= toCompressedBlockNumber) {
1296
+ toCompressedContext.push(msg);
1297
+ currentCompressedBlocks += msg.content.length;
1298
+ } else {
1299
+ const reservedBlocks = msg.content.slice(
1300
+ toCompressedBlockNumber - currentCompressedBlocks
1301
+ );
1302
+ const unPairedToolResultIds = /* @__PURE__ */ new Set();
1303
+ for (const block of reservedBlocks) {
1304
+ if (block.type == "tool_call") {
1305
+ unPairedToolResultIds.add(block.id);
1306
+ } else if (block.type == "tool_result") {
1307
+ if (unPairedToolResultIds.has(block.id)) {
1308
+ unPairedToolResultIds.delete(block.id);
1309
+ }
1310
+ }
1311
+ }
1312
+ let i = toCompressedBlockNumber - currentCompressedBlocks - 1;
1313
+ for (; i >= 0; i--) {
1314
+ const block = msg.content[i];
1315
+ if (block.type === "tool_call" && unPairedToolResultIds.has(block.id)) {
1316
+ unPairedToolResultIds.delete(block.id);
1317
+ }
1318
+ if (unPairedToolResultIds.size === 0) break;
1319
+ }
1320
+ if (i <= 0) {
1321
+ reservedContext.push(msg);
1322
+ break;
1323
+ }
1324
+ const lastMsg = { ...msg };
1325
+ lastMsg.content = msg.content.slice(0, i);
1326
+ toCompressedContext.push(lastMsg);
1327
+ const reservedMsg = { ...msg };
1328
+ reservedMsg.content = msg.content.slice(i);
1329
+ reservedContext.push(reservedMsg);
1330
+ reservedContext.push(...this.context.slice(index + 1));
1331
+ break;
1332
+ }
1333
+ }
1334
+ return { toCompressedContext, reservedContext };
1335
+ }
1336
+ /**
1337
+ * Compress the agent's memory using the specified compression model (if provided) or the original model.
1338
+ */
1339
+ async compressMemoryIfNeeded() {
1340
+ if (!this.compressionConfig || !this.compressionConfig.enabled) return;
1341
+ const { toCompressedContext, reservedContext } = this._splitContextForCompression();
1342
+ if (toCompressedContext.length <= 0 || toCompressedContext.length === 1 && toCompressedContext.at(0)?.content.length === 1)
1343
+ return;
1344
+ const messages = [
1345
+ createMsg({
1346
+ name: "system",
1347
+ content: [{ type: "text", text: this.sysPrompt, id: crypto.randomUUID() }],
1348
+ role: "system"
1349
+ }),
1350
+ ...toCompressedContext,
1351
+ // instructions to compress the context into a summary
1352
+ createMsg({
1353
+ name: "user",
1354
+ content: [
1355
+ {
1356
+ id: crypto.randomUUID(),
1357
+ type: "text",
1358
+ text: this.compressionConfig.compressionPrompt || DEFAULT_COMPRESSION_PROMPT
1359
+ }
1360
+ ],
1361
+ role: "user"
1362
+ })
1363
+ ];
1364
+ const nTokens = await this.model.countTokens({
1365
+ messages,
1366
+ tools: this.toolkit.getJSONSchemas()
1367
+ });
1368
+ console.debug(`[AGENT ${this.name}] Current context token count: ${nTokens}.`);
1369
+ if (nTokens <= this.compressionConfig.triggerThreshold) return;
1370
+ console.log(
1371
+ `[AGENT ${this.name}] Compressing memory with ${toCompressedContext.length} messages.`
1372
+ );
1373
+ const res = await this.model.callStructured({
1374
+ messages: [
1375
+ createMsg({
1376
+ name: "system",
1377
+ content: [{ type: "text", text: this.sysPrompt, id: crypto.randomUUID() }],
1378
+ role: "system"
1379
+ }),
1380
+ ...toCompressedContext,
1381
+ // instructions to compress the context into a summary
1382
+ createMsg({
1383
+ name: "user",
1384
+ content: [
1385
+ {
1386
+ id: crypto.randomUUID(),
1387
+ type: "text",
1388
+ text: this.compressionConfig.compressionPrompt || DEFAULT_COMPRESSION_PROMPT
1389
+ }
1390
+ ],
1391
+ role: "user"
1392
+ })
1393
+ ],
1394
+ schema: this.compressionConfig.summarySchema || DEFAULT_SUMMARY_SCHEMA
1395
+ });
1396
+ let summaryText = "<system-reminder>Here is a summary of your previous work\n";
1397
+ for (const [key, value] of Object.entries(res.content)) {
1398
+ summaryText += `# ${key}
1399
+ ${value}
1400
+ `;
1401
+ }
1402
+ summaryText += "</system-reminder>";
1403
+ console.debug(`[AGENT ${this.name}] Compression summary: ${summaryText}`);
1404
+ this.context = reservedContext;
1405
+ this.curSummary = summaryText;
1406
+ }
1407
+ };
1408
+ // Annotate the CommonJS export names for ESM import in node:
1409
+ 0 && (module.exports = {
1410
+ Agent
1411
+ });
1412
+ //# sourceMappingURL=index.js.map