@aigne/core 1.72.0-beta.2 → 1.72.0-beta.23

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 (175) hide show
  1. package/CHANGELOG.md +261 -0
  2. package/lib/cjs/agents/agent.d.ts +42 -11
  3. package/lib/cjs/agents/agent.js +34 -8
  4. package/lib/cjs/agents/ai-agent.d.ts +63 -4
  5. package/lib/cjs/agents/ai-agent.js +154 -20
  6. package/lib/cjs/agents/chat-model.d.ts +157 -0
  7. package/lib/cjs/agents/chat-model.js +71 -6
  8. package/lib/cjs/agents/image-agent.d.ts +17 -1
  9. package/lib/cjs/agents/image-agent.js +16 -0
  10. package/lib/cjs/agents/image-model.d.ts +12 -2
  11. package/lib/cjs/agents/image-model.js +1 -1
  12. package/lib/cjs/agents/mcp-agent.d.ts +17 -0
  13. package/lib/cjs/agents/mcp-agent.js +18 -0
  14. package/lib/cjs/agents/model.d.ts +3 -3
  15. package/lib/cjs/agents/model.js +2 -2
  16. package/lib/cjs/agents/team-agent.d.ts +55 -0
  17. package/lib/cjs/agents/team-agent.js +31 -0
  18. package/lib/cjs/agents/transform-agent.d.ts +12 -0
  19. package/lib/cjs/agents/transform-agent.js +13 -0
  20. package/lib/cjs/agents/video-model.d.ts +10 -0
  21. package/lib/cjs/agents/video-model.js +1 -1
  22. package/lib/cjs/aigne/context.js +1 -3
  23. package/lib/cjs/aigne/usage.d.ts +4 -0
  24. package/lib/cjs/aigne/usage.js +6 -0
  25. package/lib/cjs/index.d.ts +1 -0
  26. package/lib/cjs/index.js +1 -0
  27. package/lib/cjs/loader/agent-yaml.d.ts +5 -63
  28. package/lib/cjs/loader/agent-yaml.js +4 -129
  29. package/lib/cjs/loader/agents.d.ts +4 -0
  30. package/lib/cjs/loader/agents.js +17 -0
  31. package/lib/cjs/loader/index.d.ts +16 -12
  32. package/lib/cjs/loader/index.js +20 -81
  33. package/lib/cjs/loader/schema.d.ts +21 -6
  34. package/lib/cjs/loader/schema.js +60 -1
  35. package/lib/cjs/memory/recorder.d.ts +4 -4
  36. package/lib/cjs/memory/retriever.d.ts +4 -4
  37. package/lib/cjs/prompt/agent-session.d.ts +163 -0
  38. package/lib/cjs/prompt/agent-session.js +1008 -0
  39. package/lib/cjs/prompt/compact/compactor.d.ts +7 -0
  40. package/lib/cjs/prompt/compact/compactor.js +52 -0
  41. package/lib/cjs/prompt/compact/session-memory-extractor.d.ts +7 -0
  42. package/lib/cjs/prompt/compact/session-memory-extractor.js +143 -0
  43. package/lib/cjs/prompt/compact/types.d.ts +336 -0
  44. package/lib/cjs/prompt/compact/types.js +53 -0
  45. package/lib/cjs/prompt/compact/user-memory-extractor.d.ts +7 -0
  46. package/lib/cjs/prompt/compact/user-memory-extractor.js +124 -0
  47. package/lib/cjs/prompt/context/afs/history.d.ts +5 -1
  48. package/lib/cjs/prompt/context/afs/history.js +3 -2
  49. package/lib/cjs/prompt/context/afs/index.js +8 -1
  50. package/lib/cjs/prompt/prompt-builder.d.ts +11 -9
  51. package/lib/cjs/prompt/prompt-builder.js +79 -120
  52. package/lib/cjs/prompt/skills/afs/agent-skill/agent-skill.d.ts +19 -0
  53. package/lib/cjs/prompt/skills/afs/agent-skill/agent-skill.js +69 -0
  54. package/lib/cjs/prompt/skills/afs/agent-skill/skill-loader.d.ts +12 -0
  55. package/lib/cjs/prompt/skills/afs/agent-skill/skill-loader.js +50 -0
  56. package/lib/cjs/prompt/skills/afs/delete.js +15 -3
  57. package/lib/cjs/prompt/skills/afs/edit.d.ts +6 -9
  58. package/lib/cjs/prompt/skills/afs/edit.js +85 -59
  59. package/lib/cjs/prompt/skills/afs/exec.js +17 -6
  60. package/lib/cjs/prompt/skills/afs/index.js +4 -1
  61. package/lib/cjs/prompt/skills/afs/list.d.ts +2 -0
  62. package/lib/cjs/prompt/skills/afs/list.js +35 -11
  63. package/lib/cjs/prompt/skills/afs/read.d.ts +9 -3
  64. package/lib/cjs/prompt/skills/afs/read.js +67 -15
  65. package/lib/cjs/prompt/skills/afs/rename.js +18 -4
  66. package/lib/cjs/prompt/skills/afs/search.js +21 -5
  67. package/lib/cjs/prompt/skills/afs/write.js +20 -6
  68. package/lib/cjs/prompt/template.d.ts +84 -9
  69. package/lib/cjs/prompt/template.js +46 -17
  70. package/lib/cjs/utils/mcp-utils.js +1 -1
  71. package/lib/cjs/utils/token-estimator.js +1 -1
  72. package/lib/dts/agents/agent.d.ts +42 -11
  73. package/lib/dts/agents/ai-agent.d.ts +63 -4
  74. package/lib/dts/agents/chat-model.d.ts +157 -0
  75. package/lib/dts/agents/image-agent.d.ts +17 -1
  76. package/lib/dts/agents/image-model.d.ts +12 -2
  77. package/lib/dts/agents/mcp-agent.d.ts +17 -0
  78. package/lib/dts/agents/model.d.ts +3 -3
  79. package/lib/dts/agents/team-agent.d.ts +55 -0
  80. package/lib/dts/agents/transform-agent.d.ts +12 -0
  81. package/lib/dts/agents/video-model.d.ts +10 -0
  82. package/lib/dts/aigne/context.d.ts +2 -2
  83. package/lib/dts/aigne/usage.d.ts +4 -0
  84. package/lib/dts/index.d.ts +1 -0
  85. package/lib/dts/loader/agent-yaml.d.ts +5 -63
  86. package/lib/dts/loader/agents.d.ts +4 -0
  87. package/lib/dts/loader/index.d.ts +16 -12
  88. package/lib/dts/loader/schema.d.ts +21 -6
  89. package/lib/dts/memory/recorder.d.ts +4 -4
  90. package/lib/dts/memory/retriever.d.ts +4 -4
  91. package/lib/dts/prompt/agent-session.d.ts +163 -0
  92. package/lib/dts/prompt/compact/compactor.d.ts +7 -0
  93. package/lib/dts/prompt/compact/session-memory-extractor.d.ts +7 -0
  94. package/lib/dts/prompt/compact/types.d.ts +336 -0
  95. package/lib/dts/prompt/compact/user-memory-extractor.d.ts +7 -0
  96. package/lib/dts/prompt/context/afs/history.d.ts +5 -1
  97. package/lib/dts/prompt/prompt-builder.d.ts +11 -9
  98. package/lib/dts/prompt/skills/afs/agent-skill/agent-skill.d.ts +19 -0
  99. package/lib/dts/prompt/skills/afs/agent-skill/skill-loader.d.ts +12 -0
  100. package/lib/dts/prompt/skills/afs/edit.d.ts +6 -9
  101. package/lib/dts/prompt/skills/afs/list.d.ts +2 -0
  102. package/lib/dts/prompt/skills/afs/read.d.ts +9 -3
  103. package/lib/dts/prompt/template.d.ts +84 -9
  104. package/lib/esm/agents/agent.d.ts +42 -11
  105. package/lib/esm/agents/agent.js +34 -8
  106. package/lib/esm/agents/ai-agent.d.ts +63 -4
  107. package/lib/esm/agents/ai-agent.js +154 -20
  108. package/lib/esm/agents/chat-model.d.ts +157 -0
  109. package/lib/esm/agents/chat-model.js +70 -5
  110. package/lib/esm/agents/image-agent.d.ts +17 -1
  111. package/lib/esm/agents/image-agent.js +16 -0
  112. package/lib/esm/agents/image-model.d.ts +12 -2
  113. package/lib/esm/agents/image-model.js +1 -1
  114. package/lib/esm/agents/mcp-agent.d.ts +17 -0
  115. package/lib/esm/agents/mcp-agent.js +18 -0
  116. package/lib/esm/agents/model.d.ts +3 -3
  117. package/lib/esm/agents/model.js +2 -2
  118. package/lib/esm/agents/team-agent.d.ts +55 -0
  119. package/lib/esm/agents/team-agent.js +31 -0
  120. package/lib/esm/agents/transform-agent.d.ts +12 -0
  121. package/lib/esm/agents/transform-agent.js +13 -0
  122. package/lib/esm/agents/video-model.d.ts +10 -0
  123. package/lib/esm/agents/video-model.js +1 -1
  124. package/lib/esm/aigne/context.d.ts +2 -2
  125. package/lib/esm/aigne/context.js +2 -4
  126. package/lib/esm/aigne/usage.d.ts +4 -0
  127. package/lib/esm/aigne/usage.js +6 -0
  128. package/lib/esm/index.d.ts +1 -0
  129. package/lib/esm/index.js +1 -0
  130. package/lib/esm/loader/agent-yaml.d.ts +5 -63
  131. package/lib/esm/loader/agent-yaml.js +4 -128
  132. package/lib/esm/loader/agents.d.ts +4 -0
  133. package/lib/esm/loader/agents.js +14 -0
  134. package/lib/esm/loader/index.d.ts +16 -12
  135. package/lib/esm/loader/index.js +21 -81
  136. package/lib/esm/loader/schema.d.ts +21 -6
  137. package/lib/esm/loader/schema.js +57 -0
  138. package/lib/esm/memory/recorder.d.ts +4 -4
  139. package/lib/esm/memory/retriever.d.ts +4 -4
  140. package/lib/esm/prompt/agent-session.d.ts +163 -0
  141. package/lib/esm/prompt/agent-session.js +968 -0
  142. package/lib/esm/prompt/compact/compactor.d.ts +7 -0
  143. package/lib/esm/prompt/compact/compactor.js +48 -0
  144. package/lib/esm/prompt/compact/session-memory-extractor.d.ts +7 -0
  145. package/lib/esm/prompt/compact/session-memory-extractor.js +139 -0
  146. package/lib/esm/prompt/compact/types.d.ts +336 -0
  147. package/lib/esm/prompt/compact/types.js +50 -0
  148. package/lib/esm/prompt/compact/user-memory-extractor.d.ts +7 -0
  149. package/lib/esm/prompt/compact/user-memory-extractor.js +120 -0
  150. package/lib/esm/prompt/context/afs/history.d.ts +5 -1
  151. package/lib/esm/prompt/context/afs/history.js +3 -2
  152. package/lib/esm/prompt/context/afs/index.js +8 -1
  153. package/lib/esm/prompt/prompt-builder.d.ts +11 -9
  154. package/lib/esm/prompt/prompt-builder.js +80 -121
  155. package/lib/esm/prompt/skills/afs/agent-skill/agent-skill.d.ts +19 -0
  156. package/lib/esm/prompt/skills/afs/agent-skill/agent-skill.js +65 -0
  157. package/lib/esm/prompt/skills/afs/agent-skill/skill-loader.d.ts +12 -0
  158. package/lib/esm/prompt/skills/afs/agent-skill/skill-loader.js +43 -0
  159. package/lib/esm/prompt/skills/afs/delete.js +15 -3
  160. package/lib/esm/prompt/skills/afs/edit.d.ts +6 -9
  161. package/lib/esm/prompt/skills/afs/edit.js +85 -59
  162. package/lib/esm/prompt/skills/afs/exec.js +17 -6
  163. package/lib/esm/prompt/skills/afs/index.js +4 -1
  164. package/lib/esm/prompt/skills/afs/list.d.ts +2 -0
  165. package/lib/esm/prompt/skills/afs/list.js +35 -11
  166. package/lib/esm/prompt/skills/afs/read.d.ts +9 -3
  167. package/lib/esm/prompt/skills/afs/read.js +67 -15
  168. package/lib/esm/prompt/skills/afs/rename.js +18 -4
  169. package/lib/esm/prompt/skills/afs/search.js +21 -5
  170. package/lib/esm/prompt/skills/afs/write.js +20 -6
  171. package/lib/esm/prompt/template.d.ts +84 -9
  172. package/lib/esm/prompt/template.js +46 -17
  173. package/lib/esm/utils/mcp-utils.js +1 -1
  174. package/lib/esm/utils/token-estimator.js +1 -1
  175. package/package.json +7 -6
