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

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,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.63.0-beta.4](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.63.0-beta.3...core-v1.63.0-beta.4) (2025-10-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * **afs:** add configurable history injection to AFS system ([#611](https://github.com/AIGNE-io/aigne-framework/issues/611)) ([689b5d7](https://github.com/AIGNE-io/aigne-framework/commit/689b5d76d8cc82f548e8be74e63f18e7a6216c31))
9
+
10
+ ## [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)
11
+
12
+
13
+ ### Features
14
+
15
+ * **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))
16
+
17
+
18
+ ### Dependencies
19
+
20
+ * The following workspace dependencies were updated
21
+ * dependencies
22
+ * @aigne/afs bumped to 1.1.0-beta
23
+ * @aigne/observability-api bumped to 0.11.2-beta.1
24
+
3
25
  ## [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
26
 
5
27
 
@@ -122,6 +122,7 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
122
122
  */
123
123
  memory?: MemoryAgent | MemoryAgent[];
124
124
  afs?: true | AFSOptions | AFS | ((afs: AFS) => AFS);
125
+ afsConfig?: AFSConfig;
125
126
  asyncMemoryRecord?: boolean;
126
127
  /**
127
128
  * Maximum number of memory items to retrieve
@@ -130,6 +131,10 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
130
131
  hooks?: AgentHooks<I, O> | AgentHooks<I, O>[];
131
132
  retryOnError?: Agent<I, O>["retryOnError"] | boolean;
132
133
  }
134
+ export interface AFSConfig {
135
+ injectHistory?: boolean;
136
+ historyWindowSize?: number;
137
+ }
133
138
  export declare const agentOptionsSchema: ZodObject<{
134
139
  [key in keyof AgentOptions]: ZodType<AgentOptions[key]>;
135
140
  }>;
@@ -212,6 +217,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
212
217
  */
213
218
  readonly memories: MemoryAgent[];
214
219
  afs?: AFS;
220
+ afsConfig?: AFSConfig;
215
221
  asyncMemoryRecord?: boolean;
216
222
  tag?: string;
217
223
  /**
@@ -161,6 +161,7 @@ class Agent {
161
161
  : options.afs instanceof afs_1.AFS
162
162
  ? options.afs
163
163
  : new afs_1.AFS(options.afs);
164
+ this.afsConfig = options.afsConfig;
164
165
  this.asyncMemoryRecord = options.asyncMemoryRecord;
165
166
  this.maxRetrieveMemoryCount = options.maxRetrieveMemoryCount;
166
167
  this.hooks = (0, type_utils_js_1.flat)(options.hooks);
@@ -179,6 +180,7 @@ class Agent {
179
180
  */
180
181
  memories = [];
181
182
  afs;
183
+ afsConfig;
182
184
  asyncMemoryRecord;
183
185
  tag;
184
186
  /**
@@ -1,5 +1,6 @@
1
+ import type { AFSOptions } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
- import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
+ import type { AFSConfig, AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
4
5
  import { type Role } from "../agents/chat-model.js";
5
6
  import { ProcessMode, type ReflectionMode } from "../agents/team-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,10 @@ export interface BaseAgentSchema {
36
41
  provider: string;
37
42
  subscribeTopic?: string[];
38
43
  };
44
+ afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
+ modules?: AFSModuleSchema[];
46
+ });
47
+ afsConfig?: AFSConfig;
39
48
  }
40
49
  export type Instructions = {
41
50
  role: Exclude<Role, "tool">;
@@ -53,6 +53,25 @@ 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
+ ])),
71
+ afsConfig: (0, schema_js_1.optionalize)((0, schema_js_1.camelizeSchema)(zod_1.z.object({
72
+ injectHistory: (0, schema_js_1.optionalize)(zod_1.z.boolean()),
73
+ historyWindowSize: (0, schema_js_1.optionalize)(zod_1.z.number().int().min(1)),
74
+ }))),
56
75
  });
57
76
  const instructionItemSchema = zod_1.z.union([
58
77
  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) {
@@ -100,16 +102,19 @@ class PromptBuilder {
100
102
  memories.push(...options.context.memories);
101
103
  }
102
104
  if (options.agent?.afs) {
103
- const history = await options.agent.afs.list(afs_1.AFSHistory.Path, {
104
- limit: options.agent.maxRetrieveMemoryCount || 1,
105
- orderBy: [["createdAt", "desc"]],
106
- });
107
- if (message) {
108
- const result = await options.agent.afs.search("/", message);
109
- const ms = result.list.map((entry) => ({ content: (0, yaml_1.stringify)(entry.content) }));
110
- memories.push(...ms);
105
+ messages.push(template_js_1.SystemMessageTemplate.from(await (0, afs_builtin_prompt_js_1.getAFSSystemPrompt)(options.agent.afs)));
106
+ if (options.agent.afsConfig?.injectHistory) {
107
+ const history = await options.agent.afs.list(afs_1.AFSHistory.Path, {
108
+ limit: options.agent.afsConfig.historyWindowSize || 10,
109
+ orderBy: [["createdAt", "desc"]],
110
+ });
111
+ if (message) {
112
+ const result = await options.agent.afs.search("/", message);
113
+ const ms = result.list.map((entry) => ({ content: (0, yaml_1.stringify)(entry.content) }));
114
+ memories.push(...ms);
115
+ }
116
+ memories.push(...history.list.filter((i) => (0, type_utils_js_1.isNonNullable)(i.content)));
111
117
  }
112
- memories.push(...history.list.filter((i) => (0, type_utils_js_1.isNonNullable)(i.content)));
113
118
  }
114
119
  if (memories.length)
115
120
  messages.push(...(await this.convertMemoriesToMessages(memories, options)));
@@ -216,11 +221,14 @@ class PromptBuilder {
216
221
  }
217
222
  : undefined;
218
223
  }
219
- buildTools(options) {
224
+ async buildTools(options) {
220
225
  const toolAgents = (0, type_utils_js_1.unique)((options.context?.skills ?? [])
221
226
  .concat(options.agent?.skills ?? [])
222
227
  .concat(options.agent?.memoryAgentsAsTools ? options.agent.memories : [])
223
228
  .flatMap((i) => (i.isInvokable ? i : i.skills)), (i) => i.name);
229
+ if (options.agent?.afs) {
230
+ toolAgents.push(...(await (0, afs_js_1.getAFSSkills)(options.agent.afs)));
231
+ }
224
232
  const tools = toolAgents.map((i) => ({
225
233
  type: "function",
226
234
  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
+ }
@@ -122,6 +122,7 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
122
122
  */
123
123
  memory?: MemoryAgent | MemoryAgent[];
124
124
  afs?: true | AFSOptions | AFS | ((afs: AFS) => AFS);
125
+ afsConfig?: AFSConfig;
125
126
  asyncMemoryRecord?: boolean;
126
127
  /**
127
128
  * Maximum number of memory items to retrieve
@@ -130,6 +131,10 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
130
131
  hooks?: AgentHooks<I, O> | AgentHooks<I, O>[];
131
132
  retryOnError?: Agent<I, O>["retryOnError"] | boolean;
132
133
  }
134
+ export interface AFSConfig {
135
+ injectHistory?: boolean;
136
+ historyWindowSize?: number;
137
+ }
133
138
  export declare const agentOptionsSchema: ZodObject<{
134
139
  [key in keyof AgentOptions]: ZodType<AgentOptions[key]>;
135
140
  }>;
@@ -212,6 +217,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
212
217
  */
213
218
  readonly memories: MemoryAgent[];
214
219
  afs?: AFS;
220
+ afsConfig?: AFSConfig;
215
221
  asyncMemoryRecord?: boolean;
216
222
  tag?: string;
217
223
  /**
@@ -1,5 +1,6 @@
1
+ import type { AFSOptions } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
- import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
+ import type { AFSConfig, AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
4
5
  import { type Role } from "../agents/chat-model.js";
5
6
  import { ProcessMode, type ReflectionMode } from "../agents/team-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,10 @@ export interface BaseAgentSchema {
36
41
  provider: string;
37
42
  subscribeTopic?: string[];
38
43
  };
44
+ afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
+ modules?: AFSModuleSchema[];
46
+ });
47
+ afsConfig?: AFSConfig;
39
48
  }
40
49
  export type Instructions = {
41
50
  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[]>;
@@ -122,6 +122,7 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
122
122
  */
123
123
  memory?: MemoryAgent | MemoryAgent[];
124
124
  afs?: true | AFSOptions | AFS | ((afs: AFS) => AFS);
125
+ afsConfig?: AFSConfig;
125
126
  asyncMemoryRecord?: boolean;
126
127
  /**
127
128
  * Maximum number of memory items to retrieve
@@ -130,6 +131,10 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
130
131
  hooks?: AgentHooks<I, O> | AgentHooks<I, O>[];
131
132
  retryOnError?: Agent<I, O>["retryOnError"] | boolean;
132
133
  }
134
+ export interface AFSConfig {
135
+ injectHistory?: boolean;
136
+ historyWindowSize?: number;
137
+ }
133
138
  export declare const agentOptionsSchema: ZodObject<{
134
139
  [key in keyof AgentOptions]: ZodType<AgentOptions[key]>;
135
140
  }>;
@@ -212,6 +217,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
212
217
  */
213
218
  readonly memories: MemoryAgent[];
214
219
  afs?: AFS;
220
+ afsConfig?: AFSConfig;
215
221
  asyncMemoryRecord?: boolean;
216
222
  tag?: string;
217
223
  /**
@@ -113,6 +113,7 @@ export class Agent {
113
113
  : options.afs instanceof AFS
114
114
  ? options.afs
115
115
  : new AFS(options.afs);
116
+ this.afsConfig = options.afsConfig;
116
117
  this.asyncMemoryRecord = options.asyncMemoryRecord;
117
118
  this.maxRetrieveMemoryCount = options.maxRetrieveMemoryCount;
118
119
  this.hooks = flat(options.hooks);
@@ -131,6 +132,7 @@ export class Agent {
131
132
  */
132
133
  memories = [];
133
134
  afs;
135
+ afsConfig;
134
136
  asyncMemoryRecord;
135
137
  tag;
136
138
  /**
@@ -1,5 +1,6 @@
1
+ import type { AFSOptions } from "@aigne/afs";
1
2
  import { type ZodType, z } from "zod";
2
- import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
+ import type { AFSConfig, AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
4
5
  import { type Role } from "../agents/chat-model.js";
5
6
  import { ProcessMode, type ReflectionMode } from "../agents/team-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,10 @@ export interface BaseAgentSchema {
36
41
  provider: string;
37
42
  subscribeTopic?: string[];
38
43
  };
44
+ afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
+ modules?: AFSModuleSchema[];
46
+ });
47
+ afsConfig?: AFSConfig;
39
48
  }
40
49
  export type Instructions = {
41
50
  role: Exclude<Role, "tool">;
@@ -49,6 +49,25 @@ 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
+ ])),
67
+ afsConfig: optionalize(camelizeSchema(z.object({
68
+ injectHistory: optionalize(z.boolean()),
69
+ historyWindowSize: optionalize(z.number().int().min(1)),
70
+ }))),
52
71
  });
53
72
  const instructionItemSchema = z.union([
54
73
  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) {
@@ -97,16 +99,19 @@ export class PromptBuilder {
97
99
  memories.push(...options.context.memories);
98
100
  }
99
101
  if (options.agent?.afs) {
100
- const history = await options.agent.afs.list(AFSHistory.Path, {
101
- limit: options.agent.maxRetrieveMemoryCount || 1,
102
- orderBy: [["createdAt", "desc"]],
103
- });
104
- if (message) {
105
- const result = await options.agent.afs.search("/", message);
106
- const ms = result.list.map((entry) => ({ content: stringify(entry.content) }));
107
- memories.push(...ms);
102
+ messages.push(SystemMessageTemplate.from(await getAFSSystemPrompt(options.agent.afs)));
103
+ if (options.agent.afsConfig?.injectHistory) {
104
+ const history = await options.agent.afs.list(AFSHistory.Path, {
105
+ limit: options.agent.afsConfig.historyWindowSize || 10,
106
+ orderBy: [["createdAt", "desc"]],
107
+ });
108
+ if (message) {
109
+ const result = await options.agent.afs.search("/", message);
110
+ const ms = result.list.map((entry) => ({ content: stringify(entry.content) }));
111
+ memories.push(...ms);
112
+ }
113
+ memories.push(...history.list.filter((i) => isNonNullable(i.content)));
108
114
  }
109
- memories.push(...history.list.filter((i) => isNonNullable(i.content)));
110
115
  }
111
116
  if (memories.length)
112
117
  messages.push(...(await this.convertMemoriesToMessages(memories, options)));
@@ -213,11 +218,14 @@ export class PromptBuilder {
213
218
  }
214
219
  : undefined;
215
220
  }
216
- buildTools(options) {
221
+ async buildTools(options) {
217
222
  const toolAgents = unique((options.context?.skills ?? [])
218
223
  .concat(options.agent?.skills ?? [])
219
224
  .concat(options.agent?.memoryAgentsAsTools ? options.agent.memories : [])
220
225
  .flatMap((i) => (i.isInvokable ? i : i.skills)), (i) => i.name);
226
+ if (options.agent?.afs) {
227
+ toolAgents.push(...(await getAFSSkills(options.agent.afs)));
228
+ }
221
229
  const tools = toolAgents.map((i) => ({
222
230
  type: "function",
223
231
  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.4",
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",
96
- "@aigne/platform-helpers": "^0.6.3",
97
- "@aigne/observability-api": "^0.11.2-beta"
95
+ "@aigne/afs": "^1.1.0-beta",
96
+ "@aigne/observability-api": "^0.11.2-beta.1",
97
+ "@aigne/platform-helpers": "^0.6.3"
98
98
  },
99
99
  "devDependencies": {
100
100
  "@types/bun": "^1.2.22",