@aigne/core 1.6.0 → 1.8.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 (92) hide show
  1. package/CHANGELOG.md +27 -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 +12 -2
  7. package/lib/cjs/agents/mcp-agent.js +45 -27
  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 +16 -47
  13. package/lib/cjs/execution-engine/execution-engine.js +14 -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/cjs/loader/agent-js.js +1 -1
  19. package/lib/cjs/loader/agent-yaml.d.ts +1 -0
  20. package/lib/cjs/loader/agent-yaml.js +4 -0
  21. package/lib/cjs/loader/index.d.ts +72 -1
  22. package/lib/cjs/loader/index.js +13 -13
  23. package/lib/cjs/models/chat-model.d.ts +3 -2
  24. package/lib/cjs/models/chat-model.js +6 -5
  25. package/lib/cjs/models/claude-chat-model.js +11 -8
  26. package/lib/cjs/models/openai-chat-model.js +5 -2
  27. package/lib/cjs/prompt/prompt-builder.d.ts +1 -1
  28. package/lib/cjs/prompt/prompt-builder.js +3 -1
  29. package/lib/cjs/utils/json-schema.js +2 -2
  30. package/lib/cjs/utils/logger.d.ts +3 -15
  31. package/lib/cjs/utils/logger.js +3 -77
  32. package/lib/cjs/utils/mcp-utils.js +1 -5
  33. package/lib/cjs/utils/model-utils.js +2 -2
  34. package/lib/cjs/utils/type-utils.d.ts +1 -0
  35. package/lib/cjs/utils/typed-event-emtter.d.ts +10 -0
  36. package/lib/cjs/utils/typed-event-emtter.js +2 -0
  37. package/lib/dts/agents/agent.d.ts +5 -2
  38. package/lib/dts/agents/ai-agent.d.ts +8 -8
  39. package/lib/dts/agents/mcp-agent.d.ts +12 -2
  40. package/lib/dts/agents/user-agent.d.ts +9 -9
  41. package/lib/dts/execution-engine/context.d.ts +84 -46
  42. package/lib/dts/execution-engine/execution-engine.d.ts +16 -47
  43. package/lib/dts/execution-engine/message-queue.d.ts +3 -3
  44. package/lib/dts/execution-engine/usage.d.ts +11 -0
  45. package/lib/dts/loader/agent-yaml.d.ts +1 -0
  46. package/lib/dts/loader/index.d.ts +72 -1
  47. package/lib/dts/models/chat-model.d.ts +3 -2
  48. package/lib/dts/prompt/prompt-builder.d.ts +1 -1
  49. package/lib/dts/utils/logger.d.ts +3 -15
  50. package/lib/dts/utils/type-utils.d.ts +1 -0
  51. package/lib/dts/utils/typed-event-emtter.d.ts +10 -0
  52. package/lib/esm/agents/agent.d.ts +5 -2
  53. package/lib/esm/agents/agent.js +42 -24
  54. package/lib/esm/agents/ai-agent.d.ts +8 -8
  55. package/lib/esm/agents/ai-agent.js +5 -2
  56. package/lib/esm/agents/mcp-agent.d.ts +12 -2
  57. package/lib/esm/agents/mcp-agent.js +46 -28
  58. package/lib/esm/agents/user-agent.d.ts +9 -9
  59. package/lib/esm/agents/user-agent.js +26 -16
  60. package/lib/esm/execution-engine/context.d.ts +84 -46
  61. package/lib/esm/execution-engine/context.js +135 -98
  62. package/lib/esm/execution-engine/execution-engine.d.ts +16 -47
  63. package/lib/esm/execution-engine/execution-engine.js +15 -39
  64. package/lib/esm/execution-engine/message-queue.d.ts +3 -3
  65. package/lib/esm/execution-engine/message-queue.js +33 -3
  66. package/lib/esm/execution-engine/usage.d.ts +11 -0
  67. package/lib/esm/execution-engine/usage.js +7 -0
  68. package/lib/esm/loader/agent-js.js +1 -1
  69. package/lib/esm/loader/agent-yaml.d.ts +1 -0
  70. package/lib/esm/loader/agent-yaml.js +4 -0
  71. package/lib/esm/loader/index.d.ts +72 -1
  72. package/lib/esm/loader/index.js +13 -14
  73. package/lib/esm/models/chat-model.d.ts +3 -2
  74. package/lib/esm/models/chat-model.js +6 -5
  75. package/lib/esm/models/claude-chat-model.js +11 -8
  76. package/lib/esm/models/openai-chat-model.js +5 -2
  77. package/lib/esm/prompt/prompt-builder.d.ts +1 -1
  78. package/lib/esm/prompt/prompt-builder.js +3 -1
  79. package/lib/esm/utils/json-schema.js +2 -2
  80. package/lib/esm/utils/logger.d.ts +3 -15
  81. package/lib/esm/utils/logger.js +3 -77
  82. package/lib/esm/utils/mcp-utils.js +1 -5
  83. package/lib/esm/utils/model-utils.js +2 -2
  84. package/lib/esm/utils/type-utils.d.ts +1 -0
  85. package/lib/esm/utils/typed-event-emtter.d.ts +10 -0
  86. package/lib/esm/utils/typed-event-emtter.js +1 -0
  87. package/package.json +11 -9
  88. package/lib/cjs/utils/run-chat-loop.d.ts +0 -11
  89. package/lib/cjs/utils/run-chat-loop.js +0 -82
  90. package/lib/dts/utils/run-chat-loop.d.ts +0 -11
  91. package/lib/esm/utils/run-chat-loop.d.ts +0 -11
  92. package/lib/esm/utils/run-chat-loop.js +0 -76