@@ -7,15 +7,27 @@ class AFSDeleteAgent extends base_js_1.AFSSkillBase {
7
7
  constructor(options) {
8
8
  super({
9
9
  name: "afs_delete",
10
- description: "Permanently delete files or directories. Use when removing unwanted files or cleaning up temporary data.",
10
+ description: `Permanently delete files or directories from the Agentic File System (AFS)
11
+ - Removes files or directories at the specified AFS path
12
+ - Supports recursive deletion for directories with contents
13
+ - Use with caution as deletion is permanent
14
+
15
+ Usage:
16
+ - The path must be an absolute AFS path starting with "/" (e.g., "/docs/old-file.md", "/temp")
17
+ - This is NOT a local system file path - it operates within the AFS virtual file system
18
+ - To delete a directory, you MUST set recursive=true
19
+ - Deleting a non-empty directory without recursive=true will fail
20
+ - This operation cannot be undone`,
11
21
  ...options,
12
22
  inputSchema: zod_1.z.object({
13
- path: zod_1.z.string().describe("Absolute file or directory path to delete"),
23
+ path: zod_1.z
24
+ .string()
25
+ .describe("Absolute AFS path to delete (e.g., '/docs/old-file.md', '/temp'). Must start with '/'"),
14
26
  recursive: zod_1.z
15
27
  .boolean()
16
28
  .optional()
17
29
  .default(false)
18
- .describe("Allow directory deletion (default: false, required for directories)"),
30
+ .describe("MUST be set to true to delete directories. Default: false (files only)"),
19
31
  }),
20
32
  outputSchema: zod_1.z.object({
21
33
  status: zod_1.z.string(),
@@ -1,21 +1,17 @@
1
1
  import type { AgentInvokeOptions, AgentOptions, Message } from "../../../agents/agent.js";
2
2
  import { AFSSkillBase } from "./base.js";
3
- export interface Patch {
4
- start_line: number;
5
- end_line: number;
6
- replace?: string;
7
- delete: boolean;
8
- }
9
3
  export interface AFSEditInput extends Message {
10
4
  path: string;
11
- patches: Patch[];
5
+ oldString: string;
6
+ newString: string;
7
+ replaceAll?: boolean;
12
8
  }
13
9
  export interface AFSEditOutput extends Message {
14
10
  status: string;
15
11
  tool: string;
16
12
  path: string;
17
13
  message: string;
18
- data: string;
14
+ snippet: string;
19
15
  }
20
16
  export interface AFSEditAgentOptions extends AgentOptions<AFSEditInput, AFSEditOutput> {
21
17
  afs: NonNullable<AgentOptions<AFSEditInput, AFSEditOutput>["afs"]>;
@@ -23,5 +19,6 @@ export interface AFSEditAgentOptions extends AgentOptions<AFSEditInput, AFSEditO
23
19
  export declare class AFSEditAgent extends AFSSkillBase<AFSEditInput, AFSEditOutput> {
24
20
  constructor(options: AFSEditAgentOptions);
25
21
  process(input: AFSEditInput, _options: AgentInvokeOptions): Promise<AFSEditOutput>;
26
- applyCustomPatches(text: string, patches: Patch[]): string;
22
+ private countOccurrences;
23
+ private extractSnippet;
27
24
  }
@@ -3,96 +3,122 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AFSEditAgent = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const base_js_1 = require("./base.js");
6
+ const CONTEXT_LINES = 4; // Number of lines to show before and after the edit
6
7
  class AFSEditAgent extends base_js_1.AFSSkillBase {
7
8
  constructor(options) {
8
9
  super({
9
10
  name: "afs_edit",
10
- description: "Apply precise line-based patches to modify file content. Use when making targeted changes without rewriting the entire file.",
11
+ description: `Performs exact string replacements in files within the Agentic File System (AFS).
12
+
13
+ Usage:
14
+ - You must use afs_read at least once before editing to understand the file content
15
+ - The path must be an absolute AFS path starting with "/" (e.g., "/docs/readme.md")
16
+ - Preserve exact indentation (tabs/spaces) as it appears in the file
17
+ - The edit will FAIL if oldString is not found in the file
18
+ - The edit will FAIL if oldString appears multiple times (unless replaceAll is true)
19
+ - Use replaceAll to replace/rename strings across the entire file`,
11
20
  ...options,
12
21
  inputSchema: zod_1.z.object({
13
- path: zod_1.z.string().describe("Absolute file path to edit"),
14
- patches: zod_1.z
15
- .array(zod_1.z.object({
16
- start_line: zod_1.z.number().int().describe("Start line number (0-based, inclusive)"),
17
- end_line: zod_1.z.number().int().describe("End line number (0-based, exclusive)"),
18
- replace: zod_1.z.string().optional().describe("New content to replace the line range"),
19
- delete: zod_1.z.boolean().describe("Delete mode: true to delete lines, false to replace"),
20
- }))
21
- .min(1)
22
- .describe("List of patches to apply sequentially"),
22
+ path: zod_1.z
23
+ .string()
24
+ .describe("Absolute AFS path to the file to edit (e.g., '/docs/readme.md'). Must start with '/'"),
25
+ oldString: zod_1.z
26
+ .string()
27
+ .describe("The exact text to replace. Must match file content exactly including whitespace"),
28
+ newString: zod_1.z
29
+ .string()
30
+ .describe("The text to replace it with (must be different from oldString)"),
31
+ replaceAll: zod_1.z
32
+ .boolean()
33
+ .optional()
34
+ .default(false)
35
+ .describe("Replace all occurrences of oldString (default: false)"),
23
36
  }),
24
37
  outputSchema: zod_1.z.object({
25
38
  status: zod_1.z.string(),
26
39
  tool: zod_1.z.string(),
27
40
  path: zod_1.z.string(),
28
41
  message: zod_1.z.string(),
29
- data: zod_1.z.string(),
42
+ snippet: zod_1.z.string(),
30
43
  }),
31
44
  });
32
45
  }
33
46
  async process(input, _options) {
34
47
  if (!this.afs)
35
48
  throw new Error("AFS is not configured for this agent.");
36
- if (!input.patches?.length) {
37
- throw new Error("No patches provided for afs_edit.");
49
+ const { path, oldString, newString, replaceAll = false } = input;
50
+ if (oldString === newString) {
51
+ throw new Error("oldString and newString must be different");
38
52
  }
39
- const readResult = await this.afs.read(input.path);
53
+ const readResult = await this.afs.read(path);
40
54
  if (!readResult.data?.content || typeof readResult.data.content !== "string") {
41
- throw new Error(`Cannot read file content from: ${input.path}`);
55
+ throw new Error(`Cannot read file content from: ${path}`);
42
56
  }
43
57
  const originalContent = readResult.data.content;
44
- const updatedContent = this.applyCustomPatches(originalContent, input.patches);
45
- await this.afs.write(input.path, {
58
+ // Check if oldString exists in the file
59
+ const occurrences = this.countOccurrences(originalContent, oldString);
60
+ if (occurrences === 0) {
61
+ throw new Error(`oldString not found in file: ${path}`);
62
+ }
63
+ if (occurrences > 1 && !replaceAll) {
64
+ throw new Error(`oldString appears ${occurrences} times in file. Use replaceAll=true to replace all occurrences, or provide more context to make oldString unique.`);
65
+ }
66
+ // Find the position of the first occurrence for snippet extraction
67
+ const firstOccurrenceIndex = originalContent.indexOf(oldString);
68
+ // Perform the replacement
69
+ const updatedContent = replaceAll
70
+ ? originalContent.split(oldString).join(newString)
71
+ : originalContent.replace(oldString, newString);
72
+ await this.afs.write(path, {
46
73
  content: updatedContent,
47
74
  });
75
+ // Generate snippet around the edit location
76
+ const snippet = this.extractSnippet(updatedContent, firstOccurrenceIndex, newString.length);
77
+ const replacementCount = replaceAll ? occurrences : 1;
48
78
  return {
49
79
  status: "success",
50
80
  tool: "afs_edit",
51
- path: input.path,
52
- message: `Applied ${input.patches.length} patches to ${input.path}`,
53
- data: updatedContent,
81
+ path,
82
+ message: `Replaced ${replacementCount} occurrence${replacementCount > 1 ? "s" : ""} in ${path}`,
83
+ snippet,
54
84
  };
55
85
  }
56
- applyCustomPatches(text, patches) {
57
- // Sort by start_line to ensure sequential application
58
- const sorted = [...patches].sort((a, b) => a.start_line - b.start_line);
59
- const lines = text.split("\n");
60
- for (let i = 0; i < sorted.length; i++) {
61
- const patch = sorted[i];
62
- if (!patch)
63
- continue;
64
- const start = patch.start_line;
65
- const end = patch.end_line;
66
- const deleteCount = end - start; // [start, end) range
67
- let delta = 0;
68
- if (patch.delete) {
69
- // Delete mode: remove the specified lines [start, end)
70
- lines.splice(start, deleteCount);
71
- delta = -deleteCount;
72
- }
73
- else {
74
- // Replace mode: replace the specified lines with new content
75
- const replaceLines = patch.replace ? patch.replace.split("\n") : [];
76
- lines.splice(start, deleteCount, ...replaceLines);
77
- delta = replaceLines.length - deleteCount;
78
- }
79
- // Update subsequent patches' line numbers
80
- // For exclusive-end semantics [start, end), we adjust patches that start >= current patch's start_line
81
- // after the current patch has been applied
82
- if (delta !== 0) {
83
- for (let j = i + 1; j < sorted.length; j++) {
84
- const next = sorted[j];
85
- if (!next)
86
- continue;
87
- // Adjust patches that start at or after the current patch's end line
88
- if (next.start_line >= patch.end_line) {
89
- next.start_line += delta;
90
- next.end_line += delta;
91
- }
92
- }
86
+ countOccurrences(text, search) {
87
+ let count = 0;
88
+ let position = text.indexOf(search);
89
+ while (position !== -1) {
90
+ count++;
91
+ position = text.indexOf(search, position + search.length);
92
+ }
93
+ return count;
94
+ }
95
+ extractSnippet(content, editStartIndex, newStringLength) {
96
+ const lines = content.split("\n");
97
+ // Find the line number where the edit starts
98
+ let charCount = 0;
99
+ let editStartLine = 0;
100
+ for (let i = 0; i < lines.length; i++) {
101
+ const lineLength = (lines[i]?.length ?? 0) + 1; // +1 for newline
102
+ if (charCount + lineLength > editStartIndex) {
103
+ editStartLine = i;
104
+ break;
93
105
  }
106
+ charCount += lineLength;
94
107
  }
95
- return lines.join("\n");
108
+ // Calculate how many lines the new content spans
109
+ const newContentLines = content
110
+ .substring(editStartIndex, editStartIndex + newStringLength)
111
+ .split("\n").length;
112
+ const editEndLine = editStartLine + newContentLines - 1;
113
+ // Extract lines with context
114
+ const startLine = Math.max(0, editStartLine - CONTEXT_LINES);
115
+ const endLine = Math.min(lines.length - 1, editEndLine + CONTEXT_LINES);
116
+ // Format with line numbers (1-based)
117
+ const snippetLines = lines.slice(startLine, endLine + 1).map((line, idx) => {
118
+ const lineNum = startLine + idx + 1;
119
+ return `${String(lineNum).padStart(4)}| ${line}`;
120
+ });
121
+ return snippetLines.join("\n");
96
122
  }
97
123
  }
98
124
  exports.AFSEditAgent = AFSEditAgent;
@@ -7,14 +7,25 @@ class AFSExecAgent extends base_js_1.AFSSkillBase {
7
7
  constructor(options) {
8
8
  super({
9
9
  name: "afs_exec",
10
- description: `
11
- Execute files marked as executable in the Agentic File System (AFS).
12
- Use this to run executable files registered at a given path with specified arguments.
13
- `.trim(),
10
+ description: `Execute files marked as executable in the Agentic File System (AFS)
11
+ - Runs executable entries (functions, agents, skills) registered at a given AFS path
12
+ - Passes arguments to the executable and returns its output
13
+ - Use this to invoke dynamic functionality stored in AFS
14
+
15
+ Usage:
16
+ - The path must be an absolute AFS path to an executable entry (e.g., "/skills/summarize", "/agents/translator")
17
+ - This is NOT a local system file path - it operates within the AFS virtual file system
18
+ - Use afs_list to discover available executables (look for entries with execute metadata)
19
+ - Arguments must be a valid JSON string matching the executable's input schema
20
+ - The executable's input/output schema can be found in its metadata`,
14
21
  ...options,
15
22
  inputSchema: zod_1.z.object({
16
- path: zod_1.z.string().describe("Absolute path to the executable file in AFS"),
17
- args: zod_1.z.string().describe("JSON string of arguments matching the function's input schema"),
23
+ path: zod_1.z
24
+ .string()
25
+ .describe("Absolute AFS path to the executable (e.g., '/skills/summarize'). Must start with '/'"),
26
+ args: zod_1.z
27
+ .string()
28
+ .describe('JSON string of arguments matching the executable\'s input schema (e.g., \'{"text": "hello"}\')'),
18
29
  }),
19
30
  outputSchema: zod_1.z.object({
20
31
  data: zod_1.z.record(zod_1.z.any()),
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAFSSkills = getAFSSkills;
4
+ const type_utils_js_1 = require("../../../utils/type-utils.js");
5
+ const skill_loader_js_1 = require("./agent-skill/skill-loader.js");
4
6
  const delete_js_1 = require("./delete.js");
5
7
  const edit_js_1 = require("./edit.js");
6
8
  const exec_js_1 = require("./exec.js");
@@ -19,5 +21,6 @@ async function getAFSSkills(afs) {
19
21
  new delete_js_1.AFSDeleteAgent({ afs }),
20
22
  new rename_js_1.AFSRenameAgent({ afs }),
21
23
  new exec_js_1.AFSExecAgent({ afs }),
22
- ];
24
+ await (0, skill_loader_js_1.loadAgentSkillFromAFS)({ afs }),
25
+ ].filter(type_utils_js_1.isNonNullable);
23
26
  }
@@ -1,5 +1,6 @@
1
1
  import type { AFSListOptions } from "@aigne/afs";
2
2
  import type { AgentInvokeOptions, AgentOptions, Message } from "../../../agents/agent.js";
3
+ import type { PromiseOrValue } from "../../../utils/type-utils.js";
3
4
  import { AFSSkillBase } from "./base.js";
4
5
  export interface AFSListInput extends Message {
5
6
  path: string;
@@ -18,5 +19,6 @@ export interface AFSListAgentOptions extends AgentOptions<AFSListInput, AFSListO
18
19
  }
19
20
  export declare class AFSListAgent extends AFSSkillBase<AFSListInput, AFSListOutput> {
20
21
  constructor(options: AFSListAgentOptions);
22
+ formatOutput(output: AFSListOutput): PromiseOrValue<string>;
21
23
  process(input: AFSListInput, _options: AgentInvokeOptions): Promise<AFSListOutput>;
22
24
  }
@@ -7,26 +7,42 @@ class AFSListAgent extends base_js_1.AFSSkillBase {
7
7
  constructor(options) {
8
8
  super({
9
9
  name: "afs_list",
10
- description: "Browse directory structure as a tree view. Use when exploring directory contents or understanding file organization.",
10
+ description: `List contents within the Agentic File System (AFS)
11
+ - Returns files and directories at the specified AFS path
12
+ - Supports recursive listing with configurable depth
13
+ - Supports glob pattern filtering to match specific files
14
+ - By default respects .gitignore rules to filter out ignored files
15
+ - Use this tool when you need to explore AFS contents or understand file organization
16
+
17
+ Usage:
18
+ - The path must be an absolute AFS path starting with "/" (e.g., "/", "/docs", "/memory/user")
19
+ - This is NOT a local system file path - it operates within the AFS virtual file system
20
+ - Use maxDepth to control recursion depth (default: 1, current directory only)
21
+ - Use pattern to filter entries by glob pattern:
22
+ - "*.ts" - match TypeScript files in current directory
23
+ - "**/*.js" - match all JavaScript files recursively
24
+ - "src/**/*.{ts,tsx}" - match TypeScript files in src directory
25
+ - Results are filtered by .gitignore by default; set disableGitignore to include ignored files`,
11
26
  ...options,
12
27
  inputSchema: zod_1.z.object({
13
- path: zod_1.z.string().describe("Absolute directory path to browse"),
28
+ path: zod_1.z
29
+ .string()
30
+ .describe("Absolute AFS path to list (e.g., '/', '/docs', '/memory/user'). Must start with '/'"),
14
31
  options: zod_1.z
15
32
  .object({
16
- maxDepth: zod_1.z.number().optional().describe("Tree depth limit (default: 1)"),
33
+ maxDepth: zod_1.z
34
+ .number()
35
+ .optional()
36
+ .describe("Maximum depth of directory recursion. 1 = current directory only, 2 = include subdirectories, etc. Default: 1"),
17
37
  disableGitignore: zod_1.z
18
38
  .boolean()
19
39
  .optional()
20
- .describe("Disable .gitignore filtering, default is enabled"),
40
+ .describe("Set to true to include files normally ignored by .gitignore rules. Default: false (respects .gitignore)"),
21
41
  maxChildren: zod_1.z
22
42
  .number()
23
43
  .optional()
24
- .describe("Maximum number of children to list per directory"),
25
- format: zod_1.z
26
- .union([zod_1.z.literal("simple-list"), zod_1.z.literal("tree")])
27
- .optional()
28
- .default("simple-list")
29
- .describe("Output format, either 'simple-list', or 'tree', default is 'simple-list'"),
44
+ .describe("Maximum number of entries to return per directory. Useful for large directories to avoid overwhelming output"),
45
+ pattern: zod_1.z.string().optional().describe("Glob pattern to filter entries by path"),
30
46
  })
31
47
  .optional(),
32
48
  }),
@@ -40,10 +56,18 @@ class AFSListAgent extends base_js_1.AFSSkillBase {
40
56
  }),
41
57
  });
42
58
  }
59
+ formatOutput(output) {
60
+ if (typeof output.data === "string")
61
+ return output.data;
62
+ return super.formatOutput(output);
63
+ }
43
64
  async process(input, _options) {
44
65
  if (!this.afs)
45
66
  throw new Error("AFS is not configured for this agent.");
46
- const { data, message } = await this.afs.list(input.path, input.options);
67
+ const { data, message } = await this.afs.list(input.path, {
68
+ ...input.options,
69
+ format: "simple-list",
70
+ });
47
71
  return {
48
72
  status: "success",
49
73
  tool: "afs_list",
@@ -1,22 +1,28 @@
1
1
  import type { AFSEntry } from "@aigne/afs";
2
2
  import type { AgentInvokeOptions, AgentOptions, Message } from "../../../agents/agent.js";
3
+ import type { PromiseOrValue } from "../../../utils/type-utils.js";
3
4
  import { AFSSkillBase } from "./base.js";
4
5
  export interface AFSReadInput extends Message {
5
6
  path: string;
6
- withLineNumbers?: boolean;
7
+ offset?: number;
8
+ limit?: number;
7
9
  }
8
10
  export interface AFSReadOutput extends Message {
9
11
  status: string;
10
12
  tool: string;
11
13
  path: string;
12
- withLineNumbers?: boolean;
13
- data?: AFSEntry;
14
+ data?: AFSEntry | null;
14
15
  message?: string;
16
+ totalLines?: number;
17
+ returnedLines?: number;
18
+ truncated?: boolean;
19
+ offset?: number;
15
20
  }
16
21
  export interface AFSReadAgentOptions extends AgentOptions<AFSReadInput, AFSReadOutput> {
17
22
  afs: NonNullable<AgentOptions<AFSReadInput, AFSReadOutput>["afs"]>;
18
23
  }
19
24
  export declare class AFSReadAgent extends AFSSkillBase<AFSReadInput, AFSReadOutput> {
20
25
  constructor(options: AFSReadAgentOptions);
26
+ formatOutput(output: AFSReadOutput): PromiseOrValue<string>;
21
27
  process(input: AFSReadInput, _options: AgentInvokeOptions): Promise<AFSReadOutput>;
22
28
  }
@@ -3,49 +3,101 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AFSReadAgent = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const base_js_1 = require("./base.js");
6
+ const DEFAULT_LINE_LIMIT = 2000;
7
+ const MAX_LINE_LENGTH = 2000;
6
8
  class AFSReadAgent extends base_js_1.AFSSkillBase {
7
9
  constructor(options) {
8
10
  super({
9
11
  name: "afs_read",
10
- description: "Read complete file contents. Use when you need to review, analyze, or understand file content before making changes.",
12
+ description: `Read file contents from the Agentic File System (AFS)
13
+ - Returns the content of a file at the specified AFS path
14
+ - By default reads up to ${DEFAULT_LINE_LIMIT} lines, use offset/limit for large files
15
+ - Lines longer than ${MAX_LINE_LENGTH} characters will be truncated
16
+
17
+ Usage:
18
+ - The path must be an absolute AFS path starting with "/" (e.g., "/docs/readme.md")
19
+ - Use offset to start reading from a specific line (0-based)
20
+ - Use limit to control number of lines returned (default: ${DEFAULT_LINE_LIMIT})
21
+ - Check truncated field to know if file was partially returned`,
11
22
  ...options,
12
23
  inputSchema: zod_1.z.object({
13
- path: zod_1.z.string().describe("Absolute file path to read"),
14
- withLineNumbers: zod_1.z
15
- .boolean()
24
+ path: zod_1.z
25
+ .string()
26
+ .describe("Absolute AFS path to the file to read (e.g., '/docs/readme.md'). Must start with '/'"),
27
+ offset: zod_1.z
28
+ .number()
29
+ .int()
30
+ .min(0)
16
31
  .optional()
17
- .describe("Include line numbers in output (required when planning to edit the file)"),
32
+ .describe("Line number to start reading from (0-based, default: 0)"),
33
+ limit: zod_1.z
34
+ .number()
35
+ .int()
36
+ .min(1)
37
+ .max(DEFAULT_LINE_LIMIT)
38
+ .optional()
39
+ .describe(`Maximum number of lines to read (default: ${DEFAULT_LINE_LIMIT})`),
18
40
  }),
19
41
  outputSchema: zod_1.z.object({
20
42
  status: zod_1.z.string(),
21
43
  tool: zod_1.z.string(),
22
44
  path: zod_1.z.string(),
23
- withLineNumbers: zod_1.z.boolean().optional(),
24
45
  data: zod_1.z.custom().optional(),
25
46
  message: zod_1.z.string().optional(),
47
+ totalLines: zod_1.z.number().optional(),
48
+ returnedLines: zod_1.z.number().optional(),
49
+ truncated: zod_1.z.boolean().optional(),
50
+ offset: zod_1.z.number().optional(),
26
51
  }),
27
52
  });
28
53
  }
54
+ formatOutput(output) {
55
+ if (typeof output.data?.content === "string" && output.data.content)
56
+ return output.data.content;
57
+ return super.formatOutput({ ...output, data: output.data || null });
58
+ }
29
59
  async process(input, _options) {
30
60
  if (!this.afs)
31
61
  throw new Error("AFS is not configured for this agent.");
32
62
  const result = await this.afs.read(input.path);
33
- let content = result.data?.content;
34
- if (input.withLineNumbers && typeof content === "string") {
35
- content = content
36
- .split("\n")
37
- .map((line, idx) => `${idx + 1}| ${line}`)
38
- .join("\n");
63
+ if (!result.data?.content || typeof result.data.content !== "string") {
64
+ return {
65
+ status: "success",
66
+ tool: "afs_read",
67
+ path: input.path,
68
+ ...result,
69
+ };
70
+ }
71
+ const offset = input.offset ?? 0;
72
+ const limit = input.limit ?? DEFAULT_LINE_LIMIT;
73
+ const allLines = result.data.content.split("\n");
74
+ const totalLines = allLines.length;
75
+ // Apply offset and limit
76
+ const selectedLines = allLines.slice(offset, offset + limit);
77
+ // Truncate long lines
78
+ const processedLines = selectedLines.map((line) => line.length > MAX_LINE_LENGTH ? `${line.substring(0, MAX_LINE_LENGTH)}... [truncated]` : line);
79
+ const returnedLines = processedLines.length;
80
+ const truncated = offset > 0 || offset + limit < totalLines;
81
+ const processedContent = processedLines.join("\n");
82
+ let message;
83
+ if (truncated) {
84
+ const startLine = offset + 1;
85
+ const endLine = offset + returnedLines;
86
+ message = `Showing lines ${startLine}-${endLine} of ${totalLines}. Use offset/limit to read more.`;
39
87
  }
40
88
  return {
41
89
  status: "success",
42
90
  tool: "afs_read",
43
91
  path: input.path,
44
- withLineNumbers: input.withLineNumbers,
92
+ totalLines,
93
+ returnedLines,
94
+ truncated,
95
+ offset,
96
+ message,
45
97
  ...result,
46
- data: result.data && {
98
+ data: {
47
99
  ...result.data,
48
- content,
100
+ content: processedContent,
49
101
  },
50
102
  };
51
103
  }
@@ -7,16 +7,30 @@ class AFSRenameAgent extends base_js_1.AFSSkillBase {
7
7
  constructor(options) {
8
8
  super({
9
9
  name: "afs_rename",
10
- description: "Rename or move files and directories. Use when reorganizing files, changing names, or moving to different locations.",
10
+ description: `Rename or move files and directories within the Agentic File System (AFS)
11
+ - Renames a file or directory to a new name
12
+ - Can also move files/directories to a different location
13
+ - Optionally overwrites existing files at the destination
14
+
15
+ Usage:
16
+ - Both paths must be absolute AFS paths starting with "/" (e.g., "/docs/old-name.md" -> "/docs/new-name.md")
17
+ - This is NOT a local system file path - it operates within the AFS virtual file system
18
+ - To move a file, specify a different directory in newPath (e.g., "/docs/file.md" -> "/archive/file.md")
19
+ - If newPath already exists, the operation will fail unless overwrite=true
20
+ - Moving directories moves all contents recursively`,
11
21
  ...options,
12
22
  inputSchema: zod_1.z.object({
13
- oldPath: zod_1.z.string().describe("Absolute current file or directory path"),
14
- newPath: zod_1.z.string().describe("Absolute new file or directory path"),
23
+ oldPath: zod_1.z
24
+ .string()
25
+ .describe("Current absolute AFS path (e.g., '/docs/old-name.md'). Must start with '/'"),
26
+ newPath: zod_1.z
27
+ .string()
28
+ .describe("New absolute AFS path (e.g., '/docs/new-name.md'). Must start with '/'"),
15
29
  overwrite: zod_1.z
16
30
  .boolean()
17
31
  .optional()
18
32
  .default(false)
19
- .describe("Overwrite if destination exists (default: false)"),
33
+ .describe("Set to true to overwrite if destination already exists. Default: false (fails if exists)"),
20
34
  }),
21
35
  outputSchema: zod_1.z.object({
22
36
  status: zod_1.z.string(),
@@ -7,18 +7,34 @@ class AFSSearchAgent extends base_js_1.AFSSkillBase {
7
7
  constructor(options) {
8
8
  super({
9
9
  name: "afs_search",
10
- description: "Search file contents by keywords. Use when finding files containing specific text or code patterns.",
10
+ description: `Search file contents within the Agentic File System (AFS)
11
+ - Searches for files containing specific text, keywords, or patterns
12
+ - Returns matching entries with their content and metadata
13
+ - Supports case-sensitive and case-insensitive search modes
14
+ - Use this tool when you need to find files by their content
15
+
16
+ Usage:
17
+ - The path must be an absolute AFS path starting with "/" (e.g., "/", "/docs", "/memory")
18
+ - This is NOT a local system file path - it operates within the AFS virtual file system
19
+ - The query can be keywords, phrases, or text patterns to search for
20
+ - Use limit to control the number of results returned
21
+ - Search is case-insensitive by default; set caseSensitive to true for exact case matching`,
11
22
  ...options,
12
23
  inputSchema: zod_1.z.object({
13
- path: zod_1.z.string().describe("Absolute directory path to search in"),
14
- query: zod_1.z.string().describe("Search keywords or patterns"),
24
+ path: zod_1.z
25
+ .string()
26
+ .describe("Absolute AFS path to search in (e.g., '/', '/docs', '/memory'). Must start with '/'"),
27
+ query: zod_1.z.string().describe("Text, keywords, or patterns to search for in file contents"),
15
28
  options: zod_1.z
16
29
  .object({
17
- limit: zod_1.z.number().optional().describe("Max results to return"),
30
+ limit: zod_1.z
31
+ .number()
32
+ .optional()
33
+ .describe("Maximum number of results to return. Useful for limiting output size"),
18
34
  caseSensitive: zod_1.z
19
35
  .boolean()
20
36
  .optional()
21
- .describe("Case-sensitive search (default: false)"),
37
+ .describe("Set to true for case-sensitive matching. Default: false (case-insensitive)"),
22
38
  })
23
39
  .optional(),
24
40
  }),