@aigne/core 1.67.0 → 1.68.0

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,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.68.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.68.0-beta...core-v1.68.0) (2025-11-14)
4
+
5
+
6
+ ### Dependencies
7
+
8
+ * The following workspace dependencies were updated
9
+ * dependencies
10
+ * @aigne/afs bumped to 1.2.0
11
+ * @aigne/afs-history bumped to 1.0.1
12
+
13
+ ## [1.68.0-beta](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.67.0...core-v1.68.0-beta) (2025-11-14)
14
+
15
+
16
+ ### Features
17
+
18
+ * support mount mcp agent into AFS ([#740](https://github.com/AIGNE-io/aigne-framework/issues/740)) ([6d474fc](https://github.com/AIGNE-io/aigne-framework/commit/6d474fc05845a15e2c3e8fa97727b409bdd70945))
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * properly handle SIGINT to flush observability data before exit ([#739](https://github.com/AIGNE-io/aigne-framework/issues/739)) ([99b4503](https://github.com/AIGNE-io/aigne-framework/commit/99b45033d5f3bcc1f830b583f9cca7258b00606f))
24
+
25
+
26
+ ### Dependencies
27
+
28
+ * The following workspace dependencies were updated
29
+ * dependencies
30
+ * @aigne/afs bumped to 1.2.0-beta
31
+ * @aigne/afs-history bumped to 1.0.0
32
+
3
33
  ## [1.67.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.67.0-beta.4...core-v1.67.0) (2025-11-12)
4
34
 
5
35
 
@@ -1,4 +1,4 @@
1
- import { AFS, type AFSOptions } from "@aigne/afs";
1
+ import { AFS, type AFSEntry, type AFSListOptions, type AFSModule, type AFSOptions, type AFSSearchOptions } from "@aigne/afs";
2
2
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
3
3
  import type * as prompts from "@inquirer/prompts";
4
4
  import { type ZodObject, type ZodType } from "zod";
@@ -123,7 +123,6 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
123
123
  */
124
124
  memory?: MemoryAgent | MemoryAgent[];
125
125
  afs?: true | AFSOptions | AFS | ((afs: AFS) => AFS);
126
- afsConfig?: AFSConfig;
127
126
  asyncMemoryRecord?: boolean;
128
127
  /**
129
128
  * Maximum number of memory items to retrieve
@@ -132,10 +131,6 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
132
131
  hooks?: AgentHooks<I, O> | AgentHooks<I, O>[];
133
132
  retryOnError?: Agent<I, O>["retryOnError"] | boolean;
134
133
  }
135
- export interface AFSConfig {
136
- injectHistory?: boolean;
137
- historyWindowSize?: number;
138
- }
139
134
  export declare const agentOptionsSchema: ZodObject<{
140
135
  [key in keyof AgentOptions]: ZodType<AgentOptions[key]>;
141
136
  }>;
@@ -200,7 +195,7 @@ export interface AgentInvokeOptions<U extends UserContext = UserContext> {
200
195
  * Here's an example of how to create a custom agent:
201
196
  * {@includeCode ../../test/agents/agent.test.ts#example-custom-agent}
202
197
  */
203
- export declare abstract class Agent<I extends Message = any, O extends Message = any> {
198
+ export declare abstract class Agent<I extends Message = any, O extends Message = any> implements AFSModule {
204
199
  /**
205
200
  * Custom object inspection behavior
206
201
  *
@@ -218,7 +213,6 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
218
213
  */
219
214
  readonly memories: MemoryAgent[];
220
215
  afs?: AFS;
221
- afsConfig?: AFSConfig;
222
216
  asyncMemoryRecord?: boolean;
223
217
  tag?: string;
224
218
  /**
@@ -564,6 +558,26 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
564
558
  * {@includeCode ../../test/agents/agent.test.ts#example-agent-shutdown-by-using}
565
559
  */
566
560
  [Symbol.asyncDispose](): Promise<void>;
561
+ /** For AFSModule interface **/
562
+ private agentToAFSEntry;
563
+ private findAgentByAFSPath;
564
+ list(_path: string, _options?: AFSListOptions): Promise<{
565
+ list: AFSEntry[];
566
+ message?: string;
567
+ }>;
568
+ read(path: string): Promise<{
569
+ result?: AFSEntry;
570
+ message?: string;
571
+ }>;
572
+ search(path: string, _query: string, options?: AFSSearchOptions): Promise<{
573
+ list: AFSEntry[];
574
+ message?: string;
575
+ }>;
576
+ exec(path: string, args: Record<string, any>, options: {
577
+ context: Context;
578
+ }): Promise<{
579
+ result: Record<string, any>;
580
+ }>;
567
581
  }
568
582
  export type AgentInput<T extends Agent> = T extends Agent<infer I, any> ? I : never;
569
583
  export type AgentOutput<T extends Agent> = T extends Agent<any, infer O> ? O : never;
@@ -50,7 +50,9 @@ const afs_1 = require("@aigne/afs");
50
50
  const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
51
51
  const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
52
52
  const nunjucks_1 = __importDefault(require("nunjucks"));
53
+ const ufo_1 = require("ufo");
53
54
  const zod_1 = require("zod");
55
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
54
56
  const agent_utils_js_1 = require("../utils/agent-utils.js");
55
57
  const json_schema_js_1 = require("../utils/json-schema.js");
56
58
  const logger_js_1 = require("../utils/logger.js");
@@ -161,7 +163,6 @@ class Agent {
161
163
  : options.afs instanceof afs_1.AFS
162
164
  ? options.afs
163
165
  : new afs_1.AFS(options.afs);
164
- this.afsConfig = options.afsConfig;
165
166
  this.asyncMemoryRecord = options.asyncMemoryRecord;
166
167
  this.maxRetrieveMemoryCount = options.maxRetrieveMemoryCount;
167
168
  this.hooks = (0, type_utils_js_1.flat)(options.hooks);
@@ -180,7 +181,6 @@ class Agent {
180
181
  */
181
182
  memories = [];
182
183
  afs;
183
- afsConfig;
184
184
  asyncMemoryRecord;
185
185
  tag;
186
186
  /**
@@ -737,6 +737,59 @@ class Agent {
737
737
  async [Symbol.asyncDispose]() {
738
738
  await this.shutdown();
739
739
  }
740
+ /** For AFSModule interface **/
741
+ agentToAFSEntry(agent) {
742
+ return {
743
+ id: `/${this.name}/${agent.name}`,
744
+ path: agent === this ? "/" : (0, ufo_1.joinURL)("/", agent.name),
745
+ summary: agent.description,
746
+ metadata: {
747
+ execute: agent.isInvokable
748
+ ? {
749
+ name: agent.name,
750
+ description: agent.description,
751
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(agent.inputSchema),
752
+ outputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(agent.outputSchema),
753
+ }
754
+ : undefined,
755
+ },
756
+ };
757
+ }
758
+ findAgentByAFSPath(path) {
759
+ let agent;
760
+ if (path === "/") {
761
+ agent = this;
762
+ }
763
+ else {
764
+ const name = path.split("/")[1];
765
+ agent = this.skills.find((s) => s.name === name);
766
+ }
767
+ return agent;
768
+ }
769
+ // TODO: support list skills inside agent path, and use options to filter skills
770
+ async list(_path, _options) {
771
+ const agents = [this, ...this.skills];
772
+ return { list: agents.map((agent) => this.agentToAFSEntry(agent)) };
773
+ }
774
+ async read(path) {
775
+ const agent = this.findAgentByAFSPath(path);
776
+ if (!agent) {
777
+ return { message: `Agent not found at path: ${path}` };
778
+ }
779
+ return {
780
+ result: this.agentToAFSEntry(agent),
781
+ };
782
+ }
783
+ // TODO: implement search inside agent skills
784
+ async search(path, _query, options) {
785
+ return this.list(path, options);
786
+ }
787
+ async exec(path, args, options) {
788
+ const agent = this.findAgentByAFSPath(path);
789
+ if (!agent)
790
+ throw new Error(`Agent not found at path: ${path}`);
791
+ return { result: await options.context.invoke(agent, args) };
792
+ }
740
793
  }
741
794
  exports.Agent = Agent;
742
795
  /**
@@ -221,7 +221,7 @@ class AIGNE {
221
221
  * This registers handlers for SIGINT and exit events to properly terminate all agents.
222
222
  */
223
223
  initProcessExitHandler() {
224
- const shutdownAndExit = () => this.shutdown().finally(() => process.exit(0));
224
+ const shutdownAndExit = () => this.shutdown();
225
225
  process.on("SIGINT", shutdownAndExit);
226
226
  process.on("exit", shutdownAndExit);
227
227
  }
@@ -182,6 +182,7 @@ export declare class AIGNEContext implements Context {
182
182
  subscribe: Context["subscribe"];
183
183
  unsubscribe: Context["unsubscribe"];
184
184
  emit<K extends keyof ContextEmitEventMap>(eventName: K, ...args: Args<K, ContextEmitEventMap>): boolean;
185
+ initProcessExitHandler(): void;
185
186
  private trace;
186
187
  on<K extends keyof ContextEventMap>(eventName: K, listener: Listener<K, ContextEventMap>): this;
187
188
  once<K extends keyof ContextEventMap>(eventName: K, listener: Listener<K, ContextEventMap>): this;
@@ -46,6 +46,7 @@ class AIGNEContext {
46
46
  this.rootId = this.span?.spanContext?.().traceId ?? (0, uuid_1.v7)();
47
47
  }
48
48
  this.id = this.span?.spanContext()?.spanId ?? (0, uuid_1.v7)();
49
+ this.initProcessExitHandler();
49
50
  }
50
51
  id;
51
52
  parentId;
@@ -201,6 +202,23 @@ class AIGNEContext {
201
202
  this.trace(eventName, args, b);
202
203
  return this.internal.events.emit(eventName, ...newArgs);
203
204
  }
205
+ initProcessExitHandler() {
206
+ process.on("SIGINT", async () => {
207
+ try {
208
+ if (process.env.AIGNE_OBSERVABILITY_DISABLED)
209
+ return;
210
+ const span = this.span;
211
+ if (!span)
212
+ return;
213
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: "SIGINT" });
214
+ span.end();
215
+ await this.observer?.flush(span);
216
+ }
217
+ finally {
218
+ process.exit(0);
219
+ }
220
+ });
221
+ }
204
222
  async trace(eventName, args, b) {
205
223
  if (process.env.AIGNE_OBSERVABILITY_DISABLED)
206
224
  return;
@@ -1,6 +1,6 @@
1
1
  import type { AFSOptions } from "@aigne/afs";
2
2
  import { type ZodType, z } from "zod";
3
- import type { AFSConfig, AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
+ import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
4
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
5
5
  import { type Role } from "../agents/chat-model.js";
6
6
  import { ProcessMode, type ReflectionMode } from "../agents/team-agent.js";
@@ -44,7 +44,6 @@ export interface BaseAgentSchema {
44
44
  afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
45
  modules?: AFSModuleSchema[];
46
46
  });
47
- afsConfig?: AFSConfig;
48
47
  }
49
48
  export type Instructions = {
50
49
  role: Exclude<Role, "tool">;
@@ -57,22 +57,15 @@ async function parseAgentFile(path, data) {
57
57
  afs: (0, schema_js_1.optionalize)(zod_1.z.union([
58
58
  zod_1.z.boolean(),
59
59
  (0, schema_js_1.camelizeSchema)(zod_1.z.object({
60
- storage: (0, schema_js_1.optionalize)(zod_1.z.object({
61
- url: (0, schema_js_1.optionalize)(zod_1.z.string()),
62
- })),
63
60
  modules: (0, schema_js_1.optionalize)(zod_1.z.array(zod_1.z.union([
64
61
  zod_1.z.string(),
65
- zod_1.z.object({
62
+ (0, schema_js_1.camelizeSchema)(zod_1.z.object({
66
63
  module: zod_1.z.string(),
67
64
  options: (0, schema_js_1.optionalize)(zod_1.z.record(zod_1.z.any())),
68
- }),
65
+ })),
69
66
  ]))),
70
67
  })),
71
68
  ])),
72
- afsConfig: (0, schema_js_1.optionalize)((0, schema_js_1.camelizeSchema)(zod_1.z.object({
73
- injectHistory: (0, schema_js_1.optionalize)(zod_1.z.boolean()),
74
- historyWindowSize: (0, schema_js_1.optionalize)(zod_1.z.number().int().min(1)),
75
- }))),
76
69
  });
77
70
  const instructionItemSchema = zod_1.z.union([
78
71
  zod_1.z.object({
@@ -15,6 +15,7 @@ export interface LoadOptions {
15
15
  afs?: {
16
16
  availableModules?: {
17
17
  module: string;
18
+ alias?: string[];
18
19
  create: (options?: Record<string, any>) => PromiseOrValue<AFSModule>;
19
20
  }[];
20
21
  };
@@ -119,23 +119,19 @@ async function parseAgent(path, agent, options, agentOptions) {
119
119
  : undefined;
120
120
  let afs;
121
121
  if (typeof agent.afs === "boolean") {
122
- if (agent.afs) {
122
+ if (agent.afs)
123
123
  afs = new afs_1.AFS();
124
- }
125
124
  }
126
125
  else if (agent.afs) {
127
- afs = new afs_1.AFS({
128
- ...agent.afs,
129
- modules: agent.afs.modules &&
130
- (await Promise.all(agent.afs.modules.map((m) => {
131
- const mod = typeof m === "string"
132
- ? options?.afs?.availableModules?.find((mod) => mod.module === m)
133
- : options?.afs?.availableModules?.find((mod) => mod.module === m.module);
134
- if (!mod)
135
- throw new Error(`AFS module not found: ${typeof m === "string" ? m : m.module}`);
136
- return mod.create(typeof m === "string" ? {} : m.options);
137
- }))),
138
- });
126
+ afs = new afs_1.AFS();
127
+ for (const m of agent.afs.modules || []) {
128
+ const moduleName = typeof m === "string" ? m : m.module;
129
+ const mod = options?.afs?.availableModules?.find((mod) => mod.module === moduleName || mod.alias?.includes(moduleName));
130
+ if (!mod)
131
+ throw new Error(`AFS module not found: ${typeof m === "string" ? m : m.module}`);
132
+ const module = await mod.create(typeof m === "string" ? {} : m.options);
133
+ afs.mount(module);
134
+ }
139
135
  }
140
136
  const model = agent.model && typeof options?.model === "function"
141
137
  ? await options.model({ ...options.aigne?.model, ...(0, type_utils_js_1.omitBy)(agent.model, (v) => (0, type_utils_js_1.isNil)(v)) })
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PromptBuilder = void 0;
4
- const afs_1 = require("@aigne/afs");
4
+ const afs_history_1 = require("@aigne/afs-history");
5
5
  const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
6
6
  const yaml_1 = require("yaml");
7
7
  const zod_1 = require("zod");
@@ -113,21 +113,50 @@ class PromptBuilder {
113
113
  if (options.agent?.useMemoriesFromContext && options.context?.memories?.length) {
114
114
  memories.push(...options.context.memories);
115
115
  }
116
- if (options.agent?.afs) {
117
- messages.push(await template_js_1.SystemMessageTemplate.from(await (0, afs_builtin_prompt_js_1.getAFSSystemPrompt)(options.agent.afs)).format({}));
118
- if (options.agent.afsConfig?.injectHistory) {
119
- const history = await options.agent.afs.list(afs_1.AFSHistory.Path, {
120
- limit: options.agent.afsConfig.historyWindowSize || 10,
116
+ const afs = options.agent?.afs;
117
+ if (afs) {
118
+ const historyModule = (await afs.listModules()).find((m) => m.module instanceof afs_history_1.AFSHistory);
119
+ messages.push(await template_js_1.SystemMessageTemplate.from(await (0, afs_builtin_prompt_js_1.getAFSSystemPrompt)(afs)).format({}));
120
+ if (historyModule) {
121
+ const history = await afs.list(historyModule.path, {
122
+ limit: options.agent?.maxRetrieveMemoryCount || 10,
121
123
  orderBy: [["createdAt", "desc"]],
122
124
  });
123
- if (message) {
124
- const result = await options.agent.afs.search("/", message);
125
- const ms = result.list.map((entry) => ({ content: (0, yaml_1.stringify)(entry.content) }));
126
- memories.push(...ms);
127
- }
128
125
  memories.push(...history.list
129
126
  .reverse()
130
127
  .filter((i) => (0, type_utils_js_1.isNonNullable)(i.content)));
128
+ if (message) {
129
+ const result = await afs.search("/", message);
130
+ const ms = result.list
131
+ .map((entry) => {
132
+ if (entry.metadata?.execute)
133
+ return null;
134
+ const content = entry.content || entry.summary;
135
+ if (!content)
136
+ return null;
137
+ return {
138
+ content,
139
+ description: entry.description,
140
+ };
141
+ })
142
+ .filter(type_utils_js_1.isNonNullable);
143
+ memories.push(...ms);
144
+ const executable = result.list.filter((i) => !!i.metadata?.execute);
145
+ if (executable.length) {
146
+ messages.push({
147
+ role: "system",
148
+ content: await template_js_1.PromptTemplate.from(afs_builtin_prompt_js_1.AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE).format({
149
+ tools: executable.map((entry) => ({
150
+ path: entry.path,
151
+ name: entry.metadata.execute.name,
152
+ description: entry.metadata.execute.description,
153
+ inputSchema: entry.metadata.execute.inputSchema,
154
+ outputSchema: entry.metadata.execute.outputSchema,
155
+ })),
156
+ }),
157
+ });
158
+ }
159
+ }
131
160
  }
132
161
  }
133
162
  if (memories.length)
@@ -232,7 +261,8 @@ class PromptBuilder {
232
261
  result.push({ role: "agent", content: agentMessageContent });
233
262
  return result;
234
263
  };
235
- for (const { content } of memories) {
264
+ for (const memory of memories) {
265
+ const { content } = memory;
236
266
  if ((0, type_utils_js_1.isRecord)(content) &&
237
267
  "input" in content &&
238
268
  content.input &&
@@ -241,7 +271,7 @@ class PromptBuilder {
241
271
  messages.push(...(await convertMemoryToMessage(content)));
242
272
  }
243
273
  else {
244
- other.push(content);
274
+ other.push(memory);
245
275
  }
246
276
  }
247
277
  if (other.length) {
@@ -1,2 +1,3 @@
1
1
  import type { AFS } from "@aigne/afs";
2
2
  export declare function getAFSSystemPrompt(afs: AFS): Promise<string>;
3
+ export declare const AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE = "<afs_executable_tools>\nHere are the executable tools available in the AFS you can use:\n\n{{ tools | yaml.stringify }}\n</afs_executable_tools>\n";
@@ -1,23 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE = void 0;
3
4
  exports.getAFSSystemPrompt = getAFSSystemPrompt;
4
5
  const yaml_1 = require("yaml");
6
+ const type_utils_js_1 = require("../../utils/type-utils.js");
5
7
  async function getAFSSystemPrompt(afs) {
6
8
  return `\
7
9
 
8
10
  <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.
11
+ AFS (Agentic File System) provides tools to interact with a virtual file system,
12
+ allowing you to list, search, read, and write files, or execute a useful tool from the available modules.
13
+ Use these tools to manage and retrieve files as needed.
10
14
 
11
- Modules:
12
- ${(0, yaml_1.stringify)(await afs.listModules())}
15
+ Provided modules:
16
+ ${(0, yaml_1.stringify)((await afs.listModules()).map((i) => (0, type_utils_js_1.pick)(i, ["name", "path", "description"])))}
13
17
 
14
- Available Tools:
18
+ Global tools to interact with the AFS:
15
19
  1. afs_list: Browse directory contents like filesystem ls/tree command - shows files and folders in a given path
16
20
  2. afs_search: Find files by content keywords - use specific keywords related to what you're looking for
17
21
  3. afs_read: Read file contents - path must be an exact file path from list or search results
18
22
  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.
23
+ 5. afs_exec: Execute a executable tool from the available modules
21
24
  </afs_usage>
22
25
  `;
23
26
  }
27
+ exports.AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE = `\
28
+ <afs_executable_tools>
29
+ Here are the executable tools available in the AFS you can use:
30
+
31
+ {{ tools | yaml.stringify }}
32
+ </afs_executable_tools>
33
+ `;
@@ -92,5 +92,18 @@ async function getAFSSkills(afs) {
92
92
  };
93
93
  },
94
94
  }),
95
+ agent_js_1.FunctionAgent.from({
96
+ name: "afs_exec",
97
+ description: "Execute a function or command available in the AFS modules",
98
+ inputSchema: zod_1.z.object({
99
+ path: zod_1.z.string().describe("The exact path to the executable entry in AFS"),
100
+ args: zod_1.z
101
+ .string()
102
+ .describe("JSON stringified arguments to pass to the executable, must be an object matching the input schema of the executable"),
103
+ }),
104
+ process: async ({ path, args }, options) => {
105
+ return await afs.exec(path, JSON.parse(args), options);
106
+ },
107
+ }),
95
108
  ];
96
109
  }
@@ -1,4 +1,4 @@
1
- import { AFS, type AFSOptions } from "@aigne/afs";
1
+ import { AFS, type AFSEntry, type AFSListOptions, type AFSModule, type AFSOptions, type AFSSearchOptions } from "@aigne/afs";
2
2
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
3
3
  import type * as prompts from "@inquirer/prompts";
4
4
  import { type ZodObject, type ZodType } from "zod";
@@ -123,7 +123,6 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
123
123
  */
124
124
  memory?: MemoryAgent | MemoryAgent[];
125
125
  afs?: true | AFSOptions | AFS | ((afs: AFS) => AFS);
126
- afsConfig?: AFSConfig;
127
126
  asyncMemoryRecord?: boolean;
128
127
  /**
129
128
  * Maximum number of memory items to retrieve
@@ -132,10 +131,6 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
132
131
  hooks?: AgentHooks<I, O> | AgentHooks<I, O>[];
133
132
  retryOnError?: Agent<I, O>["retryOnError"] | boolean;
134
133
  }
135
- export interface AFSConfig {
136
- injectHistory?: boolean;
137
- historyWindowSize?: number;
138
- }
139
134
  export declare const agentOptionsSchema: ZodObject<{
140
135
  [key in keyof AgentOptions]: ZodType<AgentOptions[key]>;
141
136
  }>;
@@ -200,7 +195,7 @@ export interface AgentInvokeOptions<U extends UserContext = UserContext> {
200
195
  * Here's an example of how to create a custom agent:
201
196
  * {@includeCode ../../test/agents/agent.test.ts#example-custom-agent}
202
197
  */
203
- export declare abstract class Agent<I extends Message = any, O extends Message = any> {
198
+ export declare abstract class Agent<I extends Message = any, O extends Message = any> implements AFSModule {
204
199
  /**
205
200
  * Custom object inspection behavior
206
201
  *
@@ -218,7 +213,6 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
218
213
  */
219
214
  readonly memories: MemoryAgent[];
220
215
  afs?: AFS;
221
- afsConfig?: AFSConfig;
222
216
  asyncMemoryRecord?: boolean;
223
217
  tag?: string;
224
218
  /**
@@ -564,6 +558,26 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
564
558
  * {@includeCode ../../test/agents/agent.test.ts#example-agent-shutdown-by-using}
565
559
  */
566
560
  [Symbol.asyncDispose](): Promise<void>;
561
+ /** For AFSModule interface **/
562
+ private agentToAFSEntry;
563
+ private findAgentByAFSPath;
564
+ list(_path: string, _options?: AFSListOptions): Promise<{
565
+ list: AFSEntry[];
566
+ message?: string;
567
+ }>;
568
+ read(path: string): Promise<{
569
+ result?: AFSEntry;
570
+ message?: string;
571
+ }>;
572
+ search(path: string, _query: string, options?: AFSSearchOptions): Promise<{
573
+ list: AFSEntry[];
574
+ message?: string;
575
+ }>;
576
+ exec(path: string, args: Record<string, any>, options: {
577
+ context: Context;
578
+ }): Promise<{
579
+ result: Record<string, any>;
580
+ }>;
567
581
  }
568
582
  export type AgentInput<T extends Agent> = T extends Agent<infer I, any> ? I : never;
569
583
  export type AgentOutput<T extends Agent> = T extends Agent<any, infer O> ? O : never;
@@ -182,6 +182,7 @@ export declare class AIGNEContext implements Context {
182
182
  subscribe: Context["subscribe"];
183
183
  unsubscribe: Context["unsubscribe"];
184
184
  emit<K extends keyof ContextEmitEventMap>(eventName: K, ...args: Args<K, ContextEmitEventMap>): boolean;
185
+ initProcessExitHandler(): void;
185
186
  private trace;
186
187
  on<K extends keyof ContextEventMap>(eventName: K, listener: Listener<K, ContextEventMap>): this;
187
188
  once<K extends keyof ContextEventMap>(eventName: K, listener: Listener<K, ContextEventMap>): this;
@@ -1,6 +1,6 @@
1
1
  import type { AFSOptions } from "@aigne/afs";
2
2
  import { type ZodType, z } from "zod";
3
- import type { AFSConfig, AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
+ import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
4
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
5
5
  import { type Role } from "../agents/chat-model.js";
6
6
  import { ProcessMode, type ReflectionMode } from "../agents/team-agent.js";
@@ -44,7 +44,6 @@ export interface BaseAgentSchema {
44
44
  afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
45
  modules?: AFSModuleSchema[];
46
46
  });
47
- afsConfig?: AFSConfig;
48
47
  }
49
48
  export type Instructions = {
50
49
  role: Exclude<Role, "tool">;
@@ -15,6 +15,7 @@ export interface LoadOptions {
15
15
  afs?: {
16
16
  availableModules?: {
17
17
  module: string;
18
+ alias?: string[];
18
19
  create: (options?: Record<string, any>) => PromiseOrValue<AFSModule>;
19
20
  }[];
20
21
  };
@@ -1,2 +1,3 @@
1
1
  import type { AFS } from "@aigne/afs";
2
2
  export declare function getAFSSystemPrompt(afs: AFS): Promise<string>;
3
+ export declare const AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE = "<afs_executable_tools>\nHere are the executable tools available in the AFS you can use:\n\n{{ tools | yaml.stringify }}\n</afs_executable_tools>\n";
@@ -1,4 +1,4 @@
1
- import { AFS, type AFSOptions } from "@aigne/afs";
1
+ import { AFS, type AFSEntry, type AFSListOptions, type AFSModule, type AFSOptions, type AFSSearchOptions } from "@aigne/afs";
2
2
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
3
3
  import type * as prompts from "@inquirer/prompts";
4
4
  import { type ZodObject, type ZodType } from "zod";
@@ -123,7 +123,6 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
123
123
  */
124
124
  memory?: MemoryAgent | MemoryAgent[];
125
125
  afs?: true | AFSOptions | AFS | ((afs: AFS) => AFS);
126
- afsConfig?: AFSConfig;
127
126
  asyncMemoryRecord?: boolean;
128
127
  /**
129
128
  * Maximum number of memory items to retrieve
@@ -132,10 +131,6 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
132
131
  hooks?: AgentHooks<I, O> | AgentHooks<I, O>[];
133
132
  retryOnError?: Agent<I, O>["retryOnError"] | boolean;
134
133
  }
135
- export interface AFSConfig {
136
- injectHistory?: boolean;
137
- historyWindowSize?: number;
138
- }
139
134
  export declare const agentOptionsSchema: ZodObject<{
140
135
  [key in keyof AgentOptions]: ZodType<AgentOptions[key]>;
141
136
  }>;
@@ -200,7 +195,7 @@ export interface AgentInvokeOptions<U extends UserContext = UserContext> {
200
195
  * Here's an example of how to create a custom agent:
201
196
  * {@includeCode ../../test/agents/agent.test.ts#example-custom-agent}
202
197
  */
203
- export declare abstract class Agent<I extends Message = any, O extends Message = any> {
198
+ export declare abstract class Agent<I extends Message = any, O extends Message = any> implements AFSModule {
204
199
  /**
205
200
  * Custom object inspection behavior
206
201
  *
@@ -218,7 +213,6 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
218
213
  */
219
214
  readonly memories: MemoryAgent[];
220
215
  afs?: AFS;
221
- afsConfig?: AFSConfig;
222
216
  asyncMemoryRecord?: boolean;
223
217
  tag?: string;
224
218
  /**
@@ -564,6 +558,26 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
564
558
  * {@includeCode ../../test/agents/agent.test.ts#example-agent-shutdown-by-using}
565
559
  */
566
560
  [Symbol.asyncDispose](): Promise<void>;
561
+ /** For AFSModule interface **/
562
+ private agentToAFSEntry;
563
+ private findAgentByAFSPath;
564
+ list(_path: string, _options?: AFSListOptions): Promise<{
565
+ list: AFSEntry[];
566
+ message?: string;
567
+ }>;
568
+ read(path: string): Promise<{
569
+ result?: AFSEntry;
570
+ message?: string;
571
+ }>;
572
+ search(path: string, _query: string, options?: AFSSearchOptions): Promise<{
573
+ list: AFSEntry[];
574
+ message?: string;
575
+ }>;
576
+ exec(path: string, args: Record<string, any>, options: {
577
+ context: Context;
578
+ }): Promise<{
579
+ result: Record<string, any>;
580
+ }>;
567
581
  }
568
582
  export type AgentInput<T extends Agent> = T extends Agent<infer I, any> ? I : never;
569
583
  export type AgentOutput<T extends Agent> = T extends Agent<any, infer O> ? O : never;
@@ -1,8 +1,10 @@
1
- import { AFS } from "@aigne/afs";
1
+ import { AFS, } from "@aigne/afs";
2
2
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
3
3
  import equal from "fast-deep-equal";
4
4
  import nunjucks from "nunjucks";
5
+ import { joinURL } from "ufo";
5
6
  import { z } from "zod";
7
+ import { zodToJsonSchema } from "zod-to-json-schema";
6
8
  import { sortHooks } from "../utils/agent-utils.js";
7
9
  import { isZodSchema } from "../utils/json-schema.js";
8
10
  import { logger } from "../utils/logger.js";
@@ -113,7 +115,6 @@ export class Agent {
113
115
  : options.afs instanceof AFS
114
116
  ? options.afs
115
117
  : new AFS(options.afs);
116
- this.afsConfig = options.afsConfig;
117
118
  this.asyncMemoryRecord = options.asyncMemoryRecord;
118
119
  this.maxRetrieveMemoryCount = options.maxRetrieveMemoryCount;
119
120
  this.hooks = flat(options.hooks);
@@ -132,7 +133,6 @@ export class Agent {
132
133
  */
133
134
  memories = [];
134
135
  afs;
135
- afsConfig;
136
136
  asyncMemoryRecord;
137
137
  tag;
138
138
  /**
@@ -689,6 +689,59 @@ export class Agent {
689
689
  async [Symbol.asyncDispose]() {
690
690
  await this.shutdown();
691
691
  }
692
+ /** For AFSModule interface **/
693
+ agentToAFSEntry(agent) {
694
+ return {
695
+ id: `/${this.name}/${agent.name}`,
696
+ path: agent === this ? "/" : joinURL("/", agent.name),
697
+ summary: agent.description,
698
+ metadata: {
699
+ execute: agent.isInvokable
700
+ ? {
701
+ name: agent.name,
702
+ description: agent.description,
703
+ inputSchema: zodToJsonSchema(agent.inputSchema),
704
+ outputSchema: zodToJsonSchema(agent.outputSchema),
705
+ }
706
+ : undefined,
707
+ },
708
+ };
709
+ }
710
+ findAgentByAFSPath(path) {
711
+ let agent;
712
+ if (path === "/") {
713
+ agent = this;
714
+ }
715
+ else {
716
+ const name = path.split("/")[1];
717
+ agent = this.skills.find((s) => s.name === name);
718
+ }
719
+ return agent;
720
+ }
721
+ // TODO: support list skills inside agent path, and use options to filter skills
722
+ async list(_path, _options) {
723
+ const agents = [this, ...this.skills];
724
+ return { list: agents.map((agent) => this.agentToAFSEntry(agent)) };
725
+ }
726
+ async read(path) {
727
+ const agent = this.findAgentByAFSPath(path);
728
+ if (!agent) {
729
+ return { message: `Agent not found at path: ${path}` };
730
+ }
731
+ return {
732
+ result: this.agentToAFSEntry(agent),
733
+ };
734
+ }
735
+ // TODO: implement search inside agent skills
736
+ async search(path, _query, options) {
737
+ return this.list(path, options);
738
+ }
739
+ async exec(path, args, options) {
740
+ const agent = this.findAgentByAFSPath(path);
741
+ if (!agent)
742
+ throw new Error(`Agent not found at path: ${path}`);
743
+ return { result: await options.context.invoke(agent, args) };
744
+ }
692
745
  }
693
746
  /**
694
747
  * Check if a response chunk is empty
@@ -218,7 +218,7 @@ export class AIGNE {
218
218
  * This registers handlers for SIGINT and exit events to properly terminate all agents.
219
219
  */
220
220
  initProcessExitHandler() {
221
- const shutdownAndExit = () => this.shutdown().finally(() => process.exit(0));
221
+ const shutdownAndExit = () => this.shutdown();
222
222
  process.on("SIGINT", shutdownAndExit);
223
223
  process.on("exit", shutdownAndExit);
224
224
  }
@@ -182,6 +182,7 @@ export declare class AIGNEContext implements Context {
182
182
  subscribe: Context["subscribe"];
183
183
  unsubscribe: Context["unsubscribe"];
184
184
  emit<K extends keyof ContextEmitEventMap>(eventName: K, ...args: Args<K, ContextEmitEventMap>): boolean;
185
+ initProcessExitHandler(): void;
185
186
  private trace;
186
187
  on<K extends keyof ContextEventMap>(eventName: K, listener: Listener<K, ContextEventMap>): this;
187
188
  once<K extends keyof ContextEventMap>(eventName: K, listener: Listener<K, ContextEventMap>): this;
@@ -40,6 +40,7 @@ export class AIGNEContext {
40
40
  this.rootId = this.span?.spanContext?.().traceId ?? v7();
41
41
  }
42
42
  this.id = this.span?.spanContext()?.spanId ?? v7();
43
+ this.initProcessExitHandler();
43
44
  }
44
45
  id;
45
46
  parentId;
@@ -195,6 +196,23 @@ export class AIGNEContext {
195
196
  this.trace(eventName, args, b);
196
197
  return this.internal.events.emit(eventName, ...newArgs);
197
198
  }
199
+ initProcessExitHandler() {
200
+ process.on("SIGINT", async () => {
201
+ try {
202
+ if (process.env.AIGNE_OBSERVABILITY_DISABLED)
203
+ return;
204
+ const span = this.span;
205
+ if (!span)
206
+ return;
207
+ span.setStatus({ code: SpanStatusCode.ERROR, message: "SIGINT" });
208
+ span.end();
209
+ await this.observer?.flush(span);
210
+ }
211
+ finally {
212
+ process.exit(0);
213
+ }
214
+ });
215
+ }
198
216
  async trace(eventName, args, b) {
199
217
  if (process.env.AIGNE_OBSERVABILITY_DISABLED)
200
218
  return;
@@ -1,6 +1,6 @@
1
1
  import type { AFSOptions } from "@aigne/afs";
2
2
  import { type ZodType, z } from "zod";
3
- import type { AFSConfig, AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
3
+ import type { AgentHooks, FunctionAgentFn, TaskRenderMode } from "../agents/agent.js";
4
4
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
5
5
  import { type Role } from "../agents/chat-model.js";
6
6
  import { ProcessMode, type ReflectionMode } from "../agents/team-agent.js";
@@ -44,7 +44,6 @@ export interface BaseAgentSchema {
44
44
  afs?: boolean | (Omit<AFSOptions, "modules"> & {
45
45
  modules?: AFSModuleSchema[];
46
46
  });
47
- afsConfig?: AFSConfig;
48
47
  }
49
48
  export type Instructions = {
50
49
  role: Exclude<Role, "tool">;
@@ -53,22 +53,15 @@ export async function parseAgentFile(path, data) {
53
53
  afs: optionalize(z.union([
54
54
  z.boolean(),
55
55
  camelizeSchema(z.object({
56
- storage: optionalize(z.object({
57
- url: optionalize(z.string()),
58
- })),
59
56
  modules: optionalize(z.array(z.union([
60
57
  z.string(),
61
- z.object({
58
+ camelizeSchema(z.object({
62
59
  module: z.string(),
63
60
  options: optionalize(z.record(z.any())),
64
- }),
61
+ })),
65
62
  ]))),
66
63
  })),
67
64
  ])),
68
- afsConfig: optionalize(camelizeSchema(z.object({
69
- injectHistory: optionalize(z.boolean()),
70
- historyWindowSize: optionalize(z.number().int().min(1)),
71
- }))),
72
65
  });
73
66
  const instructionItemSchema = z.union([
74
67
  z.object({
@@ -15,6 +15,7 @@ export interface LoadOptions {
15
15
  afs?: {
16
16
  availableModules?: {
17
17
  module: string;
18
+ alias?: string[];
18
19
  create: (options?: Record<string, any>) => PromiseOrValue<AFSModule>;
19
20
  }[];
20
21
  };
@@ -114,23 +114,19 @@ async function parseAgent(path, agent, options, agentOptions) {
114
114
  : undefined;
115
115
  let afs;
116
116
  if (typeof agent.afs === "boolean") {
117
- if (agent.afs) {
117
+ if (agent.afs)
118
118
  afs = new AFS();
119
- }
120
119
  }
121
120
  else if (agent.afs) {
122
- afs = new AFS({
123
- ...agent.afs,
124
- modules: agent.afs.modules &&
125
- (await Promise.all(agent.afs.modules.map((m) => {
126
- const mod = typeof m === "string"
127
- ? options?.afs?.availableModules?.find((mod) => mod.module === m)
128
- : options?.afs?.availableModules?.find((mod) => mod.module === m.module);
129
- if (!mod)
130
- throw new Error(`AFS module not found: ${typeof m === "string" ? m : m.module}`);
131
- return mod.create(typeof m === "string" ? {} : m.options);
132
- }))),
133
- });
121
+ afs = new AFS();
122
+ for (const m of agent.afs.modules || []) {
123
+ const moduleName = typeof m === "string" ? m : m.module;
124
+ const mod = options?.afs?.availableModules?.find((mod) => mod.module === moduleName || mod.alias?.includes(moduleName));
125
+ if (!mod)
126
+ throw new Error(`AFS module not found: ${typeof m === "string" ? m : m.module}`);
127
+ const module = await mod.create(typeof m === "string" ? {} : m.options);
128
+ afs.mount(module);
129
+ }
134
130
  }
135
131
  const model = agent.model && typeof options?.model === "function"
136
132
  ? await options.model({ ...options.aigne?.model, ...omitBy(agent.model, (v) => isNil(v)) })
@@ -1,4 +1,4 @@
1
- import { AFSHistory } from "@aigne/afs";
1
+ import { AFSHistory } from "@aigne/afs-history";
2
2
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
3
3
  import { stringify } from "yaml";
4
4
  import { ZodObject } from "zod";
@@ -9,7 +9,7 @@ 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, partition, unique, } from "../utils/type-utils.js";
12
- import { getAFSSystemPrompt } from "./prompts/afs-builtin-prompt.js";
12
+ import { AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE, getAFSSystemPrompt, } from "./prompts/afs-builtin-prompt.js";
13
13
  import { MEMORY_MESSAGE_TEMPLATE } from "./prompts/memory-message-template.js";
14
14
  import { STRUCTURED_STREAM_INSTRUCTIONS } from "./prompts/structured-stream-instructions.js";
15
15
  import { getAFSSkills } from "./skills/afs.js";
@@ -110,21 +110,50 @@ export class PromptBuilder {
110
110
  if (options.agent?.useMemoriesFromContext && options.context?.memories?.length) {
111
111
  memories.push(...options.context.memories);
112
112
  }
113
- if (options.agent?.afs) {
114
- messages.push(await SystemMessageTemplate.from(await getAFSSystemPrompt(options.agent.afs)).format({}));
115
- if (options.agent.afsConfig?.injectHistory) {
116
- const history = await options.agent.afs.list(AFSHistory.Path, {
117
- limit: options.agent.afsConfig.historyWindowSize || 10,
113
+ const afs = options.agent?.afs;
114
+ if (afs) {
115
+ const historyModule = (await afs.listModules()).find((m) => m.module instanceof AFSHistory);
116
+ messages.push(await SystemMessageTemplate.from(await getAFSSystemPrompt(afs)).format({}));
117
+ if (historyModule) {
118
+ const history = await afs.list(historyModule.path, {
119
+ limit: options.agent?.maxRetrieveMemoryCount || 10,
118
120
  orderBy: [["createdAt", "desc"]],
119
121
  });
120
- if (message) {
121
- const result = await options.agent.afs.search("/", message);
122
- const ms = result.list.map((entry) => ({ content: stringify(entry.content) }));
123
- memories.push(...ms);
124
- }
125
122
  memories.push(...history.list
126
123
  .reverse()
127
124
  .filter((i) => isNonNullable(i.content)));
125
+ if (message) {
126
+ const result = await afs.search("/", message);
127
+ const ms = result.list
128
+ .map((entry) => {
129
+ if (entry.metadata?.execute)
130
+ return null;
131
+ const content = entry.content || entry.summary;
132
+ if (!content)
133
+ return null;
134
+ return {
135
+ content,
136
+ description: entry.description,
137
+ };
138
+ })
139
+ .filter(isNonNullable);
140
+ memories.push(...ms);
141
+ const executable = result.list.filter((i) => !!i.metadata?.execute);
142
+ if (executable.length) {
143
+ messages.push({
144
+ role: "system",
145
+ content: await PromptTemplate.from(AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE).format({
146
+ tools: executable.map((entry) => ({
147
+ path: entry.path,
148
+ name: entry.metadata.execute.name,
149
+ description: entry.metadata.execute.description,
150
+ inputSchema: entry.metadata.execute.inputSchema,
151
+ outputSchema: entry.metadata.execute.outputSchema,
152
+ })),
153
+ }),
154
+ });
155
+ }
156
+ }
128
157
  }
129
158
  }
130
159
  if (memories.length)
@@ -229,7 +258,8 @@ export class PromptBuilder {
229
258
  result.push({ role: "agent", content: agentMessageContent });
230
259
  return result;
231
260
  };
232
- for (const { content } of memories) {
261
+ for (const memory of memories) {
262
+ const { content } = memory;
233
263
  if (isRecord(content) &&
234
264
  "input" in content &&
235
265
  content.input &&
@@ -238,7 +268,7 @@ export class PromptBuilder {
238
268
  messages.push(...(await convertMemoryToMessage(content)));
239
269
  }
240
270
  else {
241
- other.push(content);
271
+ other.push(memory);
242
272
  }
243
273
  }
244
274
  if (other.length) {
@@ -1,2 +1,3 @@
1
1
  import type { AFS } from "@aigne/afs";
2
2
  export declare function getAFSSystemPrompt(afs: AFS): Promise<string>;
3
+ export declare const AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE = "<afs_executable_tools>\nHere are the executable tools available in the AFS you can use:\n\n{{ tools | yaml.stringify }}\n</afs_executable_tools>\n";
@@ -1,20 +1,29 @@
1
1
  import { stringify } from "yaml";
2
+ import { pick } from "../../utils/type-utils.js";
2
3
  export async function getAFSSystemPrompt(afs) {
3
4
  return `\
4
5
 
5
6
  <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
+ AFS (Agentic File System) provides tools to interact with a virtual file system,
8
+ allowing you to list, search, read, and write files, or execute a useful tool from the available modules.
9
+ Use these tools to manage and retrieve files as needed.
7
10
 
8
- Modules:
9
- ${stringify(await afs.listModules())}
11
+ Provided modules:
12
+ ${stringify((await afs.listModules()).map((i) => pick(i, ["name", "path", "description"])))}
10
13
 
11
- Available Tools:
14
+ Global tools to interact with the AFS:
12
15
  1. afs_list: Browse directory contents like filesystem ls/tree command - shows files and folders in a given path
13
16
  2. afs_search: Find files by content keywords - use specific keywords related to what you're looking for
14
17
  3. afs_read: Read file contents - path must be an exact file path from list or search results
15
18
  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.
19
+ 5. afs_exec: Execute a executable tool from the available modules
18
20
  </afs_usage>
19
21
  `;
20
22
  }
23
+ export const AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE = `\
24
+ <afs_executable_tools>
25
+ Here are the executable tools available in the AFS you can use:
26
+
27
+ {{ tools | yaml.stringify }}
28
+ </afs_executable_tools>
29
+ `;
@@ -89,5 +89,18 @@ export async function getAFSSkills(afs) {
89
89
  };
90
90
  },
91
91
  }),
92
+ FunctionAgent.from({
93
+ name: "afs_exec",
94
+ description: "Execute a function or command available in the AFS modules",
95
+ inputSchema: z.object({
96
+ path: z.string().describe("The exact path to the executable entry in AFS"),
97
+ args: z
98
+ .string()
99
+ .describe("JSON stringified arguments to pass to the executable, must be an object matching the input schema of the executable"),
100
+ }),
101
+ process: async ({ path, args }, options) => {
102
+ return await afs.exec(path, JSON.parse(args), options);
103
+ },
104
+ }),
92
105
  ];
93
106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.67.0",
3
+ "version": "1.68.0",
4
4
  "description": "The functional core of agentic AI",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -92,9 +92,10 @@
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/observability-api": "^0.11.6",
95
+ "@aigne/afs": "^1.2.0",
96
+ "@aigne/afs-history": "^1.0.1",
96
97
  "@aigne/platform-helpers": "^0.6.3",
97
- "@aigne/afs": "^1.1.2"
98
+ "@aigne/observability-api": "^0.11.6"
98
99
  },
99
100
  "devDependencies": {
100
101
  "@types/bun": "^1.2.22",