@@ -1,5 +1,6 @@
1
+ import { z } from "zod";
1
2
  import { type Agent } from "../agents/agent.js";
2
- import type { ChatModel } from "../models/chat-model.js";
3
+ import type { ChatModel, ChatModelOptions } from "../models/chat-model.js";
3
4
  export interface LoadOptions {
4
5
  path: string;
5
6
  }
@@ -19,6 +20,75 @@ export declare function load(options: LoadOptions): Promise<{
19
20
  } | null | undefined;
20
21
  }>;
21
22
  export declare function loadAgent(path: string): Promise<Agent>;
23
+ export declare function loadModel(model?: z.infer<typeof aigneFileSchema>["chat_model"], modelOptions?: ChatModelOptions): Promise<ChatModel | undefined>;
24
+ declare const aigneFileSchema: z.ZodObject<{
25
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
26
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
27
+ chat_model: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodUnion<[z.ZodString, z.ZodObject<{
28
+ provider: z.ZodOptional<z.ZodNullable<z.ZodString>>;
29
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
30
+ temperature: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
31
+ top_p: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
32
+ frequent_penalty: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
33
+ presence_penalty: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
34
+ }, "strip", z.ZodTypeAny, {
35
+ name?: string | null | undefined;
36
+ temperature?: number | null | undefined;
37
+ provider?: string | null | undefined;
38
+ top_p?: number | null | undefined;
39
+ frequent_penalty?: number | null | undefined;
40
+ presence_penalty?: number | null | undefined;
41
+ }, {
42
+ name?: string | null | undefined;
43
+ temperature?: number | null | undefined;
44
+ provider?: string | null | undefined;
45
+ top_p?: number | null | undefined;
46
+ frequent_penalty?: number | null | undefined;
47
+ presence_penalty?: number | null | undefined;
48
+ }>]>>>, {
49
+ name?: string | null | undefined;
50
+ temperature?: number | null | undefined;
51
+ provider?: string | null | undefined;
52
+ top_p?: number | null | undefined;
53
+ frequent_penalty?: number | null | undefined;
54
+ presence_penalty?: number | null | undefined;
55
+ } | null | undefined, string | {
56
+ name?: string | null | undefined;
57
+ temperature?: number | null | undefined;
58
+ provider?: string | null | undefined;
59
+ top_p?: number | null | undefined;
60
+ frequent_penalty?: number | null | undefined;
61
+ presence_penalty?: number | null | undefined;
62
+ } | null | undefined>;
63
+ agents: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
64
+ tools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
65
+ }, "strip", z.ZodTypeAny, {
66
+ description?: string | null | undefined;
67
+ tools?: string[] | null | undefined;
68
+ name?: string | null | undefined;
69
+ chat_model?: {
70
+ name?: string | null | undefined;
71
+ temperature?: number | null | undefined;
72
+ provider?: string | null | undefined;
73
+ top_p?: number | null | undefined;
74
+ frequent_penalty?: number | null | undefined;
75
+ presence_penalty?: number | null | undefined;
76
+ } | null | undefined;
77
+ agents?: string[] | null | undefined;
78
+ }, {
79
+ description?: string | null | undefined;
80
+ tools?: string[] | null | undefined;
81
+ name?: string | null | undefined;
82
+ chat_model?: string | {
83
+ name?: string | null | undefined;
84
+ temperature?: number | null | undefined;
85
+ provider?: string | null | undefined;
86
+ top_p?: number | null | undefined;
87
+ frequent_penalty?: number | null | undefined;
88
+ presence_penalty?: number | null | undefined;
89
+ } | null | undefined;
90
+ agents?: string[] | null | undefined;
91
+ }>;
22
92
  export declare function loadAIGNEFile(path: string): Promise<{
23
93
  description?: string | null | undefined;
24
94
  tools?: string[] | null | undefined;
@@ -33,3 +103,4 @@ export declare function loadAIGNEFile(path: string): Promise<{
33
103
  } | null | undefined;
34
104
  agents?: string[] | null | undefined;
35
105
  }>;
