@aigne/core 1.5.1-2 → 1.7.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 (97) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/cjs/agents/agent.d.ts +5 -2
  3. package/lib/cjs/agents/agent.js +42 -24
  4. package/lib/cjs/agents/ai-agent.d.ts +8 -8
  5. package/lib/cjs/agents/ai-agent.js +5 -2
  6. package/lib/cjs/agents/mcp-agent.d.ts +11 -0
  7. package/lib/cjs/agents/mcp-agent.js +37 -23
  8. package/lib/cjs/agents/user-agent.d.ts +9 -9
  9. package/lib/cjs/agents/user-agent.js +26 -16
  10. package/lib/cjs/execution-engine/context.d.ts +84 -46
  11. package/lib/cjs/execution-engine/context.js +136 -98
  12. package/lib/cjs/execution-engine/execution-engine.d.ts +20 -47
  13. package/lib/cjs/execution-engine/execution-engine.js +20 -41
  14. package/lib/cjs/execution-engine/message-queue.d.ts +3 -3
  15. package/lib/cjs/execution-engine/message-queue.js +32 -2
  16. package/lib/cjs/execution-engine/usage.d.ts +11 -0
  17. package/lib/cjs/execution-engine/usage.js +10 -0
  18. package/lib/{esm/loader/function-agent.d.ts → cjs/loader/agent-js.d.ts} +1 -5
  19. package/lib/cjs/loader/{function-agent.js → agent-js.js} +2 -2
  20. package/lib/cjs/loader/{ai-agent.d.ts → agent-yaml.d.ts} +7 -4
  21. package/lib/cjs/loader/agent-yaml.js +58 -0
  22. package/lib/cjs/loader/index.d.ts +14 -4
  23. package/lib/cjs/loader/index.js +57 -22
  24. package/lib/cjs/models/chat-model.d.ts +3 -2
  25. package/lib/cjs/models/chat-model.js +6 -5
  26. package/lib/cjs/models/claude-chat-model.js +10 -7
  27. package/lib/cjs/models/openai-chat-model.js +5 -2
  28. package/lib/cjs/prompt/prompt-builder.d.ts +1 -1
  29. package/lib/cjs/prompt/prompt-builder.js +3 -1
  30. package/lib/cjs/utils/json-schema.js +2 -2
  31. package/lib/cjs/utils/logger.d.ts +3 -15
  32. package/lib/cjs/utils/logger.js +3 -77
  33. package/lib/cjs/utils/mcp-utils.js +1 -5
  34. package/lib/cjs/utils/model-utils.js +2 -2
  35. package/lib/cjs/utils/type-utils.d.ts +1 -0
  36. package/lib/cjs/utils/typed-event-emtter.d.ts +10 -0
  37. package/lib/cjs/utils/typed-event-emtter.js +2 -0
  38. package/lib/dts/agents/agent.d.ts +5 -2
  39. package/lib/dts/agents/ai-agent.d.ts +8 -8
  40. package/lib/dts/agents/mcp-agent.d.ts +11 -0
  41. package/lib/dts/agents/user-agent.d.ts +9 -9
  42. package/lib/dts/execution-engine/context.d.ts +84 -46
  43. package/lib/dts/execution-engine/execution-engine.d.ts +20 -47
  44. package/lib/dts/execution-engine/message-queue.d.ts +3 -3
  45. package/lib/dts/execution-engine/usage.d.ts +11 -0
  46. package/lib/dts/loader/{function-agent.d.ts → agent-js.d.ts} +1 -5
  47. package/lib/dts/loader/{ai-agent.d.ts → agent-yaml.d.ts} +7 -4
  48. package/lib/dts/loader/index.d.ts +14 -4
  49. package/lib/dts/models/chat-model.d.ts +3 -2
  50. package/lib/dts/prompt/prompt-builder.d.ts +1 -1
  51. package/lib/dts/utils/logger.d.ts +3 -15
  52. package/lib/dts/utils/type-utils.d.ts +1 -0
  53. package/lib/dts/utils/typed-event-emtter.d.ts +10 -0
  54. package/lib/esm/agents/agent.d.ts +5 -2
  55. package/lib/esm/agents/agent.js +42 -24
  56. package/lib/esm/agents/ai-agent.d.ts +8 -8
  57. package/lib/esm/agents/ai-agent.js +5 -2
  58. package/lib/esm/agents/mcp-agent.d.ts +11 -0
  59. package/lib/esm/agents/mcp-agent.js +38 -24
  60. package/lib/esm/agents/user-agent.d.ts +9 -9
  61. package/lib/esm/agents/user-agent.js +26 -16
  62. package/lib/esm/execution-engine/context.d.ts +84 -46
  63. package/lib/esm/execution-engine/context.js +135 -98
  64. package/lib/esm/execution-engine/execution-engine.d.ts +20 -47
  65. package/lib/esm/execution-engine/execution-engine.js +21 -39
  66. package/lib/esm/execution-engine/message-queue.d.ts +3 -3
  67. package/lib/esm/execution-engine/message-queue.js +33 -3
  68. package/lib/esm/execution-engine/usage.d.ts +11 -0
  69. package/lib/esm/execution-engine/usage.js +7 -0
  70. package/lib/{cjs/loader/function-agent.d.ts → esm/loader/agent-js.d.ts} +1 -5
  71. package/lib/esm/loader/{function-agent.js → agent-js.js} +2 -2
  72. package/lib/esm/loader/{ai-agent.d.ts → agent-yaml.d.ts} +7 -4
  73. package/lib/esm/loader/agent-yaml.js +55 -0
  74. package/lib/esm/loader/index.d.ts +14 -4
  75. package/lib/esm/loader/index.js +56 -21
  76. package/lib/esm/models/chat-model.d.ts +3 -2
  77. package/lib/esm/models/chat-model.js +6 -5
  78. package/lib/esm/models/claude-chat-model.js +10 -7
  79. package/lib/esm/models/openai-chat-model.js +5 -2
  80. package/lib/esm/prompt/prompt-builder.d.ts +1 -1
  81. package/lib/esm/prompt/prompt-builder.js +3 -1
  82. package/lib/esm/utils/json-schema.js +2 -2
  83. package/lib/esm/utils/logger.d.ts +3 -15
  84. package/lib/esm/utils/logger.js +3 -77
  85. package/lib/esm/utils/mcp-utils.js +1 -5
  86. package/lib/esm/utils/model-utils.js +2 -2
  87. package/lib/esm/utils/type-utils.d.ts +1 -0
  88. package/lib/esm/utils/typed-event-emtter.d.ts +10 -0
  89. package/lib/esm/utils/typed-event-emtter.js +1 -0
  90. package/package.json +10 -10
  91. package/lib/cjs/loader/ai-agent.js +0 -40
  92. package/lib/cjs/utils/run-chat-loop.d.ts +0 -11
  93. package/lib/cjs/utils/run-chat-loop.js +0 -82
  94. package/lib/dts/utils/run-chat-loop.d.ts +0 -11
  95. package/lib/esm/loader/ai-agent.js +0 -37
  96. package/lib/esm/utils/run-chat-loop.d.ts +0 -11
  97. package/lib/esm/utils/run-chat-loop.js +0 -76
