@aigne/core 1.33.2 → 1.36.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 (43) hide show
  1. package/CHANGELOG.md +29 -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.js +3 -13
  6. package/lib/cjs/aigne/context.d.ts +1 -0
  7. package/lib/cjs/aigne/context.js +25 -10
  8. package/lib/cjs/loader/agent-js.d.ts +2 -11
  9. package/lib/cjs/loader/agent-js.js +4 -8
  10. package/lib/cjs/loader/agent-yaml.d.ts +18 -2
  11. package/lib/cjs/loader/agent-yaml.js +32 -13
  12. package/lib/cjs/loader/index.d.ts +2 -2
  13. package/lib/cjs/loader/index.js +48 -15
  14. package/lib/cjs/loader/schema.d.ts +10 -0
  15. package/lib/cjs/loader/schema.js +17 -1
  16. package/lib/cjs/package.json +3 -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/aigne/context.d.ts +1 -0
  21. package/lib/dts/loader/agent-js.d.ts +2 -11
  22. package/lib/dts/loader/agent-yaml.d.ts +18 -2
  23. package/lib/dts/loader/index.d.ts +2 -2
  24. package/lib/dts/loader/schema.d.ts +10 -0
  25. package/lib/dts/utils/type-utils.d.ts +1 -1
  26. package/lib/esm/agents/agent.d.ts +71 -10
  27. package/lib/esm/agents/agent.js +73 -28
  28. package/lib/esm/agents/ai-agent.js +6 -3
  29. package/lib/esm/agents/team-agent.js +3 -13
  30. package/lib/esm/aigne/context.d.ts +1 -0
  31. package/lib/esm/aigne/context.js +25 -10
  32. package/lib/esm/loader/agent-js.d.ts +2 -11
  33. package/lib/esm/loader/agent-js.js +5 -6
  34. package/lib/esm/loader/agent-yaml.d.ts +18 -2
  35. package/lib/esm/loader/agent-yaml.js +33 -11
  36. package/lib/esm/loader/index.d.ts +2 -2
  37. package/lib/esm/loader/index.js +49 -16
  38. package/lib/esm/loader/schema.d.ts +10 -0
  39. package/lib/esm/loader/schema.js +12 -0
  40. package/lib/esm/package.json +3 -1
  41. package/lib/esm/utils/type-utils.d.ts +1 -1
  42. package/lib/esm/utils/type-utils.js +2 -4
  43. package/package.json +4 -4
@@ -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";
8
+ import { camelizeSchema, defaultInputSchema, inputOutputSchema, optionalize } from "./schema.js";
10
9
  export async function loadAgentFromYamlFile(path) {
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,10 +81,10 @@ export async function loadAgentFromYamlFile(path) {
59
81
  jsonata: z.string(),
60
82
  })
61
83
  .extend(baseAgentSchema.shape),
62
- ]);
84
+ ]));
63
85
  });
64
86
  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}`));
87
+ const json = tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
66
88
  const agent = await tryOrThrow(async () => await agentSchema.parseAsync({
67
89
  ...json,
68
90
  type: json.type ?? "ai",
@@ -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,7 +30,7 @@ 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)
@@ -39,38 +39,74 @@ export async function loadAgent(path, options) {
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,13 @@ 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,
92
125
  });
93
126
  }
94
127
  }
@@ -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
+ }
@@ -1 +1,3 @@
1
- {"type": "module"}
1
+ {
2
+ "type": "module"
3
+ }
@@ -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.33.2",
3
+ "version": "1.36.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/observability-api": "^0.7.2",
87
- "@aigne/platform-helpers": "^0.3.1"
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",
@@ -107,6 +107,6 @@
107
107
  "clean": "rimraf lib test/coverage",
108
108
  "test": "bun --cwd test test",
109
109
  "test:coverage": "bun --cwd test test --coverage --coverage-reporter=lcov --coverage-reporter=text",
110
- "postbuild": "echo '{\"type\": \"module\"}' > lib/esm/package.json && echo '{\"type\": \"commonjs\"}' > lib/cjs/package.json"
110
+ "postbuild": "node ../../scripts/post-build-lib.mjs"
111
111
  }
112
112
  }