106
+ export {};
@@ -1,4 +1,4 @@
1
- import { exists, readFile, stat } from "node:fs/promises";
1
+ import { readFile, stat } from "node:fs/promises";
2
2
  import { dirname, extname, join } from "node:path";
3
3
  import { parse } from "yaml";
4
4
  import { z } from "zod";
@@ -11,7 +11,6 @@ import { XAIChatModel } from "../models/xai-chat-model.js";
11
11
  import { tryOrThrow } from "../utils/type-utils.js";
12
12
  import { loadAgentFromJsFile } from "./agent-js.js";
13
13
  import { loadAgentFromYamlFile } from "./agent-yaml.js";
14
- const DEFAULT_MODEL_PROVIDER = "openai";
15
14
  const AIGNE_FILE_NAME = ["aigne.yaml", "aigne.yml"];
16
15
  export async function load(options) {
17
16
  const { path } = options;
@@ -49,6 +48,7 @@ export async function loadAgent(path) {
49
48
  outputSchema: agent.output_schema,
50
49
  outputKey: agent.output_key,
51
50
  tools: await Promise.all((agent.tools ?? []).map((filename) => loadAgent(join(dirname(path), filename)))),
51
+ toolChoice: agent.tool_choice,
52
52
  });
53
53
  }
54
54
  if (agent.type === "mcp") {
@@ -68,21 +68,20 @@ export async function loadAgent(path) {
68
68
  }
69
69
  throw new Error(`Unsupported agent file type: ${path}`);
70
70
  }
