@aigne/core 1.63.0-beta.2 → 1.63.0-beta.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.63.0-beta.3](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.63.0-beta.2...core-v1.63.0-beta.3) (2025-10-11)
4
+
5
+
6
+ ### Features
7
+
8
+ * **afs:** add module system fs for afs ([#594](https://github.com/AIGNE-io/aigne-framework/issues/594)) ([83c7b65](https://github.com/AIGNE-io/aigne-framework/commit/83c7b6555d21c606a5005eb05f6686882fb8ffa3))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @aigne/afs bumped to 1.1.0-beta
16
+ * @aigne/observability-api bumped to 0.11.2-beta.1
17
+
3
18
  ## [1.63.0-beta.2](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.63.0-beta.1...core-v1.63.0-beta.2) (2025-10-09)
4
19
 
5
20
 
@@ -1,3 +1,4 @@
1
+ import type { AFSOptions } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
3
  import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
@@ -19,6 +20,10 @@ export type NestAgentSchema = string | {
19
20
  defaultInput?: Record<string, any>;
20
21
  hooks?: HooksSchema | HooksSchema[];
21
22
  } | AgentSchema;
23
+ export type AFSModuleSchema = string | {
24
+ module: string;
25
+ options?: Record<string, any>;
26
+ };
22
27
  export interface BaseAgentSchema {
23
28
  name?: string;
24
29
  description?: string;
@@ -36,6 +41,9 @@ export interface BaseAgentSchema {
36
41
  provider: string;
37
42
  subscribeTopic?: string[];
38
43
  };
44
+ afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
+ modules?: AFSModuleSchema[];
46
+ });
39
47
  }
40
48
  export type Instructions = {
41
49
  role: Exclude<Role, "tool">;
@@ -53,6 +53,21 @@ async function parseAgentFile(path, data) {
53
53
  subscribeTopic: (0, schema_js_1.optionalize)(zod_1.z.array(zod_1.z.string())),
54
54
  })),
55
55
  ])),
56
+ afs: (0, schema_js_1.optionalize)(zod_1.z.union([
57
+ zod_1.z.boolean(),
58
+ (0, schema_js_1.camelizeSchema)(zod_1.z.object({
59
+ storage: (0, schema_js_1.optionalize)(zod_1.z.object({
60
+ url: (0, schema_js_1.optionalize)(zod_1.z.string()),
61
+ })),
62
+ modules: (0, schema_js_1.optionalize)(zod_1.z.array(zod_1.z.union([
63
+ zod_1.z.string(),
64
+ zod_1.z.object({
65
+ module: zod_1.z.string(),
66
+ options: (0, schema_js_1.optionalize)(zod_1.z.record(zod_1.z.any())),
67
+ }),
68
+ ]))),
69
+ })),
70
+ ])),
56
71
  });
