@aigne/core 1.34.0 → 1.37.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/lib/cjs/agents/agent.d.ts +71 -10
  3. package/lib/cjs/agents/agent.js +73 -28
  4. package/lib/cjs/agents/ai-agent.js +6 -3
  5. package/lib/cjs/agents/team-agent.d.ts +93 -1
  6. package/lib/cjs/agents/team-agent.js +45 -17
  7. package/lib/cjs/aigne/context.d.ts +1 -0
  8. package/lib/cjs/aigne/context.js +25 -10
  9. package/lib/cjs/loader/agent-js.d.ts +2 -17
  10. package/lib/cjs/loader/agent-js.js +4 -16
  11. package/lib/cjs/loader/agent-yaml.d.ts +29 -8
  12. package/lib/cjs/loader/agent-yaml.js +44 -15
  13. package/lib/cjs/loader/index.d.ts +2 -2
  14. package/lib/cjs/loader/index.js +55 -16
  15. package/lib/cjs/loader/schema.d.ts +10 -0
  16. package/lib/cjs/loader/schema.js +17 -1
  17. package/lib/cjs/utils/type-utils.d.ts +1 -1
  18. package/lib/cjs/utils/type-utils.js +2 -4
  19. package/lib/dts/agents/agent.d.ts +71 -10
  20. package/lib/dts/agents/team-agent.d.ts +93 -1
  21. package/lib/dts/aigne/context.d.ts +1 -0
  22. package/lib/dts/loader/agent-js.d.ts +2 -17
  23. package/lib/dts/loader/agent-yaml.d.ts +29 -8
  24. package/lib/dts/loader/index.d.ts +2 -2
  25. package/lib/dts/loader/schema.d.ts +10 -0
  26. package/lib/dts/utils/type-utils.d.ts +1 -1
  27. package/lib/esm/agents/agent.d.ts +71 -10
  28. package/lib/esm/agents/agent.js +73 -28
  29. package/lib/esm/agents/ai-agent.js +6 -3
  30. package/lib/esm/agents/team-agent.d.ts +93 -1
  31. package/lib/esm/agents/team-agent.js +44 -16
  32. package/lib/esm/aigne/context.d.ts +1 -0
  33. package/lib/esm/aigne/context.js +25 -10
  34. package/lib/esm/loader/agent-js.d.ts +2 -17
  35. package/lib/esm/loader/agent-js.js +4 -13
  36. package/lib/esm/loader/agent-yaml.d.ts +29 -8
  37. package/lib/esm/loader/agent-yaml.js +44 -13
  38. package/lib/esm/loader/index.d.ts +2 -2
  39. package/lib/esm/loader/index.js +56 -17
  40. package/lib/esm/loader/schema.d.ts +10 -0
  41. package/lib/esm/loader/schema.js +12 -0
  42. package/lib/esm/utils/type-utils.d.ts +1 -1
  43. package/lib/esm/utils/type-utils.js +2 -4
  44. package/package.json +3 -3
@@ -1,39 +1,60 @@
1
1
  import { type ZodType } from "zod";
2
+ import type { FunctionAgentFn } from "../agents/agent.js";
2
3
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
3
4
  import { ProcessMode } from "../agents/team-agent.js";