71
- async function loadModel(model) {
72
- if (!model?.name)
73
- return undefined;
71
+ const { MODEL_PROVIDER = "openai", MODEL_NAME = "gpt-4o-mini" } = process.env;
72
+ export async function loadModel(model, modelOptions) {
74
73
  const params = {
75
- model: model.name,
76
- temperature: model.temperature ?? undefined,
77
- topP: model.top_p ?? undefined,
78
- frequencyPenalty: model.frequent_penalty ?? undefined,
79
- presencePenalty: model.presence_penalty ?? undefined,
74
+ model: model?.name ?? MODEL_NAME,
75
+ temperature: model?.temperature ?? undefined,
76
+ topP: model?.top_p ?? undefined,
77
+ frequencyPenalty: model?.frequent_penalty ?? undefined,
78
+ presencePenalty: model?.presence_penalty ?? undefined,
80
79
  };
81
80
  const availableModels = [OpenAIChatModel, ClaudeChatModel, XAIChatModel];
82
- const M = availableModels.find((m) => m.name.toLowerCase().includes(model.provider || DEFAULT_MODEL_PROVIDER));
81
+ const M = availableModels.find((m) => m.name.toLowerCase().includes(model?.provider || MODEL_PROVIDER));
83
82
  if (!M)
84
- throw new Error(`Unsupported model: ${model.provider} ${model.name}`);
85
- return new M(params);
83
+ throw new Error(`Unsupported model: ${model?.provider} ${model?.name}`);
84
+ return new M({ model: params.model, modelOptions: { ...params, ...modelOptions } });
86
85
  }
87
86
  const aigneFileSchema = z.object({
88
87
  name: z.string().nullish(),
@@ -115,7 +114,7 @@ async function getAIGNEFilePath(path) {
115
114
  if (s.isDirectory()) {
116
115
  for (const file of AIGNE_FILE_NAME) {
117
116
  const filePath = join(path, file);
118
- if (await exists(filePath))
117
+ if ((await stat(filePath)).isFile())
119
118
  return filePath;
120
119
  }
121
120
  }
@@ -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
  }
@@ -10,7 +10,7 @@ export class ChatModel extends Agent {
10
10
  preprocess(input, context) {
11
11
  super.preprocess(input, context);
12
12
  const { limits, usage } = context;
13
- const usedTokens = usage.completionTokens + usage.promptTokens;
13
+ const usedTokens = usage.outputTokens + usage.inputTokens;
14
14
  if (limits?.maxTokens && usedTokens >= limits.maxTokens) {
15
15
  throw new Error(`Exceeded max tokens ${usedTokens}/${limits.maxTokens}`);
16
16
  }
@@ -19,8 +19,8 @@ export class ChatModel extends Agent {
19
19
  super.postprocess(input, output, context);
20
20
  const { usage } = output;
21
21
  if (usage) {
22
- context.usage.completionTokens += usage.completionTokens;
23
- context.usage.promptTokens += usage.promptTokens;
22
+ context.usage.outputTokens += usage.outputTokens;
23
+ context.usage.inputTokens += usage.inputTokens;
24
24
  }
25
25
  }
26
26
  }
@@ -98,12 +98,13 @@ const chatModelOutputToolCallSchema = z.object({
98
98
  }),
99
99
  });
100
100
  const chatModelOutputUsageSchema = z.object({
101
- promptTokens: z.number(),
102
- completionTokens: z.number(),
101
+ inputTokens: z.number(),
102
+ outputTokens: z.number(),
103
103
  });
104
104
  const chatModelOutputSchema = z.object({
105
105
  text: z.string().optional(),
106
106
  json: z.record(z.unknown()).optional(),
107
107
  toolCalls: z.array(chatModelOutputToolCallSchema).optional(),
108
108
  usage: chatModelOutputUsageSchema.optional(),
109
+ model: z.string().optional(),
109
110
  });
@@ -30,7 +30,7 @@ export class ClaudeChatModel extends ChatModel {
30
30
  }
31
31
  _client;
32
32
  get client() {
33
- const apiKey = this.options?.apiKey || process.env.CLAUDE_API_KEY;
33
+ const apiKey = this.options?.apiKey || process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_API_KEY;
34
34
  if (!apiKey)
35
35
  throw new Error("Api Key is required for ClaudeChatModel");
36
36
  this._client ??= new Anthropic({ apiKey });
@@ -75,16 +75,18 @@ export class ClaudeChatModel extends ChatModel {
75
75
  let text = "";
76
76
  const toolCalls = [];
77
77
  let usage;
78
+ let model;
78
79
  for await (const chunk of stream) {
79
80
  if (chunk.type === "message_start") {
81
+ model ??= chunk.message.model;
80
82
  const { input_tokens, output_tokens } = chunk.message.usage;
81
83
  usage = {
82
- promptTokens: input_tokens,
83
- completionTokens: output_tokens,
84
+ inputTokens: input_tokens,
85
+ outputTokens: output_tokens,
84
86
  };
85
87
  }
86
88
  if (chunk.type === "message_delta" && usage) {
87
- usage.completionTokens = chunk.usage.output_tokens;
89
+ usage.outputTokens = chunk.usage.output_tokens;
88
90
  }
89
91
  logs.push(JSON.stringify(chunk));
90
92
  // handle streaming text
@@ -109,7 +111,7 @@ export class ClaudeChatModel extends ChatModel {
109
111
  call.args += chunk.delta.partial_json;
110
112
  }
111
113
  }
112
- const result = { usage, text };
114
+ const result = { usage, model, text };
113
115
  if (toolCalls.length) {
114
116
  result.toolCalls = toolCalls
115
117
  .map(({ args, ...c }) => ({
@@ -125,7 +127,7 @@ export class ClaudeChatModel extends ChatModel {
125
127
  return result;
126
128
  }
127
129
  catch (error) {
128
- logger.debug("Failed to process Claude stream", { error, logs });
130
+ logger.core("Failed to process Claude stream", { error, logs });
129
131
  throw error;
130
132
  }
131
133
  }
@@ -154,9 +156,10 @@ export class ClaudeChatModel extends ChatModel {
154
156
  throw new Error("Json tool not found");
155
157
  return {
156
158
  json: jsonTool.input,
159
+ model: result.model,
157
160
  usage: {
158
- promptTokens: result.usage.input_tokens,
159
- completionTokens: result.usage.output_tokens,
161
+ inputTokens: result.usage.input_tokens,
162
+ outputTokens: result.usage.output_tokens,
160
163
  },
161
164
  };
162
165
  }
@@ -72,8 +72,10 @@ export class OpenAIChatModel extends ChatModel {
72
72
  let text = "";
73
73
  const toolCalls = [];
74
74
  let usage;
75
+ let model;
75
76
  for await (const chunk of res) {
76
77
  const choice = chunk.choices?.[0];
78
+ model ??= chunk.model;
77
79
  if (choice?.delta.tool_calls?.length) {
78
80
  for (const call of choice.delta.tool_calls) {
79
81
  toolCalls[call.index] ??= {
@@ -95,13 +97,14 @@ export class OpenAIChatModel extends ChatModel {
95
97
  text += choice.delta.content;
96
98
  if (chunk.usage) {
97
99
  usage = {
98
- promptTokens: chunk.usage.prompt_tokens,
99
- completionTokens: chunk.usage.completion_tokens,
100
+ inputTokens: chunk.usage.prompt_tokens,
101
+ outputTokens: chunk.usage.completion_tokens,
100
102
  };
101
103
  }
102
104
  }
103
105
  const result = {
104
106
  usage,
107
+ model,
105
108
  };
106
109
  if (input.responseFormat?.type === "json_schema" && text) {
107
110
  result.json = 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;
@@ -7,7 +7,9 @@ import { AgentMessageTemplate, ChatMessagesTemplate, SystemMessageTemplate, User
7
7
  export const MESSAGE_KEY = "$message";
8
8
  export const DEFAULT_MAX_HISTORY_MESSAGES = 10;
9
9
  export function createMessage(message) {
10
- return { [MESSAGE_KEY]: message };
10
+ return typeof message === "string"
11
+ ? { [MESSAGE_KEY]: message }
12
+ : { ...message };
11
13
  }
12
14
  export function getMessage(input) {
13
15
  const userInputMessage = input[MESSAGE_KEY];
@@ -23,8 +23,8 @@ export function parseJSON(json) {
23
23
  return JSON.parse(json);
24
24
  }
25
25
  catch (error) {
26
- logger.debug("Failed to parse JSON", { json, error });
27
- throw new Error(`Failed to parse JSON ${error.message}`);
26
+ logger.core("Failed to parse JSON", { json, error });
27
+ throw error;
28
28
  }
29
29
  }
30
30
  /**
@@ -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 {};
@@ -1,80 +1,6 @@
1
1
  import debug from "debug";
2
- debug.log = (...args) => {
3
- const { isSpinning } = globalSpinner ?? {};
4
- if (isSpinning)
5
- globalSpinner?.stop();
6
- console.log(...args);
7
- if (isSpinning)
8
- globalSpinner?.start();
9
- };
10
- function createDebugger(namespace) {
11
- const i = debug(namespace);
12
- function overrideExtend(debug) {
13
- const originalExtend = debug.extend;
14
- debug.extend = (namespace) => {
15
- const extended = originalExtend.call(debug, namespace);
16
- overrideExtend(extended);
17
- extended.spinner = async (promise, message, callback, options) => {
18
- if (!extended.enabled || options?.disabled)
19
- return promise;
20
- return spinner(promise, message, callback);
21
- };
22
- return extended;
23
- };
24
- }
25
- overrideExtend(i);
26
- return i;
27
- }
28
- let globalSpinner;
29
- const globalSpinnerTasks = [];
30
- async function spinner(promise, message, callback) {
31
- const task = { promise, message, callback };
32
- globalSpinnerTasks.push(task);
33
- globalSpinner?.start(message || " ");
34
- await promise
35
- .then((result) => {
36
- task.result = result;
37
- task.status = "succeed";
38
- })
39
- .catch(() => {
40
- task.status = "fail";
41
- });
42
- // Once the promise resolves or rejects, it updates the spinner status and processes
43
- // all completed tasks in a Last-In-First-Out (LIFO) order.
44
- for (;;) {
45
- const task = globalSpinnerTasks.at(-1);
46
- if (!task)
47
- break;
48
- // Recover spinner state for last running task
49
- if (!task.status) {
50
- globalSpinner?.start(task.message || " ");
51
- break;
52
- }
53
- globalSpinnerTasks.pop();
54
- if (task.message) {
55
- if (task.status === "fail")
56
- globalSpinner?.fail(task.message);
57
- else
58
- globalSpinner?.succeed(task.message);
59
- }
60
- else {
61
- globalSpinner?.stop();
62
- }
63
- // NOTE: This is a workaround to make sure the spinner stops spinning before the next tick
64
- await new Promise((resolve) => setTimeout(resolve, 10));
65
- if (task.status === "succeed")
66
- task.callback?.(task.result);
67
- }
68
- return promise;
69
- }
70
- const base = createDebugger("aigne");
2
+ const base = debug("aigne");
71
3
  export const logger = Object.assign(debug, {
72
- globalSpinner,
73
- base,
74
- debug: base.extend("core"),
75
- spinner,
76
- setSpinner: (spinner) => {
77
- globalSpinner = spinner;
78
- logger.globalSpinner = spinner;
79
- },
4
+ core: base.extend("core"),
5
+ mcp: base.extend("mcp"),
80
6
  });
@@ -28,11 +28,7 @@ export function promptFromMCPPrompt(prompt, options) {
28
28
  }
29
29
  export function resourceFromMCPResource(resource, options) {
30
30
  const [uri, variables] = isResourceTemplate(resource)
31
- ? [
32
- resource.uriTemplate,
33
- // TODO: use template.variableNames when it's available https://github.com/modelcontextprotocol/typescript-sdk/pull/188
34
- new UriTemplate(resource.uriTemplate).parts.flatMap((i) => (typeof i === "object" ? i.names : [])),
35
- ]
31
+ ? [resource.uriTemplate, new UriTemplate(resource.uriTemplate).variableNames]
36
32
  : [resource.uri, []];
37
33
  return new MCPResource({
38
34
  ...options,
@@ -1,6 +1,6 @@
1
1
  export function mergeUsage(...usages) {
2
2
  return {
3
- promptTokens: usages.reduce((acc, usage) => (usage ? acc + usage.promptTokens : acc), 0),
4
- completionTokens: usages.reduce((acc, usage) => (usage ? acc + usage.completionTokens : acc), 0),
3
+ inputTokens: usages.reduce((acc, usage) => (usage ? acc + usage.inputTokens : acc), 0),
4
+ outputTokens: usages.reduce((acc, usage) => (usage ? acc + usage.outputTokens : acc), 0),
5
5
  };
6
6
  }
@@ -1,6 +1,7 @@
1
1
  import { type ZodType } from "zod";
2
2
  export type PromiseOrValue<T> = T | Promise<T>;
3
3
  export type Nullish<T> = T | null | undefined;
4
+ export type OmitPropertiesFromArrayFirstElement<T extends unknown[], K extends string | number | symbol> = T extends [infer U, ...infer Rest] ? [Omit<U, K>, ...Rest] : never;
4
5
  export declare function isNil(value: unknown): value is null | undefined;
5
6
  export declare function isEmpty(obj: unknown): boolean;
6
7
  export declare function isNonNullable<T>(value: T): value is NonNullable<T>;
@@ -0,0 +1,10 @@
1
+ type EventMap<T> = Record<keyof T, unknown[]>;
2
+ export type Args<K, T> = K extends keyof T ? T[K] : never;
3
+ export type Listener<K, T> = K extends keyof T ? T[K] extends unknown[] ? (...args: T[K]) => void : never : never;
4
+ export interface TypedEventEmitter<T extends EventMap<T>, E extends EventMap<E> = T> {
5
+ emit<K extends keyof E>(eventName: K, ...args: Args<K, E>): boolean;
6
+ on<K extends keyof T>(eventName: K, listener: Listener<K, T>): this;
7
+ once<K extends keyof T>(eventName: K, listener: Listener<K, T>): this;
8
+ off<K extends keyof T>(eventName: K, listener: Listener<K, T>): this;
9
+ }
10
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "AIGNE core library for building AI-powered applications",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -47,6 +47,9 @@
47
47
  "execution-engine/*": [
48
48
  "./lib/dts/execution-engine/*"
49
49
  ],
50
+ "loader/*": [
51
+ "./lib/dts/loader/*"
52
+ ],
50
53
  "models/*": [
51
54
  "./lib/dts/models/*"
52
55
  ],
@@ -60,14 +63,14 @@
60
63
  },
61
64
  "dependencies": {
62
65
  "@aigne/json-schema-to-zod": "^1.3.3",
63
- "@modelcontextprotocol/sdk": "^1.8.0",
66
+ "@modelcontextprotocol/sdk": "^1.9.0",
64
67
  "@types/debug": "^4.1.12",
65
68
  "debug": "^4.4.0",
66
- "inquirer": "^12.5.0",
69
+ "inquirer": "^12.5.2",
67
70
  "mustache": "^4.2.0",
68
71
  "nanoid": "^5.1.5",
69
- "ora": "^8.2.0",
70
72
  "p-retry": "^6.2.1",
73
+ "uuid": "^11.1.0",
71
74
  "yaml": "^2.7.1",
72
75
  "zod": "^3.24.2",
73
76
  "zod-to-json-schema": "^3.24.5"
@@ -80,17 +83,16 @@
80
83
  "devDependencies": {
81
84
  "@anthropic-ai/sdk": "^0.39.0",
82
85
  "@google/generative-ai": "^0.24.0",
83
- "@types/bun": "^1.2.8",
86
+ "@types/bun": "^1.2.9",
84
87
  "@types/express": "^5.0.1",
85
88
  "@types/mustache": "^4.2.5",
86
- "@types/node": "^22.14.0",
89
+ "@types/node": "^22.14.1",
87
90
  "detect-port": "^2.1.0",
88
91
  "express": "^5.1.0",
89
92
  "npm-run-all": "^4.1.5",
90
- "openai": "^4.91.1",
93
+ "openai": "^4.94.0",
91
94
  "rimraf": "^6.0.1",
92
- "typescript": "^5.8.2",
93
- "@aigne/test-utils": "^1.0.0"
95
+ "typescript": "^5.8.3"
94
96
  },
95
97
  "scripts": {
96
98
  "lint": "tsc --noEmit",
@@ -1,11 +0,0 @@
1
- import type { Message } from "../agents/agent.js";
2
- import type { UserAgent } from "../agents/user-agent.js";
3
- export interface ChatLoopOptions {
4
- log?: typeof console.log;
5
- initialCall?: Message | string;
6
- welcome?: string;
7
- defaultQuestion?: string;
8
- onResponse?: (response: Message) => void;
9
- inputKey?: string;
10
- }
11
- export declare function runChatLoopInTerminal(userAgent: UserAgent, { log, ...options }?: ChatLoopOptions): Promise<void>;
@@ -1,82 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runChatLoopInTerminal = runChatLoopInTerminal;
7
- const inquirer_1 = __importDefault(require("inquirer"));
8
- const ora_1 = __importDefault(require("ora"));
9
- const logger_js_1 = require("./logger.js");
10
- async function runChatLoopInTerminal(userAgent, { log = console.log.bind(console), ...options } = {}) {
11
- logger_js_1.logger.setSpinner((0, ora_1.default)());
12
- let isLoopExited = false;
13
- let prompt;
14
- if (options?.welcome)
15
- log(options.welcome);
16
- if (options?.initialCall) {
17
- await callAgent(userAgent, options.initialCall, { ...options, log });
18
- }
19
- (async () => {
20
- for await (const output of userAgent.stream) {
21
- if (isLoopExited)
22
- return;
23
- if (options?.onResponse)
24
- options.onResponse(output.message);
25
- else
26
- log(output);
27
- prompt?.ui.close();
28
- }
29
- })();
30
- for (let i = 0;; i++) {
31
- prompt = inquirer_1.default.prompt([
32
- {
33
- type: "input",
34
- name: "question",
35
- message: "💬",
36
- default: i === 0 ? options?.defaultQuestion : undefined,
37
- },
38
- ]);
39
- let question;
40
- try {
41
- question = (await prompt).question;
42
- }
43
- catch {
44
- // ignore abort error from inquirer
45
- }
46
- if (!question?.trim())
47
- continue;
48
- const cmd = COMMANDS[question.trim()];
49
- if (cmd) {
50
- const result = cmd();
51
- if (result.message)
52
- log(result.message);
53
- if (result?.exit)
54
- break;
55
- continue;
56
- }
57
- await callAgent(userAgent, question, { ...options, log });
58
- }
59
- isLoopExited = true;
60
- }
61
- async function callAgent(agent, input, options) {
62
- try {
63
- const response = await logger_js_1.logger.spinner(agent.call(options.inputKey && typeof input === "string" ? { [options.inputKey]: input } : input), "🤖");
64
- if (options?.onResponse)
65
- options.onResponse(response);
66
- else
67
- options.log(response);
68
- }
69
- catch (error) {
70
- options.log(`ERROR: ${error.message}`);
71
- }
72
- }
73
- const COMMANDS = {
74
- "/exit": () => ({ exit: true }),
75
- "/help": () => ({
76
- message: `\
77
- Commands:
78
- /exit - exit the chat loop
79
- /help - show this help message
80
- `,
81
- }),
82
- };
@@ -1,11 +0,0 @@
1
- import type { Message } from "../agents/agent.js";
2
- import type { UserAgent } from "../agents/user-agent.js";
3
- export interface ChatLoopOptions {
4
- log?: typeof console.log;
5
- initialCall?: Message | string;
6
- welcome?: string;
7
- defaultQuestion?: string;
8
- onResponse?: (response: Message) => void;
9
- inputKey?: string;
10
- }
11
- export declare function runChatLoopInTerminal(userAgent: UserAgent, { log, ...options }?: ChatLoopOptions): Promise<void>;
@@ -1,11 +0,0 @@
1
- import type { Message } from "../agents/agent.js";
2
- import type { UserAgent } from "../agents/user-agent.js";
3
- export interface ChatLoopOptions {
4
- log?: typeof console.log;
5
- initialCall?: Message | string;
6
- welcome?: string;
7
- defaultQuestion?: string;
8
- onResponse?: (response: Message) => void;
9
- inputKey?: string;
10
- }
11
- export declare function runChatLoopInTerminal(userAgent: UserAgent, { log, ...options }?: ChatLoopOptions): Promise<void>;