@aigne/core 1.6.0 → 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 (82) hide show
  1. package/CHANGELOG.md +14 -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 +16 -47
  13. package/lib/cjs/execution-engine/execution-engine.js +13 -40
  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/index.js +1 -1
  19. package/lib/cjs/models/chat-model.d.ts +3 -2
  20. package/lib/cjs/models/chat-model.js +6 -5
  21. package/lib/cjs/models/claude-chat-model.js +10 -7
  22. package/lib/cjs/models/openai-chat-model.js +5 -2
  23. package/lib/cjs/prompt/prompt-builder.d.ts +1 -1
  24. package/lib/cjs/prompt/prompt-builder.js +3 -1
  25. package/lib/cjs/utils/json-schema.js +2 -2
  26. package/lib/cjs/utils/logger.d.ts +3 -15
  27. package/lib/cjs/utils/logger.js +3 -77
  28. package/lib/cjs/utils/mcp-utils.js +1 -5
  29. package/lib/cjs/utils/model-utils.js +2 -2
  30. package/lib/cjs/utils/type-utils.d.ts +1 -0
  31. package/lib/cjs/utils/typed-event-emtter.d.ts +10 -0
  32. package/lib/cjs/utils/typed-event-emtter.js +2 -0
  33. package/lib/dts/agents/agent.d.ts +5 -2
  34. package/lib/dts/agents/ai-agent.d.ts +8 -8
  35. package/lib/dts/agents/mcp-agent.d.ts +11 -0
  36. package/lib/dts/agents/user-agent.d.ts +9 -9
  37. package/lib/dts/execution-engine/context.d.ts +84 -46
  38. package/lib/dts/execution-engine/execution-engine.d.ts +16 -47
  39. package/lib/dts/execution-engine/message-queue.d.ts +3 -3
  40. package/lib/dts/execution-engine/usage.d.ts +11 -0
  41. package/lib/dts/models/chat-model.d.ts +3 -2
  42. package/lib/dts/prompt/prompt-builder.d.ts +1 -1
  43. package/lib/dts/utils/logger.d.ts +3 -15
  44. package/lib/dts/utils/type-utils.d.ts +1 -0
  45. package/lib/dts/utils/typed-event-emtter.d.ts +10 -0
  46. package/lib/esm/agents/agent.d.ts +5 -2
  47. package/lib/esm/agents/agent.js +42 -24
  48. package/lib/esm/agents/ai-agent.d.ts +8 -8
  49. package/lib/esm/agents/ai-agent.js +5 -2
  50. package/lib/esm/agents/mcp-agent.d.ts +11 -0
  51. package/lib/esm/agents/mcp-agent.js +38 -24
  52. package/lib/esm/agents/user-agent.d.ts +9 -9
  53. package/lib/esm/agents/user-agent.js +26 -16
  54. package/lib/esm/execution-engine/context.d.ts +84 -46
  55. package/lib/esm/execution-engine/context.js +135 -98
  56. package/lib/esm/execution-engine/execution-engine.d.ts +16 -47
  57. package/lib/esm/execution-engine/execution-engine.js +14 -38
  58. package/lib/esm/execution-engine/message-queue.d.ts +3 -3
  59. package/lib/esm/execution-engine/message-queue.js +33 -3
  60. package/lib/esm/execution-engine/usage.d.ts +11 -0
  61. package/lib/esm/execution-engine/usage.js +7 -0
  62. package/lib/esm/loader/index.js +2 -2
  63. package/lib/esm/models/chat-model.d.ts +3 -2
  64. package/lib/esm/models/chat-model.js +6 -5
  65. package/lib/esm/models/claude-chat-model.js +10 -7
  66. package/lib/esm/models/openai-chat-model.js +5 -2
  67. package/lib/esm/prompt/prompt-builder.d.ts +1 -1
  68. package/lib/esm/prompt/prompt-builder.js +3 -1
  69. package/lib/esm/utils/json-schema.js +2 -2
  70. package/lib/esm/utils/logger.d.ts +3 -15
  71. package/lib/esm/utils/logger.js +3 -77
  72. package/lib/esm/utils/mcp-utils.js +1 -5
  73. package/lib/esm/utils/model-utils.js +2 -2
  74. package/lib/esm/utils/type-utils.d.ts +1 -0
  75. package/lib/esm/utils/typed-event-emtter.d.ts +10 -0
  76. package/lib/esm/utils/typed-event-emtter.js +1 -0
  77. package/package.json +7 -8
  78. package/lib/cjs/utils/run-chat-loop.d.ts +0 -11
  79. package/lib/cjs/utils/run-chat-loop.js +0 -82
  80. package/lib/dts/utils/run-chat-loop.d.ts +0 -11
  81. package/lib/esm/utils/run-chat-loop.d.ts +0 -11
  82. package/lib/esm/utils/run-chat-loop.js +0 -76