4
- interface BaseAgentSchema {
5
+ export interface HooksSchema {
6
+ onStart?: NestAgentSchema;
7
+ onSuccess?: NestAgentSchema;
8
+ onError?: NestAgentSchema;
9
+ onEnd?: NestAgentSchema;
10
+ onSkillStart?: NestAgentSchema;
11
+ onSkillEnd?: NestAgentSchema;
12
+ onHandoff?: NestAgentSchema;
13
+ }
14
+ export type NestAgentSchema = string | {
15
+ url: string;
16
+ defaultInput?: Record<string, any>;
17
+ hooks?: HooksSchema | HooksSchema[];
18
+ } | AgentSchema;
19
+ export interface BaseAgentSchema {
5
20
  name?: string;
6
21
  description?: string;
7
22
  inputSchema?: ZodType<Record<string, any>>;
23
+ defaultInput?: Record<string, any>;
8
24
  outputSchema?: ZodType<Record<string, any>>;
9
- skills?: (string | AgentSchema)[];
25
+ skills?: NestAgentSchema[];
26
+ hooks?: HooksSchema | HooksSchema[];
10
27
  memory?: boolean | {
11
28
  provider: string;
12
29
  subscribeTopic?: string[];
13
30
  };
14
31
  }
15
- interface AIAgentSchema extends BaseAgentSchema {
32
+ export interface AIAgentSchema extends BaseAgentSchema {
16
33
  type: "ai";
17
34
  instructions?: string;
18
35
  inputKey?: string;
19
36
  outputKey?: string;
20
37
  toolChoice?: AIAgentToolChoice;
21
38
  }
22
- interface MCPAgentSchema {
39
+ export interface MCPAgentSchema extends BaseAgentSchema {
23
40
  type: "mcp";
24
41
  url?: string;
25
42
  command?: string;
26
43
  args?: string[];
27
44
  }
28
- interface TeamAgentSchema extends BaseAgentSchema {
45
+ export interface TeamAgentSchema extends BaseAgentSchema {
29
46
  type: "team";
30
47
  mode?: ProcessMode;
31
48
  iterateOn?: string;
32
49
  }
33
- interface TransformAgentSchema extends BaseAgentSchema {
50
+ export interface TransformAgentSchema extends BaseAgentSchema {
34
51
  type: "transform";
35
52
  jsonata: string;
36
53
  }
37
- type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema;
54
+ export interface FunctionAgentSchema extends BaseAgentSchema {
55
+ type: "function";
56
+ process: FunctionAgentFn;
57
+ }
58
+ export type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema | FunctionAgentSchema;
59
+ export declare function parseAgentFile(path: string, data: object): Promise<AgentSchema>;
38
60
  export declare function loadAgentFromYamlFile(path: string): Promise<AgentSchema>;
39
- export {};
@@ -1,29 +1,48 @@
1
1
  import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
2
2
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
3
- import camelize from "camelize-ts";
4
3
  import { parse } from "yaml";
5
4
  import { z } from "zod";
6
5
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
7
6
  import { ProcessMode } from "../agents/team-agent.js";
8
7
  import { tryOrThrow } from "../utils/type-utils.js";
9
- import { inputOutputSchema, optionalize } from "./schema.js";
10
- export async function loadAgentFromYamlFile(path) {
8
+ import { camelizeSchema, defaultInputSchema, inputOutputSchema, optionalize } from "./schema.js";
9
+ export async function parseAgentFile(path, data) {
11
10
  const agentSchema = z.lazy(() => {
11
+ const nestAgentSchema = z.lazy(() => z.union([
12
+ agentSchema,
13
+ z.string(),
14
+ camelizeSchema(z.object({
15
+ url: z.string(),
16
+ defaultInput: optionalize(defaultInputSchema),
17
+ hooks: optionalize(z.union([hooksSchema, z.array(hooksSchema)])),
18
+ })),
19
+ ]));
20
+ const hooksSchema = camelizeSchema(z.object({
21
+ onStart: optionalize(nestAgentSchema),
22
+ onSuccess: optionalize(nestAgentSchema),
23
+ onError: optionalize(nestAgentSchema),
24
+ onEnd: optionalize(nestAgentSchema),
25
+ onSkillStart: optionalize(nestAgentSchema),
26
+ onSkillEnd: optionalize(nestAgentSchema),
27
+ onHandoff: optionalize(nestAgentSchema),
28
+ }));
12
29
  const baseAgentSchema = z.object({
13
30
  name: optionalize(z.string()),
14
31
  description: optionalize(z.string()),
15
32
  inputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
33
+ defaultInput: optionalize(defaultInputSchema),
16
34
  outputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
17
- skills: optionalize(z.array(z.union([z.string(), agentSchema]))),
35
+ hooks: optionalize(z.union([hooksSchema, z.array(hooksSchema)])),
36
+ skills: optionalize(z.array(nestAgentSchema)),
18
37
  memory: optionalize(z.union([
19
38
  z.boolean(),
20
- z.object({
39
+ camelizeSchema(z.object({
21
40
  provider: z.string(),
22
41
  subscribeTopic: optionalize(z.array(z.string())),
23
- }),
42
+ })),
24
43
  ])),
25
44
  });
26
- return z.discriminatedUnion("type", [
45
+ return camelizeSchema(z.discriminatedUnion("type", [
27
46
  z
28
47
  .object({
29
48
  type: z.literal("ai"),
@@ -34,18 +53,21 @@ export async function loadAgentFromYamlFile(path) {
34
53
  }),
35
54
  ])).transform((v) => typeof v === "string"
36
55
  ? v
37
- : v && nodejs.fs.readFile(nodejs.path.join(nodejs.path.dirname(path), v.url), "utf8")),
56
+ : v &&
57
+ nodejs.fs.readFile(nodejs.path.join(nodejs.path.dirname(path), v.url), "utf8")),
38
58
  inputKey: optionalize(z.string()),
39
59
  outputKey: optionalize(z.string()),
40
60
  toolChoice: optionalize(z.nativeEnum(AIAgentToolChoice)),
41
61
  })
42
62
  .extend(baseAgentSchema.shape),
43
- z.object({
63
+ z
64
+ .object({
44
65
  type: z.literal("mcp"),
45
66
  url: optionalize(z.string()),
46
67
  command: optionalize(z.string()),
47
68
  args: optionalize(z.array(z.string())),
48
- }),
69
+ })
70
+ .extend(baseAgentSchema.shape),
49
71
  z
50
72
  .object({
51
73
  type: z.literal("team"),
@@ -59,11 +81,20 @@ export async function loadAgentFromYamlFile(path) {
59
81
  jsonata: z.string(),
60
82
  })
61
83
  .extend(baseAgentSchema.shape),
62
- ]);
84
+ z
85
+ .object({
86
+ type: z.literal("function"),
87
+ process: z.custom(),
88
+ })
89
+ .extend(baseAgentSchema.shape),
90
+ ]));
63
91
  });
92
+ return agentSchema.parseAsync(data);
93
+ }
94
+ export async function loadAgentFromYamlFile(path) {
64
95
  const raw = await tryOrThrow(() => nodejs.fs.readFile(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
65
- const json = tryOrThrow(() => camelize(parse(raw)), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
66
- const agent = await tryOrThrow(async () => await agentSchema.parseAsync({
96
+ const json = tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
97
+ const agent = await tryOrThrow(async () => await parseAgentFile(path, {
67
98
  ...json,
68
99
  type: json.type ?? "ai",
69
100
  skills: json.skills ?? json.tools,
@@ -1,6 +1,6 @@
1
1
  import type { Camelize } from "camelize-ts";
2
2
  import { z } from "zod";
3
- import { Agent } from "../agents/agent.js";
3
+ import { Agent, type AgentOptions } from "../agents/agent.js";
4
4
  import type { ChatModel, ChatModelOptions } from "../agents/chat-model.js";
5
5
  import type { AIGNEOptions } from "../aigne/aigne.js";
6
6
  import type { MemoryAgent, MemoryAgentOptions } from "../memory/memory.js";
@@ -25,7 +25,7 @@ export interface LoadOptions {
25
25
  path: string;
26
26
  }
27
27
  export declare function load(options: LoadOptions): Promise<AIGNEOptions>;
28
- export declare function loadAgent(path: string, options?: LoadOptions): Promise<Agent>;
28
+ export declare function loadAgent(path: string, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
29
29
  export declare function loadModel(models: LoadableModel[], model?: Camelize<z.infer<typeof aigneFileSchema>["model"]>, modelOptions?: ChatModelOptions): Promise<ChatModel | undefined>;
30
30
  declare const aigneFileSchema: z.ZodObject<{
31
31
  name: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
@@ -8,7 +8,7 @@ import { MCPAgent } from "../agents/mcp-agent.js";
8
8
  import { TeamAgent } from "../agents/team-agent.js";
9
9
  import { TransformAgent } from "../agents/transform-agent.js";
10
10
  import { PromptBuilder } from "../prompt/prompt-builder.js";
11
- import { tryOrThrow } from "../utils/type-utils.js";
11
+ import { isNonNullable, tryOrThrow } from "../utils/type-utils.js";
12
12
  import { loadAgentFromJsFile } from "./agent-js.js";
13
13
  import { loadAgentFromYamlFile } from "./agent-yaml.js";
14
14
  import { optionalize } from "./schema.js";
@@ -30,47 +30,83 @@ export async function load(options) {
30
30
  skills,
31
31
  };
32
32
  }
33
- export async function loadAgent(path, options) {
33
+ export async function loadAgent(path, options, agentOptions) {
34
34
  if ([".js", ".mjs", ".ts", ".mts"].includes(nodejs.path.extname(path))) {
35
35
  const agent = await loadAgentFromJsFile(path);
36
36
  if (agent instanceof Agent)
37
37
  return agent;
38
- return FunctionAgent.from(agent);
38
+ return parseAgent(path, agent, options, agentOptions);
39
39
  }
40
40
  if ([".yml", ".yaml"].includes(nodejs.path.extname(path))) {
41
41
  const agent = await loadAgentFromYamlFile(path);
42
- return parseAgent(path, agent, options);
42
+ return parseAgent(path, agent, options, agentOptions);
43
43
  }
44
44
  throw new Error(`Unsupported agent file type: ${path}`);
45
45
  }
46
- async function parseAgent(path, agent, options) {
46
+ async function loadNestAgent(path, agent, options) {
47
+ return typeof agent === "object" && "type" in agent
48
+ ? parseAgent(path, agent, options)
49
+ : typeof agent === "string"
50
+ ? loadAgent(nodejs.path.join(nodejs.path.dirname(path), agent), options)
51
+ : loadAgent(nodejs.path.join(nodejs.path.dirname(path), agent.url), options, {
52
+ defaultInput: agent.defaultInput,
53
+ hooks: await parseHooks(path, agent.hooks, options),
54
+ });
55
+ }
56
+ async function parseHooks(path, hooks, options) {
57
+ hooks = [hooks].flat().filter(isNonNullable);
58
+ if (!hooks.length)
59
+ return undefined;
60
+ return await Promise.all(hooks.map(async (hook) => ({
61
+ onStart: hook.onStart ? await loadNestAgent(path, hook.onStart, options) : undefined,
62
+ onSuccess: hook.onSuccess ? await loadNestAgent(path, hook.onSuccess, options) : undefined,
63
+ onError: hook.onError ? await loadNestAgent(path, hook.onError, options) : undefined,
64
+ onEnd: hook.onEnd ? await loadNestAgent(path, hook.onEnd, options) : undefined,
65
+ onSkillStart: hook.onSkillStart
66
+ ? await loadNestAgent(path, hook.onSkillStart, options)
67
+ : undefined,
68
+ onSkillEnd: hook.onSkillEnd
69
+ ? await loadNestAgent(path, hook.onSkillEnd, options)
70
+ : undefined,
71
+ onHandoff: hook.onHandoff ? await loadNestAgent(path, hook.onHandoff, options) : undefined,
72
+ })));
73
+ }
74
+ async function parseAgent(path, agent, options, agentOptions) {
47
75
  const skills = "skills" in agent
48
76
  ? agent.skills &&
49
- (await Promise.all(agent.skills.map((skill) => typeof skill === "string"
50
- ? loadAgent(nodejs.path.join(nodejs.path.dirname(path), skill), options)
51
- : parseAgent(path, skill, options))))
77
+ (await Promise.all(agent.skills.map((skill) => loadNestAgent(path, skill, options))))
52
78
  : undefined;
53
79
  const memory = "memory" in agent && options?.memories?.length
54
80
  ? await loadMemory(options.memories, typeof agent.memory === "object" ? agent.memory.provider : undefined, typeof agent.memory === "object" ? agent.memory : {})
55
81
  : undefined;
82
+ const baseOptions = {
83
+ ...agentOptions,
84
+ ...agent,
85
+ skills,
86
+ memory,
87
+ hooks: [
88
+ ...((await parseHooks(path, agent.hooks, options)) ?? []),
89
+ ...[agentOptions?.hooks].flat().filter(isNonNullable),
90
+ ],
91
+ };
56
92
  switch (agent.type) {
57
93
  case "ai": {
58
94
  return AIAgent.from({
59
- ...agent,
95
+ ...baseOptions,
60
96
  instructions: agent.instructions &&
61
97
  PromptBuilder.from(agent.instructions, { workingDir: nodejs.path.dirname(path) }),
62
- memory,
63
- skills,
64
98
  });
65
99
  }
66
100
  case "mcp": {
67
101
  if (agent.url) {
68
102
  return MCPAgent.from({
103
+ ...baseOptions,
69
104
  url: agent.url,
70
105
  });
71
106
  }
72
107
  if (agent.command) {
73
108
  return MCPAgent.from({
109
+ ...baseOptions,
74
110
  command: agent.command,
75
111
  args: agent.args,
76
112
  });
@@ -79,16 +115,19 @@ async function parseAgent(path, agent, options) {
79
115
  }
80
116
  case "team": {
81
117
  return TeamAgent.from({
82
- ...agent,
83
- memory,
84
- skills,
118
+ ...baseOptions,
85
119
  });
86
120
  }
87
121
  case "transform": {
88
122
  return TransformAgent.from({
89
- ...agent,
90
- memory,
91
- skills,
123
+ ...baseOptions,
124
+ jsonata: agent.jsonata,
125
+ });
126
+ }
127
+ case "function": {
128
+ return FunctionAgent.from({
129
+ ...baseOptions,
130
+ process: agent.process,
92
131
  });
93
132
  }
94
133
  }
@@ -22,4 +22,14 @@ export declare const inputOutputSchema: ({ path }: {
22
22
  required?: string[] | undefined;
23
23
  additionalProperties?: boolean | undefined;
24
24
  }>]>;
25
+ export declare const defaultInputSchema: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodObject<{
26
+ $get: z.ZodString;
27
+ }, "strip", z.ZodTypeAny, {
28
+ $get: string;
29
+ }, {
30
+ $get: string;
31
+ }>, z.ZodUnknown]>>;
25
32
  export declare function optionalize<T>(schema: ZodType<T>): ZodType<T | undefined>;
33
+ export declare function camelizeSchema<T>(schema: ZodType<T>, { shallow }?: {
34
+ shallow?: boolean;
35
+ }): ZodType<T>;
@@ -1,6 +1,9 @@
1
1
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
2
+ import camelize from "camelize-ts";
2
3
  import { parse } from "yaml";
3
4
  import { z } from "zod";
5
+ import { DEFAULT_INPUT_ACTION_GET } from "../agents/agent.js";
6
+ import { isRecord } from "../utils/type-utils.js";
4
7
  export const inputOutputSchema = ({ path }) => {
5
8
  const includeExternalSchema = async (schema) => {
6
9
  if (schema?.type === "object" && schema.properties) {
@@ -45,6 +48,15 @@ export const inputOutputSchema = ({ path }) => {
45
48
  jsonSchemaSchema,
46
49
  ]);
47
50
  };
51
+ export const defaultInputSchema = z.record(z.string(), z.union([
52
+ z.object({
53
+ [DEFAULT_INPUT_ACTION_GET]: z.string(),
54
+ }),
55
+ z.unknown(),
56
+ ]));
48
57
  export function optionalize(schema) {
49
58
  return schema.nullish().transform((v) => v ?? undefined);
50
59
  }
60
+ export function camelizeSchema(schema, { shallow = true } = {}) {
61
+ return z.preprocess((v) => (isRecord(v) ? camelize(v, shallow) : v), schema);
62
+ }
@@ -19,7 +19,7 @@ export declare function pick<T extends object, K extends keyof T>(obj: T, ...key
19
19
  export declare function omit<T extends object, K extends keyof T>(obj: T, ...keys: (K | K[])[]): Omit<T, K>;
20
20
  export declare function omitDeep<T, K>(obj: T, ...keys: (K | K[])[]): unknown;
21
21
  export declare function omitBy<T extends Record<string, unknown>, K extends keyof T>(obj: T, predicate: (value: T[K], key: K) => boolean): Partial<T>;
22
- export declare function flat<T>(value?: T | T[]): T[];
22
+ export declare function flat<T>(...value: (T | T[])[]): NonNullable<T>[];
23
23
  export declare function createAccessorArray<T>(array: T[], accessor: (array: T[], name: string) => T | undefined): T[] & {
24
24
  [key: string]: T;
25
25
  };
@@ -84,10 +84,8 @@ export function omitBy(obj, predicate) {
84
84
  return !predicate(value, k);
85
85
  }));
86
86
  }
87
- export function flat(value) {
88
- if (isNil(value))
89
- return [];
90
- return Array.isArray(value) ? value : [value];
87
+ export function flat(...value) {
88
+ return value.flat().filter(isNonNullable);
91
89
  }
92
90
  export function createAccessorArray(array, accessor) {
93
91
  return new Proxy(array, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.34.0",
3
+ "version": "1.37.0",
4
4
  "description": "AIGNE core library for building AI-powered applications",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -83,8 +83,8 @@
83
83
  "yaml": "^2.8.0",
84
84
  "zod": "^3.25.67",
85
85
  "zod-to-json-schema": "^3.24.6",
86
- "@aigne/platform-helpers": "^0.4.0",
87
- "@aigne/observability-api": "^0.8.0"
86
+ "@aigne/observability-api": "^0.8.0",
87
+ "@aigne/platform-helpers": "^0.4.0"
88
88
  },
89
89
  "devDependencies": {
90
90
  "@types/bun": "^1.2.18",