57
72
  const instructionItemSchema = zod_1.z.union([
58
73
  zod_1.z.object({
@@ -1,3 +1,4 @@
1
+ import { type AFSModule } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
3
  import { Agent, type AgentOptions } from "../agents/agent.js";
3
4
  import type { ChatModel } from "../agents/chat-model.js";
@@ -11,6 +12,12 @@ export interface LoadOptions {
11
12
  }[];
12
13
  model?: ChatModel | ((model?: z.infer<typeof aigneFileSchema>["model"]) => PromiseOrValue<ChatModel | undefined>);
13
14
  imageModel?: ImageModel | ((model?: z.infer<typeof aigneFileSchema>["imageModel"]) => PromiseOrValue<ImageModel | undefined>);
15
+ afs?: {
16
+ availableModules?: {
17
+ module: string;
18
+ create: (options?: Record<string, any>) => PromiseOrValue<AFSModule>;
19
+ }[];
20
+ };
14
21
  }
15
22
  export declare function load(path: string, options?: LoadOptions): Promise<AIGNEOptions>;
16
23
  export declare function loadAgent(path: string, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.load = load;
4
4
  exports.loadAgent = loadAgent;
5
5
  exports.loadAIGNEFile = loadAIGNEFile;
6
+ const afs_1 = require("@aigne/afs");
6
7
  const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
7
8
  const yaml_1 = require("yaml");
8
9
  const zod_1 = require("zod");
@@ -112,6 +113,26 @@ async function parseAgent(path, agent, options, agentOptions) {
112
113
  const memory = "memory" in agent && options?.memories?.length
113
114
  ? await loadMemory(options.memories, typeof agent.memory === "object" ? agent.memory.provider : undefined, typeof agent.memory === "object" ? agent.memory : {})
114
115
  : undefined;
116
+ let afs;
117
+ if (typeof agent.afs === "boolean") {
118
+ if (agent.afs) {
119
+ afs = new afs_1.AFS();
120
+ }
121
+ }
122
+ else if (agent.afs) {
123
+ afs = new afs_1.AFS({
124
+ ...agent.afs,
125
+ modules: agent.afs.modules &&
126
+ (await Promise.all(agent.afs.modules.map((m) => {
127
+ const mod = typeof m === "string"
128
+ ? options?.afs?.availableModules?.find((mod) => mod.module === m)
129
+ : options?.afs?.availableModules?.find((mod) => mod.module === m.module);
130
+ if (!mod)
131
+ throw new Error(`AFS module not found: ${typeof m === "string" ? m : m.module}`);
132
+ return mod.create(typeof m === "string" ? {} : m.options);
133
+ }))),
134
+ });
135
+ }
115
136
  const model = agent.model && typeof options?.model === "function"
116
137
  ? await options.model(agent.model)
117
138
  : undefined;
@@ -129,6 +150,7 @@ async function parseAgent(path, agent, options, agentOptions) {
129
150
  ...((await parseHooks(path, agent.hooks, options)) ?? []),
130
151
  ...[agentOptions?.hooks].flat().filter(type_utils_js_1.isNonNullable),
131
152
  ],
153
+ afs,
132
154
  };
133
155
  let instructions;
134
156
  if ("instructions" in agent && agent.instructions) {
@@ -12,8 +12,10 @@ const model_js_1 = require("../agents/model.js");
12
12
  const schema_js_1 = require("../loader/schema.js");
13
13
  const json_schema_js_1 = require("../utils/json-schema.js");
14
14
  const type_utils_js_1 = require("../utils/type-utils.js");
15
+ const afs_builtin_prompt_js_1 = require("./prompts/afs-builtin-prompt.js");
15
16
  const memory_message_template_js_1 = require("./prompts/memory-message-template.js");
16
17
  const structured_stream_instructions_js_1 = require("./prompts/structured-stream-instructions.js");
18
+ const afs_js_1 = require("./skills/afs.js");
17
19
  const template_js_1 = require("./template.js");
18
20
  class PromptBuilder {
19
21
  static from(instructions, { workingDir } = {}) {
@@ -70,7 +72,7 @@ class PromptBuilder {
70
72
  ? undefined
71
73
  : this.buildResponseFormat(options),
72
74
  outputFileType: options.agent?.outputFileType,
73
- ...this.buildTools(options),
75
+ ...(await this.buildTools(options)),
74
76
  };
75
77
  }
76
78
  async buildImagePrompt(options) {
@@ -101,7 +103,7 @@ class PromptBuilder {
101
103
  }
102
104
  if (options.agent?.afs) {
103
105
  const history = await options.agent.afs.list(afs_1.AFSHistory.Path, {
104
- limit: options.agent.maxRetrieveMemoryCount || 1,
106
+ limit: options.agent.maxRetrieveMemoryCount ?? 10,
105
107
  orderBy: [["createdAt", "desc"]],
106
108
  });
107
109
  if (message) {
@@ -110,6 +112,7 @@ class PromptBuilder {
110
112
  memories.push(...ms);
111
113
  }
112
114
  memories.push(...history.list.filter((i) => (0, type_utils_js_1.isNonNullable)(i.content)));
115
+ messages.push(template_js_1.SystemMessageTemplate.from(await (0, afs_builtin_prompt_js_1.getAFSSystemPrompt)(options.agent.afs)));
113
116
  }
114
117
  if (memories.length)
115
118
  messages.push(...(await this.convertMemoriesToMessages(memories, options)));
@@ -216,11 +219,14 @@ class PromptBuilder {
216
219
  }
217
220
  : undefined;
218
221
  }
219
- buildTools(options) {
222
+ async buildTools(options) {
220
223
  const toolAgents = (0, type_utils_js_1.unique)((options.context?.skills ?? [])
221
224
  .concat(options.agent?.skills ?? [])
222
225
  .concat(options.agent?.memoryAgentsAsTools ? options.agent.memories : [])
223
226
  .flatMap((i) => (i.isInvokable ? i : i.skills)), (i) => i.name);
227
+ if (options.agent?.afs) {
228
+ toolAgents.push(...(await (0, afs_js_1.getAFSSkills)(options.agent.afs)));
229
+ }
224
230
  const tools = toolAgents.map((i) => ({
225
231
  type: "function",
226
232
  function: {
@@ -0,0 +1,2 @@
1
+ import type { AFS } from "@aigne/afs";
2
+ export declare function getAFSSystemPrompt(afs: AFS): Promise<string>;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAFSSystemPrompt = getAFSSystemPrompt;
4
+ const yaml_1 = require("yaml");
5
+ async function getAFSSystemPrompt(afs) {
6
+ return `\
7
+
8
+ <afs_usage>
9
+ AFS (AIGNE File System) provides tools to interact with a virtual file system, allowing you to list, search, read, and write files. Use these tools to manage and retrieve files as needed.
10
+
11
+ Modules:
12
+ ${(0, yaml_1.stringify)(await afs.listModules())}
13
+
14
+ Available Tools:
15
+ 1. afs_list: Browse directory contents like filesystem ls/tree command - shows files and folders in a given path
16
+ 2. afs_search: Find files by content keywords - use specific keywords related to what you're looking for
17
+ 3. afs_read: Read file contents - path must be an exact file path from list or search results
18
+ 4. afs_write: Write content to a file in the AFS
19
+
20
+ Workflow: Use afs_list to browse directories, afs_search to find specific content, then afs_read to access file contents.
21
+ </afs_usage>
22
+ `;
23
+ }
@@ -0,0 +1,3 @@
1
+ import type { AFS } from "@aigne/afs";
2
+ import { type Agent } from "../../agents/agent.js";
3
+ export declare function getAFSSkills(afs: AFS): Promise<Agent[]>;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAFSSkills = getAFSSkills;
4
+ const zod_1 = require("zod");
5
+ const agent_js_1 = require("../../agents/agent.js");
6
+ async function getAFSSkills(afs) {
7
+ return [
8
+ agent_js_1.FunctionAgent.from({
9
+ name: "afs_list",
10
+ description: "Browse directory contents in the AFS like filesystem ls/tree command - shows files and folders in the specified path",
11
+ inputSchema: zod_1.z.object({
12
+ path: zod_1.z.string().describe("The directory path to browse (e.g., '/', '/docs', '/src')"),
13
+ options: zod_1.z
14
+ .object({
15
+ recursive: zod_1.z.boolean().optional().describe("Whether to list files recursively"),
16
+ maxDepth: zod_1.z.number().optional().describe("Maximum depth to list files"),
17
+ limit: zod_1.z.number().optional().describe("Maximum number of entries to return"),
18
+ })
19
+ .optional(),
20
+ }),
21
+ process: async (input) => {
22
+ return afs.list(input.path, input.options);
23
+ },
24
+ }),
25
+ agent_js_1.FunctionAgent.from({
26
+ name: "afs_search",
27
+ description: "Find files by searching content using keywords - returns matching files with their paths",
28
+ inputSchema: zod_1.z.object({
29
+ path: zod_1.z.string().describe("The directory path to search in (e.g., '/', '/docs')"),
30
+ query: zod_1.z
31
+ .string()
32
+ .describe("Keywords to search for in file contents (e.g., 'function authentication', 'database config')"),
33
+ options: zod_1.z
34
+ .object({
35
+ limit: zod_1.z.number().optional().describe("Maximum number of entries to return"),
36
+ })
37
+ .optional(),
38
+ }),
39
+ process: async (input) => {
40
+ return afs.search(input.path, input.query, input.options);
41
+ },
42
+ }),
43
+ agent_js_1.FunctionAgent.from({
44
+ name: "afs_read",
45
+ description: "Read file contents from the AFS - path must be an exact file path from list or search results",
46
+ inputSchema: zod_1.z.object({
47
+ path: zod_1.z
48
+ .string()
49
+ .describe("Exact file path from list or search results (e.g., '/docs/api.md', '/src/utils/helper.js')"),
50
+ }),
51
+ process: async (input) => {
52
+ const file = await afs.read(input.path);
53
+ return {
54
+ file,
55
+ };
56
+ },
57
+ }),
58
+ agent_js_1.FunctionAgent.from({
59
+ name: "afs_write",
60
+ description: "Create or update a file in the AFS with new content - overwrites existing files",
61
+ inputSchema: zod_1.z.object({
62
+ path: zod_1.z
63
+ .string()
64
+ .describe("Full file path where to write content (e.g., '/docs/new-file.md', '/src/component.js')"),
65
+ content: zod_1.z.string().describe("The text content to write to the file"),
66
+ }),
67
+ process: async (input) => {
68
+ const file = await afs.write(input.path, {
69
+ content: input.content,
70
+ });
71
+ return { file };
72
+ },
73
+ }),
74
+ ];
75
+ }
@@ -1,3 +1,4 @@
1
+ import type { AFSOptions } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
3
  import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
@@ -19,6 +20,10 @@ export type NestAgentSchema = string | {
19
20
  defaultInput?: Record<string, any>;
20
21
  hooks?: HooksSchema | HooksSchema[];
21
22
  } | AgentSchema;
23
+ export type AFSModuleSchema = string | {
24
+ module: string;
25
+ options?: Record<string, any>;
26
+ };
22
27
  export interface BaseAgentSchema {
23
28
  name?: string;
24
29
  description?: string;
@@ -36,6 +41,9 @@ export interface BaseAgentSchema {
36
41
  provider: string;
37
42
  subscribeTopic?: string[];
38
43
  };
44
+ afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
+ modules?: AFSModuleSchema[];
46
+ });
39
47
  }
40
48
  export type Instructions = {
41
49
  role: Exclude<Role, "tool">;
@@ -1,3 +1,4 @@
1
+ import { type AFSModule } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
3
  import { Agent, type AgentOptions } from "../agents/agent.js";
3
4
  import type { ChatModel } from "../agents/chat-model.js";
@@ -11,6 +12,12 @@ export interface LoadOptions {
11
12
  }[];
12
13
  model?: ChatModel | ((model?: z.infer<typeof aigneFileSchema>["model"]) => PromiseOrValue<ChatModel | undefined>);
13
14
  imageModel?: ImageModel | ((model?: z.infer<typeof aigneFileSchema>["imageModel"]) => PromiseOrValue<ImageModel | undefined>);
15
+ afs?: {
16
+ availableModules?: {
17
+ module: string;
18
+ create: (options?: Record<string, any>) => PromiseOrValue<AFSModule>;
19
+ }[];
20
+ };
14
21
  }
15
22
  export declare function load(path: string, options?: LoadOptions): Promise<AIGNEOptions>;
16
23
  export declare function loadAgent(path: string, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
@@ -0,0 +1,2 @@
1
+ import type { AFS } from "@aigne/afs";
2
+ export declare function getAFSSystemPrompt(afs: AFS): Promise<string>;
@@ -0,0 +1,3 @@
1
+ import type { AFS } from "@aigne/afs";
2
+ import { type Agent } from "../../agents/agent.js";
3
+ export declare function getAFSSkills(afs: AFS): Promise<Agent[]>;
@@ -1,3 +1,4 @@
1
+ import type { AFSOptions } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
3
  import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
@@ -19,6 +20,10 @@ export type NestAgentSchema = string | {
19
20
  defaultInput?: Record<string, any>;
20
21
  hooks?: HooksSchema | HooksSchema[];
21
22
  } | AgentSchema;
23
+ export type AFSModuleSchema = string | {
24
+ module: string;
25
+ options?: Record<string, any>;
26
+ };
22
27
  export interface BaseAgentSchema {
23
28
  name?: string;
24
29
  description?: string;
@@ -36,6 +41,9 @@ export interface BaseAgentSchema {
36
41
  provider: string;
37
42
  subscribeTopic?: string[];
38
43
  };
44
+ afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
+ modules?: AFSModuleSchema[];
46
+ });
39
47
  }
40
48
  export type Instructions = {
41
49
  role: Exclude<Role, "tool">;
@@ -49,6 +49,21 @@ export async function parseAgentFile(path, data) {
49
49
  subscribeTopic: optionalize(z.array(z.string())),
50
50
  })),
51
51
  ])),
52
+ afs: optionalize(z.union([
53
+ z.boolean(),
54
+ camelizeSchema(z.object({
55
+ storage: optionalize(z.object({
56
+ url: optionalize(z.string()),
57
+ })),
58
+ modules: optionalize(z.array(z.union([
59
+ z.string(),
60
+ z.object({
61
+ module: z.string(),
62
+ options: optionalize(z.record(z.any())),
63
+ }),
64
+ ]))),
65
+ })),
66
+ ])),
52
67
  });
53
68
  const instructionItemSchema = z.union([
54
69
  z.object({
@@ -1,3 +1,4 @@
1
+ import { type AFSModule } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
3
  import { Agent, type AgentOptions } from "../agents/agent.js";
3
4
  import type { ChatModel } from "../agents/chat-model.js";
@@ -11,6 +12,12 @@ export interface LoadOptions {
11
12
  }[];
12
13
  model?: ChatModel | ((model?: z.infer<typeof aigneFileSchema>["model"]) => PromiseOrValue<ChatModel | undefined>);
13
14
  imageModel?: ImageModel | ((model?: z.infer<typeof aigneFileSchema>["imageModel"]) => PromiseOrValue<ImageModel | undefined>);
15
+ afs?: {
16
+ availableModules?: {
17
+ module: string;
18
+ create: (options?: Record<string, any>) => PromiseOrValue<AFSModule>;
19
+ }[];
20
+ };
14
21
  }
15
22
  export declare function load(path: string, options?: LoadOptions): Promise<AIGNEOptions>;
16
23
  export declare function loadAgent(path: string, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
@@ -1,3 +1,4 @@
1
+ import { AFS } from "@aigne/afs";
1
2
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
2
3
  import { parse } from "yaml";
3
4
  import { z } from "zod";
@@ -107,6 +108,26 @@ async function parseAgent(path, agent, options, agentOptions) {
107
108
  const memory = "memory" in agent && options?.memories?.length
108
109
  ? await loadMemory(options.memories, typeof agent.memory === "object" ? agent.memory.provider : undefined, typeof agent.memory === "object" ? agent.memory : {})
109
110
  : undefined;
111
+ let afs;
112
+ if (typeof agent.afs === "boolean") {
113
+ if (agent.afs) {
114
+ afs = new AFS();
115
+ }
116
+ }
117
+ else if (agent.afs) {
118
+ afs = new AFS({
119
+ ...agent.afs,
120
+ modules: agent.afs.modules &&
121
+ (await Promise.all(agent.afs.modules.map((m) => {
122
+ const mod = typeof m === "string"
123
+ ? options?.afs?.availableModules?.find((mod) => mod.module === m)
124
+ : options?.afs?.availableModules?.find((mod) => mod.module === m.module);
125
+ if (!mod)
126
+ throw new Error(`AFS module not found: ${typeof m === "string" ? m : m.module}`);
127
+ return mod.create(typeof m === "string" ? {} : m.options);
128
+ }))),
129
+ });
130
+ }
110
131
  const model = agent.model && typeof options?.model === "function"
111
132
  ? await options.model(agent.model)
112
133
  : undefined;
@@ -124,6 +145,7 @@ async function parseAgent(path, agent, options, agentOptions) {
124
145
  ...((await parseHooks(path, agent.hooks, options)) ?? []),
125
146
  ...[agentOptions?.hooks].flat().filter(isNonNullable),
126
147
  ],
148
+ afs,
127
149
  };
128
150
  let instructions;
129
151
  if ("instructions" in agent && agent.instructions) {
@@ -9,8 +9,10 @@ import { fileUnionContentsSchema } from "../agents/model.js";
9
9
  import { optionalize } from "../loader/schema.js";
10
10
  import { outputSchemaToResponseFormatSchema } from "../utils/json-schema.js";
11
11
  import { checkArguments, flat, isNonNullable, isRecord, unique } from "../utils/type-utils.js";
12
+ import { getAFSSystemPrompt } from "./prompts/afs-builtin-prompt.js";
12
13
  import { MEMORY_MESSAGE_TEMPLATE } from "./prompts/memory-message-template.js";
13
14
  import { STRUCTURED_STREAM_INSTRUCTIONS } from "./prompts/structured-stream-instructions.js";
15
+ import { getAFSSkills } from "./skills/afs.js";
14
16
  import { AgentMessageTemplate, ChatMessagesTemplate, PromptTemplate, SystemMessageTemplate, UserMessageTemplate, } from "./template.js";
15
17
  export class PromptBuilder {
16
18
  static from(instructions, { workingDir } = {}) {
@@ -67,7 +69,7 @@ export class PromptBuilder {
67
69
  ? undefined
68
70
  : this.buildResponseFormat(options),
69
71
  outputFileType: options.agent?.outputFileType,
70
- ...this.buildTools(options),
72
+ ...(await this.buildTools(options)),
71
73
  };
72
74
  }
73
75
  async buildImagePrompt(options) {
@@ -98,7 +100,7 @@ export class PromptBuilder {
98
100
  }
99
101
  if (options.agent?.afs) {
100
102
  const history = await options.agent.afs.list(AFSHistory.Path, {
101
- limit: options.agent.maxRetrieveMemoryCount || 1,
103
+ limit: options.agent.maxRetrieveMemoryCount ?? 10,
102
104
  orderBy: [["createdAt", "desc"]],
103
105
  });
104
106
  if (message) {
@@ -107,6 +109,7 @@ export class PromptBuilder {
107
109
  memories.push(...ms);
108
110
  }
109
111
  memories.push(...history.list.filter((i) => isNonNullable(i.content)));
112
+ messages.push(SystemMessageTemplate.from(await getAFSSystemPrompt(options.agent.afs)));
110
113
  }
111
114
  if (memories.length)
112
115
  messages.push(...(await this.convertMemoriesToMessages(memories, options)));
@@ -213,11 +216,14 @@ export class PromptBuilder {
213
216
  }
214
217
  : undefined;
215
218
  }
216
- buildTools(options) {
219
+ async buildTools(options) {
217
220
  const toolAgents = unique((options.context?.skills ?? [])
218
221
  .concat(options.agent?.skills ?? [])
219
222
  .concat(options.agent?.memoryAgentsAsTools ? options.agent.memories : [])
220
223
  .flatMap((i) => (i.isInvokable ? i : i.skills)), (i) => i.name);
224
+ if (options.agent?.afs) {
225
+ toolAgents.push(...(await getAFSSkills(options.agent.afs)));
226
+ }
221
227
  const tools = toolAgents.map((i) => ({
222
228
  type: "function",
223
229
  function: {
@@ -0,0 +1,2 @@
1
+ import type { AFS } from "@aigne/afs";
2
+ export declare function getAFSSystemPrompt(afs: AFS): Promise<string>;
@@ -0,0 +1,20 @@
1
+ import { stringify } from "yaml";
2
+ export async function getAFSSystemPrompt(afs) {
3
+ return `\
4
+
5
+ <afs_usage>
6
+ AFS (AIGNE File System) provides tools to interact with a virtual file system, allowing you to list, search, read, and write files. Use these tools to manage and retrieve files as needed.
7
+
8
+ Modules:
9
+ ${stringify(await afs.listModules())}
10
+
11
+ Available Tools:
12
+ 1. afs_list: Browse directory contents like filesystem ls/tree command - shows files and folders in a given path
13
+ 2. afs_search: Find files by content keywords - use specific keywords related to what you're looking for
14
+ 3. afs_read: Read file contents - path must be an exact file path from list or search results
15
+ 4. afs_write: Write content to a file in the AFS
16
+
17
+ Workflow: Use afs_list to browse directories, afs_search to find specific content, then afs_read to access file contents.
18
+ </afs_usage>
19
+ `;
20
+ }
@@ -0,0 +1,3 @@
1
+ import type { AFS } from "@aigne/afs";
2
+ import { type Agent } from "../../agents/agent.js";
3
+ export declare function getAFSSkills(afs: AFS): Promise<Agent[]>;
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import { FunctionAgent } from "../../agents/agent.js";
3
+ export async function getAFSSkills(afs) {
4
+ return [
5
+ FunctionAgent.from({
6
+ name: "afs_list",
7
+ description: "Browse directory contents in the AFS like filesystem ls/tree command - shows files and folders in the specified path",
8
+ inputSchema: z.object({
9
+ path: z.string().describe("The directory path to browse (e.g., '/', '/docs', '/src')"),
10
+ options: z
11
+ .object({
12
+ recursive: z.boolean().optional().describe("Whether to list files recursively"),
13
+ maxDepth: z.number().optional().describe("Maximum depth to list files"),
14
+ limit: z.number().optional().describe("Maximum number of entries to return"),
15
+ })
16
+ .optional(),
17
+ }),
18
+ process: async (input) => {
19
+ return afs.list(input.path, input.options);
20
+ },
21
+ }),
22
+ FunctionAgent.from({
23
+ name: "afs_search",
24
+ description: "Find files by searching content using keywords - returns matching files with their paths",
25
+ inputSchema: z.object({
26
+ path: z.string().describe("The directory path to search in (e.g., '/', '/docs')"),
27
+ query: z
28
+ .string()
29
+ .describe("Keywords to search for in file contents (e.g., 'function authentication', 'database config')"),
30
+ options: z
31
+ .object({
32
+ limit: z.number().optional().describe("Maximum number of entries to return"),
33
+ })
34
+ .optional(),
35
+ }),
36
+ process: async (input) => {
37
+ return afs.search(input.path, input.query, input.options);
38
+ },
39
+ }),
40
+ FunctionAgent.from({
41
+ name: "afs_read",
42
+ description: "Read file contents from the AFS - path must be an exact file path from list or search results",
43
+ inputSchema: z.object({
44
+ path: z
45
+ .string()
46
+ .describe("Exact file path from list or search results (e.g., '/docs/api.md', '/src/utils/helper.js')"),
47
+ }),
48
+ process: async (input) => {
49
+ const file = await afs.read(input.path);
50
+ return {
51
+ file,
52
+ };
53
+ },
54
+ }),
55
+ FunctionAgent.from({
56
+ name: "afs_write",
57
+ description: "Create or update a file in the AFS with new content - overwrites existing files",
58
+ inputSchema: z.object({
59
+ path: z
60
+ .string()
61
+ .describe("Full file path where to write content (e.g., '/docs/new-file.md', '/src/component.js')"),
62
+ content: z.string().describe("The text content to write to the file"),
63
+ }),
64
+ process: async (input) => {
65
+ const file = await afs.write(input.path, {
66
+ content: input.content,
67
+ });
68
+ return { file };
69
+ },
70
+ }),
71
+ ];
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.63.0-beta.2",
3
+ "version": "1.63.0-beta.3",
4
4
  "description": "The functional core of agentic AI",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -92,9 +92,9 @@
92
92
  "zod": "^3.25.67",
93
93
  "zod-from-json-schema": "^0.0.5",
94
94
  "zod-to-json-schema": "^3.24.6",
95
- "@aigne/afs": "^1.0.0",
95
+ "@aigne/observability-api": "^0.11.2-beta.1",
96
96
  "@aigne/platform-helpers": "^0.6.3",
97
- "@aigne/observability-api": "^0.11.2-beta"
97
+ "@aigne/afs": "^1.1.0-beta"
98
98
  },
99
99
  "devDependencies": {
100
100
  "@types/bun": "^1.2.22",