@@ -1,3 +1,4 @@
1
+ import { EventEmitter } from "node:events";
1
2
  import type { Message } from "../agents/agent.js";
2
3
  import type { Context } from "./context.js";
3
4
  export declare const UserInputTopic = "UserInputTopic";
@@ -9,11 +10,10 @@ export interface MessagePayload {
9
10
  context: Context;
10
11
  }
11
12
  export type MessageQueueListener = (message: MessagePayload) => void;
12
- export type MessageRequest = MessagePayload;
13
13
  export type Unsubscribe = () => void;
14
14
  export declare class MessageQueue {
15
- private events;
16
- publish(topic: string | string[], message: MessageRequest): void;
15
+ events: EventEmitter<[never]>;
16
+ publish(topic: string | string[], payload: MessagePayload): void;
17
17
  error(error: Error): void;
18
18
  subscribe(topic: string, listener?: undefined): Promise<MessagePayload>;
19
19
  subscribe(topic: string, listener: MessageQueueListener): Unsubscribe;
@@ -2,20 +2,29 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MessageQueue = exports.UserOutputTopic = exports.UserInputTopic = void 0;
4
4
  const node_events_1 = require("node:events");
5
+ const zod_1 = require("zod");
5
6
  const type_utils_js_1 = require("../utils/type-utils.js");
6
7
  exports.UserInputTopic = "UserInputTopic";
7
8
  exports.UserOutputTopic = "UserOutputTopic";
8
9
  class MessageQueue {
9
10
  events = new node_events_1.EventEmitter();
10
- publish(topic, message) {
11
+ publish(topic, payload) {
12
+ (0, type_utils_js_1.checkArguments)("MessageQueue.publish", publishArgsSchema, {
13
+ topic,
14
+ payload,
15
+ });
11
16
  for (const t of (0, type_utils_js_1.orArrayToArray)(topic)) {
12
- this.events.emit(t, message);
17
+ this.events.emit(t, payload);
13
18
  }
14
19
  }
15
20
  error(error) {
16
21
  this.events.emit("error", error);
17
22
  }
18
23
  subscribe(topic, listener) {
24
+ (0, type_utils_js_1.checkArguments)("MessageQueue.subscribe", subscribeArgsSchema, {
25
+ topic,
26
+ listener,
27
+ });
19
28
  if (!listener) {
20
29
  return new Promise((resolve, reject) => {
21
30
  const unsubscribe1 = once(this.events, topic, (message) => {
@@ -31,6 +40,10 @@ class MessageQueue {
31
40
  return on(this.events, topic, listener);
32
41
  }
33
42
  unsubscribe(topic, listener) {
43
+ (0, type_utils_js_1.checkArguments)("MessageQueue.unsubscribe", unsubscribeArgsSchema, {
44
+ topic,
45
+ listener,
46
+ });
34
47
  this.events.off(topic, listener);
35
48
  }
36
49
  }
@@ -43,3 +56,20 @@ function once(events, event, listener) {
43
56
  events.once(event, listener);
44
57
  return () => events.off(event, listener);
45
58
  }
59
+ const subscribeArgsSchema = zod_1.z.object({
60
+ topic: zod_1.z.string(),
61
+ listener: zod_1.z.function(zod_1.z.tuple([zod_1.z.any()]), zod_1.z.any()).optional(),
62
+ });
63
+ const unsubscribeArgsSchema = zod_1.z.object({
64
+ topic: zod_1.z.string(),
65
+ listener: zod_1.z.function(zod_1.z.tuple([zod_1.z.any()]), zod_1.z.any()),
66
+ });
67
+ const publishArgsSchema = zod_1.z.object({
68
+ topic: zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]),
69
+ payload: zod_1.z.object({
70
+ role: zod_1.z.union([zod_1.z.literal("user"), zod_1.z.literal("agent")]),
71
+ source: zod_1.z.string().optional(),
72
+ message: zod_1.z.union([zod_1.z.string(), zod_1.z.record(zod_1.z.unknown())]),
73
+ context: zod_1.z.any(),
74
+ }),
75
+ });
@@ -0,0 +1,11 @@
1
+ export interface ContextUsage {
2
+ inputTokens: number;
3
+ outputTokens: number;
4
+ agentCalls: number;
5
+ }
6
+ export declare function newEmptyContextUsage(): ContextUsage;
7
+ export interface ContextLimits {
8
+ maxTokens?: number;
9
+ maxAgentCalls?: number;
10
+ timeout?: number;
11
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.newEmptyContextUsage = newEmptyContextUsage;
4
+ function newEmptyContextUsage() {
5
+ return {
6
+ inputTokens: 0,
7
+ outputTokens: 0,
8
+ agentCalls: 0,
9
+ };
10
+ }
@@ -1,10 +1,6 @@
1
1
  import { type ZodObject, type ZodType, z } from "zod";
2
2
  import type { Message } from "../agents/agent.js";
3
- export declare function loadAgentFromJsFile(path: string, { import: _import }?: {
4
- import?: (path: string) => Promise<{
5
- default: unknown;
6
- }>;
7
- }): Promise<{
3
+ export declare function loadAgentFromJsFile(path: string): Promise<{
8
4
  name: string;
9
5
  fn: (args_0: Message) => Message;
10
6
  description?: string | undefined;
@@ -52,8 +52,8 @@ const agentJsFileSchema = zod_1.z.object({
52
52
  .transform((v) => (v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined)),
53
53
  fn: zod_1.z.function(),
54
54
  });
55
- async function loadAgentFromJsFile(path, { import: _import } = {}) {
56
- const { default: agent } = await (0, type_utils_js_1.tryOrThrow)(() => (_import ? _import(path) : Promise.resolve(`${path}`).then(s => __importStar(require(s)))), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
55
+ async function loadAgentFromJsFile(path) {
56
+ const { default: agent } = await (0, type_utils_js_1.tryOrThrow)(() => Promise.resolve(`${path}`).then(s => __importStar(require(s))), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
57
57
  if (typeof agent !== "function") {
58
58
  throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
59
59
  }
@@ -1,8 +1,6 @@
1
- import { readFile } from "node:fs/promises";
2
1
  import { type ZodObject, type ZodType, z } from "zod";
3
- export declare function loadAgentFromYamlFile(path: string, { readFile: _readFile }?: {
4
- readFile?: typeof readFile;
5
- }): Promise<{
2
+ export declare function loadAgentFromYamlFile(path: string): Promise<{
3
+ type: "ai";
6
4
  name: string;
7
5
  description?: string | undefined;
8
6
  tools?: string[] | undefined;
@@ -18,4 +16,9 @@ export declare function loadAgentFromYamlFile(path: string, { readFile: _readFil
18
16
  [x: string]: any;
19
17
  }> | undefined;
20
18
  output_key?: string | undefined;
19
+ } | {
20
+ type: "mcp";
21
+ url?: string | undefined;
22
+ command?: string | undefined;
23
+ args?: string[] | undefined;
21
24
  }>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadAgentFromYamlFile = loadAgentFromYamlFile;
4
+ const promises_1 = require("node:fs/promises");
5
+ const json_schema_to_zod_1 = require("@aigne/json-schema-to-zod");
6
+ const yaml_1 = require("yaml");
7
+ const zod_1 = require("zod");
8
+ const type_utils_js_1 = require("../utils/type-utils.js");
9
+ const schema_js_1 = require("./schema.js");
10
+ const agentFileSchema = zod_1.z.discriminatedUnion("type", [
11
+ zod_1.z.object({
12
+ type: zod_1.z.literal("ai"),
13
+ name: zod_1.z.string(),
14
+ description: zod_1.z
15
+ .string()
16
+ .nullish()
17
+ .transform((v) => v ?? undefined),
18
+ instructions: zod_1.z
19
+ .string()
20
+ .nullish()
21
+ .transform((v) => v ?? undefined),
22
+ input_schema: schema_js_1.inputOutputSchema
23
+ .nullish()
24
+ .transform((v) => (v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined)),
25
+ output_schema: schema_js_1.inputOutputSchema
26
+ .nullish()
27
+ .transform((v) => (v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined)),
28
+ output_key: zod_1.z
29
+ .string()
30
+ .nullish()
31
+ .transform((v) => v ?? undefined),
32
+ tools: zod_1.z
33
+ .array(zod_1.z.string())
34
+ .nullish()
35
+ .transform((v) => v ?? undefined),
36
+ }),
37
+ zod_1.z.object({
38
+ type: zod_1.z.literal("mcp"),
39
+ url: zod_1.z
40
+ .string()
41
+ .nullish()
42
+ .transform((v) => v ?? undefined),
43
+ command: zod_1.z
44
+ .string()
45
+ .nullish()
46
+ .transform((v) => v ?? undefined),
47
+ args: zod_1.z
48
+ .array(zod_1.z.string())
49
+ .nullish()
50
+ .transform((v) => v ?? undefined),
51
+ }),
52
+ ]);
53
+ async function loadAgentFromYamlFile(path) {
54
+ const raw = await (0, type_utils_js_1.tryOrThrow)(() => (0, promises_1.readFile)(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
55
+ const json = await (0, type_utils_js_1.tryOrThrow)(() => (0, yaml_1.parse)(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
56
+ const agent = (0, type_utils_js_1.tryOrThrow)(() => agentFileSchema.parse({ ...json, type: json.type ?? "ai" }), (error) => new Error(`Failed to validate agent definition from ${path}: ${error.message}`));
57
+ return agent;
58
+ }
@@ -1,4 +1,3 @@
1
- import { readFile } from "node:fs/promises";
2
1
  import { type Agent } from "../agents/agent.js";
3
2
  import type { ChatModel } from "../models/chat-model.js";
4
3
  export interface LoadOptions {
@@ -8,15 +7,26 @@ export declare function load(options: LoadOptions): Promise<{
8
7
  model: ChatModel | undefined;
9
8
  agents: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
10
9
  tools: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
10
+ description?: string | null | undefined;
11
+ name?: string | null | undefined;
12
+ chat_model?: {
13
+ name?: string | null | undefined;
14
+ temperature?: number | null | undefined;
15
+ provider?: string | null | undefined;
16
+ top_p?: number | null | undefined;
17
+ frequent_penalty?: number | null | undefined;
18
+ presence_penalty?: number | null | undefined;
19
+ } | null | undefined;
11
20
  }>;
12
21
  export declare function loadAgent(path: string): Promise<Agent>;
13
- export declare function loadAIGNEFile(path: string, { readFile: _readFile }?: {
14
- readFile?: typeof readFile;
15
- }): Promise<{
22
+ export declare function loadAIGNEFile(path: string): Promise<{
23
+ description?: string | null | undefined;
16
24
  tools?: string[] | null | undefined;
25
+ name?: string | null | undefined;
17
26
  chat_model?: {
18
27
  name?: string | null | undefined;
19
28
  temperature?: number | null | undefined;
29
+ provider?: string | null | undefined;
20
30
  top_p?: number | null | undefined;
21
31
  frequent_penalty?: number | null | undefined;
22
32
  presence_penalty?: number | null | undefined;
@@ -9,19 +9,24 @@ const yaml_1 = require("yaml");
9
9
  const zod_1 = require("zod");
10
10
  const agent_js_1 = require("../agents/agent.js");
11
11
  const ai_agent_js_1 = require("../agents/ai-agent.js");
12
+ const mcp_agent_js_1 = require("../agents/mcp-agent.js");
13
+ const claude_chat_model_js_1 = require("../models/claude-chat-model.js");
12
14
  const openai_chat_model_js_1 = require("../models/openai-chat-model.js");
15
+ const xai_chat_model_js_1 = require("../models/xai-chat-model.js");
13
16
  const type_utils_js_1 = require("../utils/type-utils.js");
14
- const ai_agent_js_2 = require("./ai-agent.js");
15
- const function_agent_js_1 = require("./function-agent.js");
16
- const AIGNE_FILE_NAME = "aigne.yaml";
17
+ const agent_js_js_1 = require("./agent-js.js");
18
+ const agent_yaml_js_1 = require("./agent-yaml.js");
19
+ const DEFAULT_MODEL_PROVIDER = "openai";
20
+ const AIGNE_FILE_NAME = ["aigne.yaml", "aigne.yml"];
17
21
  async function load(options) {
18
22
  const { path } = options;
19
- const aigneFilePath = path.endsWith(AIGNE_FILE_NAME) ? path : (0, node_path_1.join)(path, AIGNE_FILE_NAME);
23
+ const aigneFilePath = await getAIGNEFilePath(path);
20
24
  const rootDir = (0, node_path_1.dirname)(aigneFilePath);
21
25
  const aigne = await loadAIGNEFile(aigneFilePath);
22
26
  const agents = await Promise.all((aigne.agents ?? []).map((filename) => loadAgent((0, node_path_1.join)(rootDir, filename))));
23
27
  const tools = await Promise.all((aigne.tools ?? []).map((filename) => loadAgent((0, node_path_1.join)(rootDir, filename))));
24
28
  return {
29
+ ...aigne,
25
30
  model: await loadModel(aigne.chat_model),
26
31
  agents,
27
32
  tools,
@@ -29,7 +34,7 @@ async function load(options) {
29
34
  }
30
35
  async function loadAgent(path) {
31
36
  if ((0, node_path_1.extname)(path) === ".js") {
32
- const agent = await (0, function_agent_js_1.loadAgentFromJsFile)(path);
37
+ const agent = await (0, agent_js_js_1.loadAgentFromJsFile)(path);
33
38
  return agent_js_1.FunctionAgent.from({
34
39
  name: agent.name,
35
40
  description: agent.description,
@@ -39,16 +44,32 @@ async function loadAgent(path) {
39
44
  });
40
45
  }
41
46
  if ((0, node_path_1.extname)(path) === ".yaml" || (0, node_path_1.extname)(path) === ".yml") {
42
- const agent = await (0, ai_agent_js_2.loadAgentFromYamlFile)(path);
43
- return ai_agent_js_1.AIAgent.from({
44
- name: agent.name,
45
- description: agent.description,
46
- instructions: agent.instructions,
47
- inputSchema: agent.input_schema,
48
- outputSchema: agent.output_schema,
49
- outputKey: agent.output_key,
50
- tools: await Promise.all((agent.tools ?? []).map((filename) => loadAgent((0, node_path_1.join)((0, node_path_1.dirname)(path), filename)))),
51
- });
47
+ const agent = await (0, agent_yaml_js_1.loadAgentFromYamlFile)(path);
48
+ if (agent.type === "ai") {
49
+ return ai_agent_js_1.AIAgent.from({
50
+ name: agent.name,
51
+ description: agent.description,
52
+ instructions: agent.instructions,
53
+ inputSchema: agent.input_schema,
54
+ outputSchema: agent.output_schema,
55
+ outputKey: agent.output_key,
56
+ tools: await Promise.all((agent.tools ?? []).map((filename) => loadAgent((0, node_path_1.join)((0, node_path_1.dirname)(path), filename)))),
57
+ });
58
+ }
59
+ if (agent.type === "mcp") {
60
+ if (agent.url) {
61
+ return mcp_agent_js_1.MCPAgent.from({
62
+ url: agent.url,
63
+ });
64
+ }
65
+ if (agent.command) {
66
+ return mcp_agent_js_1.MCPAgent.from({
67
+ command: agent.command,
68
+ args: agent.args,
69
+ });
70
+ }
71
+ throw new Error(`Missing url or command in mcp agent: ${path}`);
72
+ }
52
73
  }
53
74
  throw new Error(`Unsupported agent file type: ${path}`);
54
75
  }
@@ -62,17 +83,20 @@ async function loadModel(model) {
62
83
  frequencyPenalty: model.frequent_penalty ?? undefined,
63
84
  presencePenalty: model.presence_penalty ?? undefined,
64
85
  };
65
- // TODO: add support for other models such as AutoChatModel, ClaudeChatModel, etc.
66
- if (/^o1|gpt-/.test(model.name)) {
67
- return new openai_chat_model_js_1.OpenAIChatModel(params);
68
- }
69
- throw new Error(`Unsupported model: ${model.name}`);
86
+ const availableModels = [openai_chat_model_js_1.OpenAIChatModel, claude_chat_model_js_1.ClaudeChatModel, xai_chat_model_js_1.XAIChatModel];
87
+ const M = availableModels.find((m) => m.name.toLowerCase().includes(model.provider || DEFAULT_MODEL_PROVIDER));
88
+ if (!M)
89
+ throw new Error(`Unsupported model: ${model.provider} ${model.name}`);
90
+ return new M(params);
70
91
  }
71
92
  const aigneFileSchema = zod_1.z.object({
93
+ name: zod_1.z.string().nullish(),
94
+ description: zod_1.z.string().nullish(),
72
95
  chat_model: zod_1.z
73
96
  .union([
74
97
  zod_1.z.string(),
75
98
  zod_1.z.object({
99
+ provider: zod_1.z.string().nullish(),
76
100
  name: zod_1.z.string().nullish(),
77
101
  temperature: zod_1.z.number().min(0).max(2).nullish(),
78
102
  top_p: zod_1.z.number().min(0).nullish(),
@@ -85,9 +109,20 @@ const aigneFileSchema = zod_1.z.object({
85
109
  agents: zod_1.z.array(zod_1.z.string()).nullish(),
86
110
  tools: zod_1.z.array(zod_1.z.string()).nullish(),
87
111
  });
88
- async function loadAIGNEFile(path, { readFile: _readFile = promises_1.readFile } = {}) {
89
- const raw = await (0, type_utils_js_1.tryOrThrow)(() => _readFile(path, "utf8"), (error) => new Error(`Failed to load aigne.yaml from ${path}: ${error.message}`));
112
+ async function loadAIGNEFile(path) {
113
+ const raw = await (0, type_utils_js_1.tryOrThrow)(() => (0, promises_1.readFile)(path, "utf8"), (error) => new Error(`Failed to load aigne.yaml from ${path}: ${error.message}`));
90
114
  const json = await (0, type_utils_js_1.tryOrThrow)(() => (0, yaml_1.parse)(raw), (error) => new Error(`Failed to parse aigne.yaml from ${path}: ${error.message}`));
91
115
  const agent = (0, type_utils_js_1.tryOrThrow)(() => aigneFileSchema.parse(json), (error) => new Error(`Failed to validate aigne.yaml from ${path}: ${error.message}`));
92
116
  return agent;
93
117
  }
118
+ async function getAIGNEFilePath(path) {
119
+ const s = await (0, promises_1.stat)(path);
120
+ if (s.isDirectory()) {
121
+ for (const file of AIGNE_FILE_NAME) {
122
+ const filePath = (0, node_path_1.join)(path, file);
123
+ if ((await (0, promises_1.stat)(filePath)).isFile())
124
+ return filePath;
125
+ }
126
+ }
127
+ return path;
128
+ }
@@ -75,6 +75,7 @@ export interface ChatModelOutput extends Message {
75
75
  json?: object;
76
76
  toolCalls?: ChatModelOutputToolCall[];
77
77
  usage?: ChatModelOutputUsage;
78
+ model?: string;
78
79
  }
79
80
  export interface ChatModelOutputToolCall {
80
81
  id: string;
@@ -85,6 +86,6 @@ export interface ChatModelOutputToolCall {
85
86
  };
86
87
  }
87
88
  export interface ChatModelOutputUsage {
88
- promptTokens: number;
89
- completionTokens: number;
89
+ inputTokens: number;
90
+ outputTokens: number;
90
91
  }
@@ -13,7 +13,7 @@ class ChatModel extends agent_js_1.Agent {
13
13
  preprocess(input, context) {
14
14
  super.preprocess(input, context);
15
15
  const { limits, usage } = context;
16
- const usedTokens = usage.completionTokens + usage.promptTokens;
16
+ const usedTokens = usage.outputTokens + usage.inputTokens;
17
17
  if (limits?.maxTokens && usedTokens >= limits.maxTokens) {
18
18
  throw new Error(`Exceeded max tokens ${usedTokens}/${limits.maxTokens}`);
19
19
  }
@@ -22,8 +22,8 @@ class ChatModel extends agent_js_1.Agent {
22
22
  super.postprocess(input, output, context);
23
23
  const { usage } = output;
24
24
  if (usage) {
25
- context.usage.completionTokens += usage.completionTokens;
26
- context.usage.promptTokens += usage.promptTokens;
25
+ context.usage.outputTokens += usage.outputTokens;
26
+ context.usage.inputTokens += usage.inputTokens;
27
27
  }
28
28
  }
29
29
  }
@@ -102,12 +102,13 @@ const chatModelOutputToolCallSchema = zod_1.z.object({
102
102
  }),
103
103
  });
104
104
  const chatModelOutputUsageSchema = zod_1.z.object({
105
- promptTokens: zod_1.z.number(),
106
- completionTokens: zod_1.z.number(),
105
+ inputTokens: zod_1.z.number(),
106
+ outputTokens: zod_1.z.number(),
107
107
  });
108
108
  const chatModelOutputSchema = zod_1.z.object({
109
109
  text: zod_1.z.string().optional(),
110
110
  json: zod_1.z.record(zod_1.z.unknown()).optional(),
111
111
  toolCalls: zod_1.z.array(chatModelOutputToolCallSchema).optional(),
112
112
  usage: chatModelOutputUsageSchema.optional(),
113
+ model: zod_1.z.string().optional(),
113
114
  });
@@ -81,16 +81,18 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
81
81
  let text = "";
82
82
  const toolCalls = [];
83
83
  let usage;
84
+ let model;
84
85
  for await (const chunk of stream) {
85
86
  if (chunk.type === "message_start") {
87
+ model ??= chunk.message.model;
86
88
  const { input_tokens, output_tokens } = chunk.message.usage;
87
89
  usage = {
88
- promptTokens: input_tokens,
89
- completionTokens: output_tokens,
90
+ inputTokens: input_tokens,
91
+ outputTokens: output_tokens,
90
92
  };
91
93
  }
92
94
  if (chunk.type === "message_delta" && usage) {
93
- usage.completionTokens = chunk.usage.output_tokens;
95
+ usage.outputTokens = chunk.usage.output_tokens;
94
96
  }
95
97
  logs.push(JSON.stringify(chunk));
96
98
  // handle streaming text
@@ -115,7 +117,7 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
115
117
  call.args += chunk.delta.partial_json;
116
118
  }
117
119
  }
118
- const result = { usage, text };
120
+ const result = { usage, model, text };
119
121
  if (toolCalls.length) {
120
122
  result.toolCalls = toolCalls
121
123
  .map(({ args, ...c }) => ({
@@ -131,7 +133,7 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
131
133
  return result;
132
134
  }
133
135
  catch (error) {
134
- logger_js_1.logger.debug("Failed to process Claude stream", { error, logs });
136
+ logger_js_1.logger.core("Failed to process Claude stream", { error, logs });
135
137
  throw error;
136
138
  }
137
139
  }
@@ -160,9 +162,10 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
160
162
  throw new Error("Json tool not found");
161
163
  return {
162
164
  json: jsonTool.input,
165
+ model: result.model,
163
166
  usage: {
164
- promptTokens: result.usage.input_tokens,
165
- completionTokens: result.usage.output_tokens,
167
+ inputTokens: result.usage.input_tokens,
168
+ outputTokens: result.usage.output_tokens,
166
169
  },
167
170
  };
168
171
  }
@@ -78,8 +78,10 @@ class OpenAIChatModel extends chat_model_js_1.ChatModel {
78
78
  let text = "";
79
79
  const toolCalls = [];
80
80
  let usage;
81
+ let model;
81
82
  for await (const chunk of res) {
82
83
  const choice = chunk.choices?.[0];
84
+ model ??= chunk.model;
83
85
  if (choice?.delta.tool_calls?.length) {
84
86
  for (const call of choice.delta.tool_calls) {
85
87
  toolCalls[call.index] ??= {
@@ -101,13 +103,14 @@ class OpenAIChatModel extends chat_model_js_1.ChatModel {
101
103
  text += choice.delta.content;
102
104
  if (chunk.usage) {
103
105
  usage = {
104
- promptTokens: chunk.usage.prompt_tokens,
105
- completionTokens: chunk.usage.completion_tokens,
106
+ inputTokens: chunk.usage.prompt_tokens,
107
+ outputTokens: chunk.usage.completion_tokens,
106
108
  };
107
109
  }
108
110
  }
109
111
  const result = {
110
112
  usage,
113
+ model,
111
114
  };
112
115
  if (input.responseFormat?.type === "json_schema" && text) {
113
116
  result.json = (0, json_schema_js_1.parseJSON)(text);
@@ -7,7 +7,7 @@ import type { ChatModel, ChatModelInput } from "../models/chat-model.js";
7
7
  import { ChatMessagesTemplate } from "./template.js";
8
8
  export declare const MESSAGE_KEY = "$message";
9
9
  export declare const DEFAULT_MAX_HISTORY_MESSAGES = 10;
10
- export declare function createMessage(message: string | object): Message;
10
+ export declare function createMessage<I extends Message>(message: string | I): I;
11
11
  export declare function getMessage(input: Message): string | undefined;
12
12
  export interface PromptBuilderOptions {
13
13
  instructions?: string | ChatMessagesTemplate;
@@ -12,7 +12,9 @@ const template_js_1 = require("./template.js");
12
12
  exports.MESSAGE_KEY = "$message";
13
13
  exports.DEFAULT_MAX_HISTORY_MESSAGES = 10;
14
14
  function createMessage(message) {
15
- return { [exports.MESSAGE_KEY]: message };
15
+ return typeof message === "string"
16
+ ? { [exports.MESSAGE_KEY]: message }
17
+ : { ...message };
16
18
  }
17
19
  function getMessage(input) {
18
20
  const userInputMessage = input[exports.MESSAGE_KEY];
@@ -28,8 +28,8 @@ function parseJSON(json) {
28
28
  return JSON.parse(json);
29
29
  }
30
30
  catch (error) {
31
- logger_js_1.logger.debug("Failed to parse JSON", { json, error });
32
- throw new Error(`Failed to parse JSON ${error.message}`);
31
+ logger_js_1.logger.core("Failed to parse JSON", { json, error });
32
+ throw error;
33
33
  }
34
34
  }
35
35
  /**
@@ -1,20 +1,8 @@
1
- import debug, { type Debugger } from "debug";
2
- import type { Ora } from "ora";
3
- interface DebugWithSpinner extends Debugger {
4
- spinner<T>(promise: Promise<T>, message?: string, callback?: (result: T) => void, options?: {
5
- disabled?: boolean;
6
- }): Promise<T>;
7
- extend: (namespace: string) => DebugWithSpinner;
8
- }
9
- declare function spinner<T>(promise: Promise<T>, message?: string, callback?: (result: T) => void): Promise<T>;
1
+ import debug from "debug";
10
2
  export declare const logger: debug.Debug & {
11
3
  debug: debug.Debug;
12
4
  default: debug.Debug;
13
5
  } & {
14
- globalSpinner: Ora | undefined;
15
- base: DebugWithSpinner;
16
- debug: DebugWithSpinner;
17
- spinner: typeof spinner;
18
- setSpinner: (spinner: Ora) => void;
6
+ core: debug.Debugger;
7
+ mcp: debug.Debugger;
19
8
  };
20
- export {};
@@ -5,82 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.logger = void 0;
7
7
  const debug_1 = __importDefault(require("debug"));
8
- debug_1.default.log = (...args) => {
9
- const { isSpinning } = globalSpinner ?? {};
10
- if (isSpinning)
11
- globalSpinner?.stop();
12
- console.log(...args);
13
- if (isSpinning)
14
- globalSpinner?.start();
15
- };
16
- function createDebugger(namespace) {
17
- const i = (0, debug_1.default)(namespace);
18
- function overrideExtend(debug) {
19
- const originalExtend = debug.extend;
20
- debug.extend = (namespace) => {
21
- const extended = originalExtend.call(debug, namespace);
22
- overrideExtend(extended);
23
- extended.spinner = async (promise, message, callback, options) => {
24
- if (!extended.enabled || options?.disabled)
25
- return promise;
26
- return spinner(promise, message, callback);
27
- };
28
- return extended;
29
- };
30
- }
31
- overrideExtend(i);
32
- return i;
33
- }
34
- let globalSpinner;
35
- const globalSpinnerTasks = [];
36
- async function spinner(promise, message, callback) {
37
- const task = { promise, message, callback };
38
- globalSpinnerTasks.push(task);
39
- globalSpinner?.start(message || " ");
40
- await promise
41
- .then((result) => {
42
- task.result = result;
43
- task.status = "succeed";
44
- })
45
- .catch(() => {
46
- task.status = "fail";
47
- });
48
- // Once the promise resolves or rejects, it updates the spinner status and processes
49
- // all completed tasks in a Last-In-First-Out (LIFO) order.
50
- for (;;) {
51
- const task = globalSpinnerTasks.at(-1);
52
- if (!task)
53
- break;
54
- // Recover spinner state for last running task
55
- if (!task.status) {
56
- globalSpinner?.start(task.message || " ");
57
- break;
58
- }
59
- globalSpinnerTasks.pop();
60
- if (task.message) {
61
- if (task.status === "fail")
62
- globalSpinner?.fail(task.message);
63
- else
64
- globalSpinner?.succeed(task.message);
65
- }
66
- else {
67
- globalSpinner?.stop();
68
- }
69
- // NOTE: This is a workaround to make sure the spinner stops spinning before the next tick
70
- await new Promise((resolve) => setTimeout(resolve, 10));
71
- if (task.status === "succeed")
72
- task.callback?.(task.result);
73
- }
74
- return promise;
75
- }
76
- const base = createDebugger("aigne");
8
+ const base = (0, debug_1.default)("aigne");
77
9
  exports.logger = Object.assign(debug_1.default, {
78
- globalSpinner,
79
- base,
80
- debug: base.extend("core"),
81
- spinner,
82
- setSpinner: (spinner) => {
83
- globalSpinner = spinner;
84
- exports.logger.globalSpinner = spinner;
85
- },
10
+ core: base.extend("core"),
11
+ mcp: base.extend("mcp"),
86
12
  });