@@ -1,134 +1,179 @@
1
1
  import EventEmitter from "node:events";
2
+ import { v7 } from "uuid";
2
3
  import { z } from "zod";
3
4
  import { Agent } from "../agents/agent.js";
4
5
  import { isTransferAgentOutput, transferAgentOutputKey } from "../agents/types.js";
5
6
  import { UserAgent } from "../agents/user-agent.js";
6
7
  import { createMessage } from "../prompt/prompt-builder.js";
7
- import { checkArguments, isNil } from "../utils/type-utils.js";
8
+ import { checkArguments, isNil, } from "../utils/type-utils.js";
8
9
  import { MessageQueue, } from "./message-queue.js";
9
- export class ExecutionContext extends EventEmitter {
10
- engine;
11
- constructor(engine) {
12
- super();
13
- this.engine = engine;
14
- this.limits = engine?.limits;
15
- this.messageQueue = engine?.messageQueue ?? new MessageQueue();
10
+ import { newEmptyContextUsage } from "./usage.js";
11
+ export function createPublishMessage(message, from) {
12
+ return {
13
+ role: !from || from instanceof UserAgent ? "user" : "agent",
14
+ source: from?.name,
15
+ message: createMessage(message),
16
+ };
17
+ }
18
+ export class ExecutionContext {
19
+ constructor(parent) {
20
+ if (parent instanceof ExecutionContext) {
21
+ this.parentId = parent.id;
22
+ this.internal = parent.internal;
23
+ }
24
+ else {
25
+ this.internal = new ExecutionContextInternal(parent);
26
+ }
16
27
  }
17
- messageQueue;
28
+ parentId;
29
+ id = v7();
30
+ internal;
18
31
  get model() {
19
- return this.engine?.model;
32
+ return this.internal.model;
20
33
  }
21
34
  get tools() {
22
- return this.engine?.tools;
35
+ return this.internal.tools;
23
36
  }
24
- usage = {
25
- promptTokens: 0,
26
- completionTokens: 0,
27
- agentCalls: 0,
28
- };
29
- limits;
30
- abortController = new AbortController();
31
- timer;
32
- initTimeout() {
33
- if (this.timer)
34
- return;
35
- const timeout = this.limits?.timeout;
36
- if (timeout) {
37
- this.timer = setTimeout(() => {
38
- this.abortController.abort();
39
- }, timeout);
40
- }
37
+ get limits() {
38
+ return this.internal.limits;
41
39
  }
42
40
  get status() {
43
- return this.abortController.signal.aborted ? "timeout" : "normal";
41
+ return this.internal.status;
42
+ }
43
+ get usage() {
44
+ return this.internal.usage;
45
+ }
46
+ newContext({ reset } = {}) {
47
+ if (reset)
48
+ return new ExecutionContext(this.internal);
49
+ return new ExecutionContext(this);
44
50
  }
45
- call(agent, message, options) {
46
- checkArguments("ExecutionEngine._call", executionEngineCallArgsSchema, {
51
+ call = ((agent, message, options) => {
52
+ checkArguments("ExecutionContext.call", executionContextCallArgsSchema, {
47
53
  agent,
48
54
  message,
49
55
  options,
50
56
  });
51
57
  if (isNil(message)) {
52
- let activeAgent = agent;
53
58
  return UserAgent.from({
54
59
  context: this,
55
- process: async (input, context) => {
56
- const [output, agent] = await context.call(activeAgent, input, {
57
- returnActiveAgent: true,
58
- });
59
- activeAgent = agent;
60
- return output;
61
- },
60
+ activeAgent: agent,
62
61
  });
63
62
  }
64
- return withAbortSignal(this.abortController.signal, new Error("ExecutionEngine is timeout"), async () => {
65
- this.initTimeout();
66
- const msg = createMessageFromInput(message);
67
- return this.callAgent(agent, msg).then(async ({ output, agent: activeAgent }) => {
68
- if (activeAgent instanceof Agent) {
69
- const publishTopics = typeof activeAgent.publishTopic === "function"
70
- ? await activeAgent.publishTopic(output)
71
- : activeAgent.publishTopic;
72
- if (publishTopics?.length) {
73
- this.publish(publishTopics, output, activeAgent);
74
- }
63
+ const newContext = this.newContext();
64
+ const msg = createMessage(message);
65
+ return newContext.internal
66
+ .call(agent, msg, newContext, options)
67
+ .then(async ({ output, agent: activeAgent }) => {
68
+ if (activeAgent instanceof Agent) {
69
+ const publishTopics = typeof activeAgent.publishTopic === "function"
70
+ ? await activeAgent.publishTopic(output)
71
+ : activeAgent.publishTopic;
72
+ if (publishTopics?.length) {
73
+ newContext.publish(publishTopics, createPublishMessage(output, activeAgent));
75
74
  }
76
- if (options?.returnActiveAgent) {
77
- return [output, activeAgent];
78
- }
79
- return output;
80
- });
81
- });
82
- }
83
- publish(topic, message, from) {
84
- checkArguments("ExecutionEngineContext.publish", executionEnginePublishArgsSchema, {
85
- topic,
86
- message,
87
- from,
75
+ }
76
+ if (options?.returnActiveAgent) {
77
+ return [output, activeAgent];
78
+ }
79
+ return output;
88
80
  });
89
- const request = {
90
- role: !from || from instanceof UserAgent ? "user" : "agent",
91
- source: from?.name,
92
- message: createMessageFromInput(message),
93
- context: this,
81
+ });
82
+ publish = ((topic, payload) => {
83
+ return this.internal.messageQueue.publish(topic, { ...payload, context: this });
84
+ });
85
+ subscribe = ((...args) => {
86
+ return this.internal.messageQueue.subscribe(...args);
87
+ });
88
+ unsubscribe = ((...args) => {
89
+ return this.internal.messageQueue.unsubscribe(...args);
90
+ });
91
+ emit(eventName, ...args) {
92
+ const b = {
93
+ ...args[0],
94
+ contextId: this.id,
95
+ parentContextId: this.parentId,
96
+ timestamp: Date.now(),
94
97
  };
95
- this.messageQueue.publish(topic, request);
98
+ const newArgs = [b, ...args.slice(1)];
99
+ return this.internal.events.emit(eventName, ...newArgs);
96
100
  }
97
- subscribe(topic, listener) {
98
- return this.messageQueue.subscribe(topic, listener);
101
+ on(eventName, listener) {
102
+ this.internal.events.on(eventName, listener);
103
+ return this;
99
104
  }
100
- unsubscribe(topic, listener) {
101
- this.messageQueue.unsubscribe(topic, listener);
105
+ once(eventName, listener) {
106
+ this.internal.events.once(eventName, listener);
107
+ return this;
102
108
  }
103
- emit(eventName, ...args) {
104
- if (this.engine?.emit)
105
- return this.engine.emit(eventName, ...args);
106
- return super.emit(eventName, ...args);
109
+ off(eventName, listener) {
110
+ this.internal.events.off(eventName, listener);
111
+ return this;
112
+ }
113
+ }
114
+ class ExecutionContextInternal {
115
+ parent;
116
+ constructor(parent) {
117
+ this.parent = parent;
118
+ this.messageQueue = this.parent?.messageQueue ?? new MessageQueue();
119
+ }
120
+ messageQueue;
121
+ events = new EventEmitter();
122
+ get model() {
123
+ return this.parent?.model;
124
+ }
125
+ get tools() {
126
+ return this.parent?.tools;
107
127
  }
108
- async callAgent(agent, input) {
128
+ get limits() {
129
+ return this.parent?.limits;
130
+ }
131
+ usage = newEmptyContextUsage();
132
+ abortController = new AbortController();
133
+ timer;
134
+ initTimeout() {
135
+ if (this.timer)
136
+ return;
137
+ const timeout = this.limits?.timeout;
138
+ if (timeout) {
139
+ this.timer = setTimeout(() => {
140
+ this.abortController.abort();
141
+ }, timeout);
142
+ }
143
+ }
144
+ get status() {
145
+ return this.abortController.signal.aborted ? "timeout" : "normal";
146
+ }
147
+ async call(agent, input, context, options) {
148
+ this.initTimeout();
149
+ return withAbortSignal(this.abortController.signal, new Error("ExecutionContext is timeout"), () => this.callAgent(agent, input, context, options));
150
+ }
151
+ async callAgent(agent, input, context, options) {
109
152
  let activeAgent = agent;
110
153
  let output;
111
154
  for (;;) {
112
155
  let result;
113
156
  if (typeof activeAgent === "function") {
114
- result = await activeAgent(input, this);
157
+ result = await activeAgent(input, context);
115
158
  }
116
159
  else {
117
- result = await activeAgent.call(input, this);
160
+ result = await activeAgent.call(input, context);
161
+ }
162
+ if (result instanceof Agent) {
163
+ activeAgent = result;
164
+ continue;
118
165
  }
119
- if (!(result instanceof Agent))
120
- output = result;
121
- const transferToAgent = result instanceof Agent
122
- ? result
123
- : isTransferAgentOutput(result)
166
+ if (!options?.disableTransfer) {
167
+ const transferToAgent = isTransferAgentOutput(result)
124
168
  ? result[transferAgentOutputKey].agent
125
169
  : undefined;
126
- if (transferToAgent) {
127
- activeAgent = transferToAgent;
128
- }
129
- else {
130
- break;
170
+ if (transferToAgent) {
171
+ activeAgent = transferToAgent;
172
+ continue;
173
+ }
131
174
  }
175
+ output = result;
176
+ break;
132
177
  }
133
178
  if (!output)
134
179
  throw new Error("Unexpected empty output");
@@ -149,15 +194,7 @@ function withAbortSignal(signal, error, fn) {
149
194
  });
150
195
  });
151
196
  }
152
- function createMessageFromInput(message) {
153
- return typeof message === "string" ? createMessage(message) : message;
154
- }
155
- const executionEnginePublishArgsSchema = z.object({
156
- topic: z.union([z.string(), z.array(z.string())]),
157
- message: z.union([z.string(), z.record(z.unknown())]),
158
- from: z.instanceof(Agent).optional(),
159
- });
160
- const executionEngineCallArgsSchema = z.object({
197
+ const executionContextCallArgsSchema = z.object({
161
198
  agent: z.union([z.function(), z.instanceof(Agent)]),
162
199
  message: z.union([z.record(z.unknown()), z.string()]).optional(),
163
200
  options: z.object({ returnActiveAgent: z.boolean().optional() }).optional(),
@@ -1,9 +1,8 @@
1
- import EventEmitter from "node:events";
2
- import { Agent, type Message } from "../agents/agent.js";
3
- import type { UserAgent } from "../agents/user-agent.js";
1
+ import { Agent } from "../agents/agent.js";
4
2
  import { ChatModel } from "../models/chat-model.js";
5
- import { type ContextLimits, ExecutionContext, type Runnable } from "./context.js";
6
- import { type MessagePayload, MessageQueue, type MessageQueueListener, type Unsubscribe } from "./message-queue.js";
3
+ import { type Context, ExecutionContext } from "./context.js";
4
+ import { MessageQueue } from "./message-queue.js";
5
+ import type { ContextLimits } from "./usage.js";
7
6
  export interface ExecutionEngineOptions {
8
7
  name?: string;
9
8
  description?: string;
@@ -12,7 +11,10 @@ export interface ExecutionEngineOptions {
12
11
  agents?: Agent[];
13
12
  limits?: ContextLimits;
14
13
  }
15
- export declare class ExecutionEngine extends EventEmitter {
14
+ export interface ExecutionEngineRunOptions {
15
+ returnActiveAgent?: boolean;
16
+ }
17
+ export declare class ExecutionEngine {
16
18
  static load({ path, ...options }: {
17
19
  path: string;
18
20
  } & ExecutionEngineOptions): Promise<ExecutionEngine>;
@@ -21,52 +23,19 @@ export declare class ExecutionEngine extends EventEmitter {
21
23
  description?: string;
22
24
  readonly messageQueue: MessageQueue;
23
25
  model?: ChatModel;
24
- readonly tools: Agent<Message, Message>[] & {
25
- [key: string]: Agent<Message, Message>;
26
+ readonly tools: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[] & {
27
+ [key: string]: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>;
26
28
  };
27
- readonly agents: Agent<Message, Message>[] & {
28
- [key: string]: Agent<Message, Message>;
29
+ readonly agents: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[] & {
30
+ [key: string]: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>;
29
31
  };
30
32
  limits?: ContextLimits;
31
33
  addAgent(...agents: Agent[]): void;
32
34
  newContext(): ExecutionContext;
33
- /**
34
- * Publish a message to a topic, the engine will call the listeners of the topic
35
- * @param topic topic name, or an array of topic names
36
- * @param message message to publish
37
- * @param from the agent who publish the message, if not provided, it will be treated as a user message
38
- */
39
- publish(topic: string | string[], message: Message | string, from?: Agent): void;
40
- /**
41
- * Create a user agent to consistently call an agent
42
- * @param agent Agent to call
43
- * @returns User agent
44
- */
45
- call<I extends Message, O extends Message>(agent: Runnable<I, O>): UserAgent<I, O>;
46
- /**
47
- * Call an agent with a message
48
- * @param agent Agent to call
49
- * @param message Message to pass to the agent
50
- * @returns the output of the agent
51
- */
52
- call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string): Promise<O>;
53
- /**
54
- * Call an agent with a message and return the output and the active agent
55
- * @param agent Agent to call
56
- * @param message Message to pass to the agent
57
- * @param options.returnActiveAgent return the active agent
58
- * @returns the output of the agent and the final active agent
59
- */
60
- call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options: {
61
- returnActiveAgent: true;
62
- }): Promise<[O, Runnable]>;
63
- call<I extends Message, O extends Message>(agent: Runnable<I, O>, message?: I | string, options?: {
64
- returnActiveAgent?: boolean;
65
- }): UserAgent<I, O> | Promise<O | [O, Runnable]>;
66
- subscribe(topic: string, listener?: undefined): Promise<MessagePayload>;
67
- subscribe(topic: string, listener: MessageQueueListener): Unsubscribe;
68
- subscribe(topic: string, listener?: MessageQueueListener): Unsubscribe | Promise<MessagePayload>;
69
- unsubscribe(topic: string, listener: MessageQueueListener): void;
35
+ publish: Context["publish"];
36
+ call: Context["call"];
37
+ subscribe: Context["subscribe"];
38
+ unsubscribe: Context["unsubscribe"];
70
39
  shutdown(): Promise<void>;
71
40
  private initProcessExitHandler;
72
41
  }
@@ -1,12 +1,11 @@
1
- import EventEmitter from "node:events";
2
1
  import { z } from "zod";
3
2
  import { Agent } from "../agents/agent.js";
4
3
  import { load } from "../loader/index.js";
5
4
  import { ChatModel } from "../models/chat-model.js";
6
5
  import { checkArguments, createAccessorArray } from "../utils/type-utils.js";
7
6
  import { ExecutionContext } from "./context.js";
8
- import { MessageQueue, } from "./message-queue.js";
9
- export class ExecutionEngine extends EventEmitter {
7
+ import { MessageQueue } from "./message-queue.js";
8
+ export class ExecutionEngine {
10
9
  static async load({ path, ...options }) {
11
10
  const { model, agents, tools, ...aigne } = await load({ path });
12
11
  return new ExecutionEngine({
@@ -21,7 +20,6 @@ export class ExecutionEngine extends EventEmitter {
21
20
  constructor(options) {
22
21
  if (options)
23
22
  checkArguments("ExecutionEngine", executionEngineOptionsSchema, options);
24
- super();
25
23
  this.name = options?.name;
26
24
  this.description = options?.description;
27
25
  this.model = options?.model;
@@ -49,32 +47,18 @@ export class ExecutionEngine extends EventEmitter {
49
47
  newContext() {
50
48
  return new ExecutionContext(this);
51
49
  }
52
- /**
53
- * Publish a message to a topic, the engine will call the listeners of the topic
54
- * @param topic topic name, or an array of topic names
55
- * @param message message to publish
56
- * @param from the agent who publish the message, if not provided, it will be treated as a user message
57
- */
58
- publish(topic, message, from) {
59
- return new ExecutionContext(this).publish(topic, message, from);
60
- }
61
- call(agent, message, options) {
62
- return new ExecutionContext(this).call(agent, message, options);
63
- }
64
- subscribe(topic, listener) {
65
- checkArguments("ExecutionEngine.subscribe", executionEngineSubscribeArgsSchema, {
66
- topic,
67
- listener,
68
- });
69
- return this.messageQueue.subscribe(topic, listener);
70
- }
71
- unsubscribe(topic, listener) {
72
- checkArguments("ExecutionEngine.unsubscribe", executionEngineUnsubscribeArgsSchema, {
73
- topic,
74
- listener,
75
- });
76
- this.messageQueue.unsubscribe(topic, listener);
77
- }
50
+ publish = ((...args) => {
51
+ return new ExecutionContext(this).publish(...args);
52
+ });
53
+ call = ((...args) => {
54
+ return new ExecutionContext(this).call(...args);
55
+ });
56
+ subscribe = ((...args) => {
57
+ return this.messageQueue.subscribe(...args);
58
+ });
59
+ unsubscribe = ((...args) => {
60
+ this.messageQueue.unsubscribe(...args);
61
+ });
78
62
  async shutdown() {
79
63
  for (const tool of this.tools) {
80
64
  await tool.shutdown();
@@ -95,11 +79,3 @@ const executionEngineOptionsSchema = z.object({
95
79
  agents: z.array(z.instanceof(Agent)).optional(),
96
80
  });
97
81
  const executionEngineAddAgentArgsSchema = z.array(z.instanceof(Agent));
98
- const executionEngineSubscribeArgsSchema = z.object({
99
- topic: z.string(),
100
- listener: z.function(z.tuple([z.any()]), z.any()).optional(),
101
- });
102
- const executionEngineUnsubscribeArgsSchema = z.object({
103
- topic: z.string(),
104
- listener: z.function(z.tuple([z.any()]), z.any()),
105
- });
@@ -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;
@@ -1,18 +1,27 @@
1
1
  import { EventEmitter } from "node:events";
2
- import { orArrayToArray } from "../utils/type-utils.js";
2
+ import { z } from "zod";
3
+ import { checkArguments, orArrayToArray } from "../utils/type-utils.js";
3
4
  export const UserInputTopic = "UserInputTopic";
4
5
  export const UserOutputTopic = "UserOutputTopic";
5
6
  export class MessageQueue {
6
7
  events = new EventEmitter();
7
- publish(topic, message) {
8
+ publish(topic, payload) {
9
+ checkArguments("MessageQueue.publish", publishArgsSchema, {
10
+ topic,
11
+ payload,
12
+ });
8
13
  for (const t of orArrayToArray(topic)) {
9
- this.events.emit(t, message);
14
+ this.events.emit(t, payload);
10
15
  }
11
16
  }
12
17
  error(error) {
13
18
  this.events.emit("error", error);
14
19
  }
15
20
  subscribe(topic, listener) {
21
+ checkArguments("MessageQueue.subscribe", subscribeArgsSchema, {
22
+ topic,
23
+ listener,
24
+ });
16
25
  if (!listener) {
17
26
  return new Promise((resolve, reject) => {
18
27
  const unsubscribe1 = once(this.events, topic, (message) => {
@@ -28,6 +37,10 @@ export class MessageQueue {
28
37
  return on(this.events, topic, listener);
29
38
  }
30
39
  unsubscribe(topic, listener) {
40
+ checkArguments("MessageQueue.unsubscribe", unsubscribeArgsSchema, {
41
+ topic,
42
+ listener,
43
+ });
31
44
  this.events.off(topic, listener);
32
45
  }
33
46
  }
@@ -39,3 +52,20 @@ function once(events, event, listener) {
39
52
  events.once(event, listener);
40
53
  return () => events.off(event, listener);
41
54
  }
55
+ const subscribeArgsSchema = z.object({
56
+ topic: z.string(),
57
+ listener: z.function(z.tuple([z.any()]), z.any()).optional(),
58
+ });
59
+ const unsubscribeArgsSchema = z.object({
60
+ topic: z.string(),
61
+ listener: z.function(z.tuple([z.any()]), z.any()),
62
+ });
63
+ const publishArgsSchema = z.object({
64
+ topic: z.union([z.string(), z.array(z.string())]),
65
+ payload: z.object({
66
+ role: z.union([z.literal("user"), z.literal("agent")]),
67
+ source: z.string().optional(),
68
+ message: z.union([z.string(), z.record(z.unknown())]),
69
+ context: z.any(),
70
+ }),
71
+ });
@@ -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,7 @@
1
+ export function newEmptyContextUsage() {
2
+ return {
3
+ inputTokens: 0,
4
+ outputTokens: 0,
5
+ agentCalls: 0,
6
+ };
7
+ }
@@ -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";
@@ -115,7 +115,7 @@ async function getAIGNEFilePath(path) {
115
115
  if (s.isDirectory()) {
116
116
  for (const file of AIGNE_FILE_NAME) {
117
117
  const filePath = join(path, file);
118
- if (await exists(filePath))
118
+ if ((await stat(filePath)).isFile())
119
119
  return filePath;
120
120
  }
121
121
  }
@@ -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
  });