@aigne/core 1.1.0-beta.5 → 1.3.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.
- package/CHANGELOG.md +81 -0
- package/lib/cjs/agents/agent.d.ts +37 -33
- package/lib/cjs/agents/agent.js +68 -28
- package/lib/cjs/agents/ai-agent.d.ts +8 -12
- package/lib/cjs/agents/ai-agent.js +17 -35
- package/lib/cjs/agents/mcp-agent.d.ts +25 -9
- package/lib/cjs/agents/mcp-agent.js +61 -14
- package/lib/cjs/agents/memory.d.ts +26 -0
- package/lib/cjs/agents/memory.js +38 -0
- package/lib/cjs/agents/types.d.ts +4 -3
- package/lib/cjs/agents/types.js +11 -1
- package/lib/cjs/agents/user-agent.d.ts +24 -0
- package/lib/cjs/agents/user-agent.js +62 -0
- package/lib/cjs/execution-engine/context.d.ts +35 -5
- package/lib/cjs/execution-engine/execution-engine.d.ts +64 -0
- package/lib/cjs/execution-engine/execution-engine.js +136 -0
- package/lib/cjs/execution-engine/index.d.ts +4 -46
- package/lib/cjs/execution-engine/index.js +17 -193
- package/lib/cjs/execution-engine/message-queue.d.ts +17 -2
- package/lib/cjs/execution-engine/message-queue.js +37 -1
- package/lib/cjs/execution-engine/utils.d.ts +4 -0
- package/lib/cjs/execution-engine/utils.js +32 -0
- package/lib/cjs/index.d.ts +14 -11
- package/lib/cjs/index.js +14 -11
- package/lib/{dts/models/chat.d.ts → cjs/models/chat-model.d.ts} +15 -12
- package/lib/cjs/models/{chat.js → chat-model.js} +5 -5
- package/lib/cjs/models/claude-chat-model.d.ts +17 -0
- package/lib/cjs/models/claude-chat-model.js +199 -0
- package/lib/cjs/models/{chat-openai.d.ts → openai-chat-model.d.ts} +2 -2
- package/lib/cjs/models/{chat-openai.js → openai-chat-model.js} +8 -8
- package/lib/cjs/prompt/prompt-builder.d.ts +14 -14
- package/lib/cjs/prompt/prompt-builder.js +62 -67
- package/lib/cjs/prompt/template.d.ts +9 -21
- package/lib/cjs/prompt/template.js +3 -5
- package/lib/cjs/utils/json-schema.d.ts +3 -0
- package/lib/cjs/utils/json-schema.js +23 -0
- package/lib/cjs/utils/mcp-utils.d.ts +3 -2
- package/lib/cjs/utils/mcp-utils.js +29 -17
- package/lib/cjs/utils/run-chat-loop.d.ts +5 -4
- package/lib/cjs/utils/run-chat-loop.js +25 -4
- package/lib/cjs/utils/type-utils.d.ts +3 -0
- package/lib/cjs/utils/type-utils.js +8 -8
- package/lib/dts/agents/agent.d.ts +37 -33
- package/lib/dts/agents/ai-agent.d.ts +8 -12
- package/lib/dts/agents/mcp-agent.d.ts +25 -9
- package/lib/dts/agents/memory.d.ts +26 -0
- package/lib/dts/agents/types.d.ts +4 -3
- package/lib/dts/agents/user-agent.d.ts +24 -0
- package/lib/dts/execution-engine/context.d.ts +35 -5
- package/lib/dts/execution-engine/execution-engine.d.ts +64 -0
- package/lib/dts/execution-engine/index.d.ts +4 -46
- package/lib/dts/execution-engine/message-queue.d.ts +17 -2
- package/lib/dts/execution-engine/utils.d.ts +4 -0
- package/lib/dts/index.d.ts +14 -11
- package/lib/{esm/models/chat.d.ts → dts/models/chat-model.d.ts} +15 -12
- package/lib/dts/models/claude-chat-model.d.ts +17 -0
- package/lib/dts/models/{chat-openai.d.ts → openai-chat-model.d.ts} +2 -2
- package/lib/dts/prompt/prompt-builder.d.ts +14 -14
- package/lib/dts/prompt/template.d.ts +9 -21
- package/lib/dts/utils/json-schema.d.ts +3 -0
- package/lib/dts/utils/mcp-utils.d.ts +3 -2
- package/lib/dts/utils/run-chat-loop.d.ts +5 -4
- package/lib/dts/utils/type-utils.d.ts +3 -0
- package/lib/esm/agents/agent.d.ts +37 -33
- package/lib/esm/agents/agent.js +67 -24
- package/lib/esm/agents/ai-agent.d.ts +8 -12
- package/lib/esm/agents/ai-agent.js +13 -31
- package/lib/esm/agents/mcp-agent.d.ts +25 -9
- package/lib/esm/agents/mcp-agent.js +54 -8
- package/lib/esm/agents/memory.d.ts +26 -0
- package/lib/esm/agents/memory.js +34 -0
- package/lib/esm/agents/types.d.ts +4 -3
- package/lib/esm/agents/types.js +10 -1
- package/lib/esm/agents/user-agent.d.ts +24 -0
- package/lib/esm/agents/user-agent.js +58 -0
- package/lib/esm/execution-engine/context.d.ts +35 -5
- package/lib/esm/execution-engine/execution-engine.d.ts +64 -0
- package/lib/esm/execution-engine/execution-engine.js +129 -0
- package/lib/esm/execution-engine/index.d.ts +4 -46
- package/lib/esm/execution-engine/index.js +4 -188
- package/lib/esm/execution-engine/message-queue.d.ts +17 -2
- package/lib/esm/execution-engine/message-queue.js +37 -1
- package/lib/esm/execution-engine/utils.d.ts +4 -0
- package/lib/esm/execution-engine/utils.js +28 -0
- package/lib/esm/index.d.ts +14 -11
- package/lib/esm/index.js +14 -11
- package/lib/{cjs/models/chat.d.ts → esm/models/chat-model.d.ts} +15 -12
- package/lib/esm/models/{chat.js → chat-model.js} +4 -4
- package/lib/esm/models/claude-chat-model.d.ts +17 -0
- package/lib/esm/models/claude-chat-model.js +192 -0
- package/lib/esm/models/{chat-openai.d.ts → openai-chat-model.d.ts} +2 -2
- package/lib/esm/models/{chat-openai.js → openai-chat-model.js} +5 -5
- package/lib/esm/prompt/prompt-builder.d.ts +14 -14
- package/lib/esm/prompt/prompt-builder.js +56 -58
- package/lib/esm/prompt/template.d.ts +9 -21
- package/lib/esm/prompt/template.js +3 -5
- package/lib/esm/utils/json-schema.d.ts +3 -0
- package/lib/esm/utils/json-schema.js +20 -0
- package/lib/esm/utils/mcp-utils.d.ts +3 -2
- package/lib/esm/utils/mcp-utils.js +26 -15
- package/lib/esm/utils/run-chat-loop.d.ts +5 -4
- package/lib/esm/utils/run-chat-loop.js +25 -4
- package/lib/esm/utils/type-utils.d.ts +3 -0
- package/lib/esm/utils/type-utils.js +4 -2
- package/package.json +31 -30
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
2
|
import { type StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
-
import type { CallToolResult, GetPromptResult } from "@modelcontextprotocol/sdk/types";
|
|
4
|
-
import
|
|
3
|
+
import type { CallToolResult, GetPromptResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import type { Context } from "../execution-engine/context.js";
|
|
5
|
+
import { Agent, type AgentOptions, type Message } from "./agent.js";
|
|
5
6
|
export interface MCPAgentOptions extends AgentOptions {
|
|
6
7
|
client: Client;
|
|
7
8
|
prompts?: MCPPrompt[];
|
|
9
|
+
resources?: MCPResource[];
|
|
8
10
|
}
|
|
9
11
|
export type MCPServerOptions = SSEServerParameters | StdioServerParameters;
|
|
10
12
|
export type SSEServerParameters = {
|
|
@@ -19,21 +21,35 @@ export declare class MCPAgent extends Agent {
|
|
|
19
21
|
readonly prompts: MCPPrompt[] & {
|
|
20
22
|
[key: string]: MCPPrompt;
|
|
21
23
|
};
|
|
24
|
+
readonly resources: MCPResource[] & {
|
|
25
|
+
[key: string]: MCPResource;
|
|
26
|
+
};
|
|
27
|
+
get isCallable(): boolean;
|
|
28
|
+
process(_input: Message, _context?: Context): Promise<Message>;
|
|
22
29
|
shutdown(): Promise<void>;
|
|
23
30
|
}
|
|
24
|
-
export interface MCPToolBaseOptions<I extends
|
|
31
|
+
export interface MCPToolBaseOptions<I extends Message, O extends Message> extends AgentOptions<I, O> {
|
|
25
32
|
client: Client;
|
|
26
33
|
}
|
|
27
|
-
export declare abstract class MCPBase<I extends
|
|
34
|
+
export declare abstract class MCPBase<I extends Message, O extends Message> extends Agent<I, O> {
|
|
28
35
|
constructor(options: MCPToolBaseOptions<I, O>);
|
|
29
36
|
protected client: Client;
|
|
30
37
|
protected get mcpServer(): string | undefined;
|
|
31
38
|
}
|
|
32
|
-
export declare class MCPTool extends MCPBase<
|
|
33
|
-
process(input:
|
|
39
|
+
export declare class MCPTool extends MCPBase<Message, CallToolResult> {
|
|
40
|
+
process(input: Message): Promise<CallToolResult>;
|
|
34
41
|
}
|
|
35
|
-
export
|
|
42
|
+
export interface MCPPromptInput extends Message {
|
|
36
43
|
[key: string]: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
44
|
+
}
|
|
45
|
+
export declare class MCPPrompt extends MCPBase<MCPPromptInput, GetPromptResult> {
|
|
46
|
+
process(input: MCPPromptInput): Promise<GetPromptResult>;
|
|
47
|
+
}
|
|
48
|
+
export interface MCPResourceOptions extends MCPToolBaseOptions<MCPPromptInput, ReadResourceResult> {
|
|
49
|
+
uri: string;
|
|
50
|
+
}
|
|
51
|
+
export declare class MCPResource extends MCPBase<MCPPromptInput, ReadResourceResult> {
|
|
52
|
+
constructor(options: MCPResourceOptions);
|
|
53
|
+
uri: string;
|
|
54
|
+
process(input: MCPPromptInput): Promise<ReadResourceResult>;
|
|
39
55
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
2
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
3
|
-
import { StdioClientTransport, } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { StdioClientTransport, getDefaultEnvironment, } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
4
|
+
import { UriTemplate } from "@modelcontextprotocol/sdk/shared/uriTemplate.js";
|
|
5
|
+
import { logger } from "../utils/logger.js";
|
|
6
|
+
import { promptFromMCPPrompt, resourceFromMCPResource, toolFromMCPTool, } from "../utils/mcp-utils.js";
|
|
7
|
+
import { createAccessorArray } from "../utils/type-utils.js";
|
|
8
|
+
import { Agent } from "./agent.js";
|
|
8
9
|
const MCP_AGENT_CLIENT_NAME = "MCPAgent";
|
|
9
10
|
const MCP_AGENT_CLIENT_VERSION = "0.0.1";
|
|
10
11
|
const debug = logger.base.extend("mcp");
|
|
@@ -21,7 +22,14 @@ export class MCPAgent extends Agent {
|
|
|
21
22
|
return MCPAgent.fromTransport(transport);
|
|
22
23
|
}
|
|
23
24
|
if (isStdioServerParameters(options)) {
|
|
24
|
-
const transport = new StdioClientTransport({
|
|
25
|
+
const transport = new StdioClientTransport({
|
|
26
|
+
...options,
|
|
27
|
+
env: {
|
|
28
|
+
...getDefaultEnvironment(),
|
|
29
|
+
...options.env,
|
|
30
|
+
},
|
|
31
|
+
stderr: "pipe",
|
|
32
|
+
});
|
|
25
33
|
return MCPAgent.fromTransport(transport);
|
|
26
34
|
}
|
|
27
35
|
return new MCPAgent(options);
|
|
@@ -33,7 +41,7 @@ export class MCPAgent extends Agent {
|
|
|
33
41
|
});
|
|
34
42
|
await debug.spinner(client.connect(transport), "Connecting to MCP server");
|
|
35
43
|
const mcpServer = getMCPServerName(client);
|
|
36
|
-
const { tools: isToolsAvailable, prompts: isPromptsAvailable } = client.getServerCapabilities() ?? {};
|
|
44
|
+
const { tools: isToolsAvailable, prompts: isPromptsAvailable, resources: isResourcesAvailable, } = client.getServerCapabilities() ?? {};
|
|
37
45
|
const tools = isToolsAvailable
|
|
38
46
|
? await debug
|
|
39
47
|
.spinner(client.listTools(), `Listing tools from ${mcpServer}`, ({ tools }) => debug("%O", tools))
|
|
@@ -44,16 +52,42 @@ export class MCPAgent extends Agent {
|
|
|
44
52
|
.spinner(client.listPrompts(), `Listing prompts from ${mcpServer}`, ({ prompts }) => debug("%O", prompts))
|
|
45
53
|
.then(({ prompts }) => prompts.map((prompt) => promptFromMCPPrompt(client, prompt)))
|
|
46
54
|
: undefined;
|
|
47
|
-
|
|
55
|
+
const resources = isResourcesAvailable
|
|
56
|
+
? await debug
|
|
57
|
+
.spinner(
|
|
58
|
+
// TODO: should conditionally call listResourceTemplates based on the server capabilities
|
|
59
|
+
// but the capability is not correct in the current SDK version
|
|
60
|
+
Promise.all([
|
|
61
|
+
client.listResources().catch(() => ({ resources: [] })),
|
|
62
|
+
client.listResourceTemplates().catch(() => ({ resourceTemplates: [] })),
|
|
63
|
+
]), `Listing resources from ${mcpServer}`, ([{ resources }, { resourceTemplates }]) => debug("%O\n%O", resources, resourceTemplates))
|
|
64
|
+
.then(([{ resources }, { resourceTemplates }]) => [...resources, ...resourceTemplates].map((resource) => resourceFromMCPResource(client, resource)))
|
|
65
|
+
: undefined;
|
|
66
|
+
return new MCPAgent({
|
|
67
|
+
name: client.getServerVersion()?.name,
|
|
68
|
+
client,
|
|
69
|
+
tools,
|
|
70
|
+
prompts,
|
|
71
|
+
resources,
|
|
72
|
+
});
|
|
48
73
|
}
|
|
49
74
|
constructor(options) {
|
|
50
75
|
super(options);
|
|
51
76
|
this.client = options.client;
|
|
52
77
|
if (options.prompts?.length)
|
|
53
78
|
this.prompts.push(...options.prompts);
|
|
79
|
+
if (options.resources?.length)
|
|
80
|
+
this.resources.push(...options.resources);
|
|
54
81
|
}
|
|
55
82
|
client;
|
|
56
83
|
prompts = createAccessorArray([], (arr, name) => arr.find((i) => i.name === name));
|
|
84
|
+
resources = createAccessorArray([], (arr, name) => arr.find((i) => i.name === name));
|
|
85
|
+
get isCallable() {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
async process(_input, _context) {
|
|
89
|
+
throw new Error("Method not implemented.");
|
|
90
|
+
}
|
|
57
91
|
async shutdown() {
|
|
58
92
|
super.shutdown();
|
|
59
93
|
await this.client.close();
|
|
@@ -81,6 +115,18 @@ export class MCPPrompt extends MCPBase {
|
|
|
81
115
|
return result;
|
|
82
116
|
}
|
|
83
117
|
}
|
|
118
|
+
export class MCPResource extends MCPBase {
|
|
119
|
+
constructor(options) {
|
|
120
|
+
super(options);
|
|
121
|
+
this.uri = options.uri;
|
|
122
|
+
}
|
|
123
|
+
uri;
|
|
124
|
+
async process(input) {
|
|
125
|
+
const uri = new UriTemplate(this.uri).expand(input);
|
|
126
|
+
const result = await debug.spinner(this.client.readResource({ uri }), `Read resource ${this.name} from ${this.mcpServer}`, (output) => debug("input: %O\noutput: %O", input, output));
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
84
130
|
function getMCPServerName(client) {
|
|
85
131
|
const info = client.getServerVersion();
|
|
86
132
|
if (!info)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Context } from "../execution-engine/context.js";
|
|
2
|
+
import type { Message } from "./agent.js";
|
|
3
|
+
export interface AgentMemoryOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Enable memory, default is true
|
|
6
|
+
*/
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
subscribeTopic?: string | string[];
|
|
9
|
+
maxMemoriesInChat?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface Memory {
|
|
12
|
+
role: "user" | "agent";
|
|
13
|
+
content: Message;
|
|
14
|
+
source?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class AgentMemory {
|
|
17
|
+
constructor(options: AgentMemoryOptions);
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
subscribeTopic?: string | string[];
|
|
20
|
+
maxMemoriesInChat?: number;
|
|
21
|
+
memories: Memory[];
|
|
22
|
+
private subscriptions;
|
|
23
|
+
addMemory(memory: Memory): void;
|
|
24
|
+
attach(context: Context): void;
|
|
25
|
+
detach(): void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { orArrayToArray } from "../utils/type-utils.js";
|
|
2
|
+
export class AgentMemory {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
this.enabled = options.enabled ?? true;
|
|
5
|
+
this.subscribeTopic = options.subscribeTopic;
|
|
6
|
+
this.maxMemoriesInChat = options.maxMemoriesInChat;
|
|
7
|
+
}
|
|
8
|
+
enabled;
|
|
9
|
+
subscribeTopic;
|
|
10
|
+
maxMemoriesInChat;
|
|
11
|
+
memories = [];
|
|
12
|
+
subscriptions = [];
|
|
13
|
+
addMemory(memory) {
|
|
14
|
+
if (this.memories.at(-1)?.content === memory.content)
|
|
15
|
+
return;
|
|
16
|
+
// TODO: save all memories into database instead of in-memory,
|
|
17
|
+
// and give every memory a unique id to avoid duplication
|
|
18
|
+
this.memories.push(memory);
|
|
19
|
+
}
|
|
20
|
+
attach(context) {
|
|
21
|
+
for (const topic of orArrayToArray(this.subscribeTopic)) {
|
|
22
|
+
const sub = context.subscribe(topic, ({ role, message, source }) => {
|
|
23
|
+
this.addMemory({ role, source, content: message });
|
|
24
|
+
});
|
|
25
|
+
this.subscriptions.push(sub);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
detach() {
|
|
29
|
+
for (const sub of this.subscriptions) {
|
|
30
|
+
sub();
|
|
31
|
+
}
|
|
32
|
+
this.subscriptions = [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { Agent,
|
|
1
|
+
import type { Agent, Message } from "./agent.js";
|
|
2
2
|
export declare const transferAgentOutputKey = "$transferAgentTo";
|
|
3
|
-
export interface TransferAgentOutput extends
|
|
3
|
+
export interface TransferAgentOutput extends Message {
|
|
4
4
|
[transferAgentOutputKey]: {
|
|
5
5
|
agent: Agent;
|
|
6
6
|
};
|
|
7
7
|
}
|
|
8
8
|
export declare function transferToAgentOutput(agent: Agent): TransferAgentOutput;
|
|
9
|
-
export declare function isTransferAgentOutput(output:
|
|
9
|
+
export declare function isTransferAgentOutput(output: Message): output is TransferAgentOutput;
|
|
10
|
+
export declare function replaceTransferAgentToName(output: Message): Message;
|
package/lib/esm/agents/types.js
CHANGED
|
@@ -7,5 +7,14 @@ export function transferToAgentOutput(agent) {
|
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
9
|
export function isTransferAgentOutput(output) {
|
|
10
|
-
return transferAgentOutputKey
|
|
10
|
+
return !!output[transferAgentOutputKey]?.agent;
|
|
11
|
+
}
|
|
12
|
+
export function replaceTransferAgentToName(output) {
|
|
13
|
+
if (isTransferAgentOutput(output)) {
|
|
14
|
+
return {
|
|
15
|
+
...output,
|
|
16
|
+
[transferAgentOutputKey]: output[transferAgentOutputKey].agent.name,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return output;
|
|
11
20
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Context } from "../execution-engine/context.js";
|
|
2
|
+
import type { MessagePayload, MessageQueueListener, Unsubscribe } from "../execution-engine/message-queue.js";
|
|
3
|
+
import { type PromiseOrValue } from "../utils/type-utils.js";
|
|
4
|
+
import { Agent, type AgentOptions, type Message } from "./agent.js";
|
|
5
|
+
export interface UserAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
|
|
6
|
+
context?: Context;
|
|
7
|
+
process?: (input: I, context: Context) => PromiseOrValue<O>;
|
|
8
|
+
}
|
|
9
|
+
export declare class UserAgent<I extends Message = Message, O extends Message = Message> extends Agent<I, O> {
|
|
10
|
+
static from<I extends Message, O extends Message>(options: UserAgentOptions<I, O>): UserAgent<I, O>;
|
|
11
|
+
constructor(options: UserAgentOptions<I, O>);
|
|
12
|
+
private context?;
|
|
13
|
+
private get ctx();
|
|
14
|
+
private _process?;
|
|
15
|
+
process(input: I, context?: Context): Promise<O>;
|
|
16
|
+
publish(topic: string | string[], message: Message | string): void;
|
|
17
|
+
subscribe(topic: string, listener?: undefined): Promise<MessagePayload>;
|
|
18
|
+
subscribe(topic: string, listener: MessageQueueListener): Unsubscribe;
|
|
19
|
+
subscribe(topic: string, listener?: MessageQueueListener): Unsubscribe | Promise<MessagePayload>;
|
|
20
|
+
unsubscribe(topic: string, listener: MessageQueueListener): void;
|
|
21
|
+
get stream(): ReadableStream<MessagePayload & {
|
|
22
|
+
topic: string;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { orArrayToArray } from "../utils/type-utils.js";
|
|
2
|
+
import { Agent } from "./agent.js";
|
|
3
|
+
export class UserAgent extends Agent {
|
|
4
|
+
static from(options) {
|
|
5
|
+
return new UserAgent(options);
|
|
6
|
+
}
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super({ ...options, disableLogging: true });
|
|
9
|
+
this._process = options.process;
|
|
10
|
+
this.context = options.context;
|
|
11
|
+
}
|
|
12
|
+
context;
|
|
13
|
+
get ctx() {
|
|
14
|
+
if (!this.context)
|
|
15
|
+
throw new Error("UserAgent must have a context");
|
|
16
|
+
return this.context;
|
|
17
|
+
}
|
|
18
|
+
_process;
|
|
19
|
+
async process(input, context) {
|
|
20
|
+
const ctx = context ?? this.context;
|
|
21
|
+
if (!ctx)
|
|
22
|
+
throw new Error("UserAgent must have a context");
|
|
23
|
+
if (this._process) {
|
|
24
|
+
return this._process(input, ctx);
|
|
25
|
+
}
|
|
26
|
+
const publicTopic = typeof this.publishTopic === "function" ? await this.publishTopic(input) : this.publishTopic;
|
|
27
|
+
if (publicTopic?.length) {
|
|
28
|
+
ctx.publish(publicTopic, input, this);
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
throw new Error("UserAgent must have a process function or a publishTopic");
|
|
32
|
+
}
|
|
33
|
+
publish(topic, message) {
|
|
34
|
+
return this.ctx.publish(topic, message, this);
|
|
35
|
+
}
|
|
36
|
+
subscribe(topic, listener) {
|
|
37
|
+
return this.ctx.subscribe(topic, listener);
|
|
38
|
+
}
|
|
39
|
+
unsubscribe(topic, listener) {
|
|
40
|
+
this.ctx.unsubscribe(topic, listener);
|
|
41
|
+
}
|
|
42
|
+
get stream() {
|
|
43
|
+
let subscriptions = [];
|
|
44
|
+
return new ReadableStream({
|
|
45
|
+
start: (controller) => {
|
|
46
|
+
const subscribeTopic = orArrayToArray(this.subscribeTopic);
|
|
47
|
+
subscriptions = subscribeTopic.map((topic) => this.subscribe(topic, (message) => {
|
|
48
|
+
controller.enqueue({ ...message, topic });
|
|
49
|
+
}));
|
|
50
|
+
},
|
|
51
|
+
cancel: () => {
|
|
52
|
+
for (const unsubscribe of subscriptions) {
|
|
53
|
+
unsubscribe();
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import type EventEmitter from "node:events";
|
|
2
|
-
import type { Agent,
|
|
3
|
-
import type { ChatModel } from "../models/chat";
|
|
2
|
+
import type { Agent, FunctionAgentFn, Message } from "../agents/agent.js";
|
|
3
|
+
import type { ChatModel } from "../models/chat-model.js";
|
|
4
|
+
import type { MessagePayload, MessageQueueListener, Unsubscribe } from "./message-queue.js";
|
|
5
|
+
export type Runnable<I extends Message = Message, O extends Message = Message> = Agent<I, O> | FunctionAgentFn;
|
|
4
6
|
export interface Context extends EventEmitter {
|
|
5
7
|
model?: ChatModel;
|
|
6
8
|
tools?: Agent[];
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Call an agent with a message
|
|
11
|
+
* @param agent Agent to call
|
|
12
|
+
* @param message Message to pass to the agent
|
|
13
|
+
* @returns the output of the agent
|
|
14
|
+
*/
|
|
15
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string): Promise<O>;
|
|
16
|
+
/**
|
|
17
|
+
* Call an agent with a message and return the output and the active agent
|
|
18
|
+
* @param agent Agent to call
|
|
19
|
+
* @param message Message to pass to the agent
|
|
20
|
+
* @param options.returnActiveAgent return the active agent
|
|
21
|
+
* @returns the output of the agent and the final active agent
|
|
22
|
+
*/
|
|
23
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options: {
|
|
24
|
+
returnActiveAgent?: true;
|
|
25
|
+
}): Promise<[O, Runnable]>;
|
|
26
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options?: {
|
|
27
|
+
returnActiveAgent?: boolean;
|
|
28
|
+
}): Promise<O | [O, Runnable]>;
|
|
29
|
+
/**
|
|
30
|
+
* Publish a message to a topic, the engine will call the listeners of the topic
|
|
31
|
+
* @param topic topic name, or an array of topic names
|
|
32
|
+
* @param message message to publish
|
|
33
|
+
* @param from the agent who publish the message, if not provided, it will be treated as a user message
|
|
34
|
+
*/
|
|
35
|
+
publish(topic: string | string[], message: Message | string, from?: Agent): void;
|
|
36
|
+
subscribe(topic: string, listener?: undefined): Promise<MessagePayload>;
|
|
37
|
+
subscribe(topic: string, listener: MessageQueueListener): Unsubscribe;
|
|
38
|
+
subscribe(topic: string, listener?: MessageQueueListener): Unsubscribe | Promise<MessagePayload>;
|
|
39
|
+
unsubscribe(topic: string, listener: MessageQueueListener): void;
|
|
10
40
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import EventEmitter from "node:events";
|
|
2
|
+
import { Agent, type Message } from "../agents/agent.js";
|
|
3
|
+
import { UserAgent } from "../agents/user-agent.js";
|
|
4
|
+
import type { ChatModel } from "../models/chat-model.js";
|
|
5
|
+
import type { Context, Runnable } from "./context.js";
|
|
6
|
+
import { type MessagePayload, MessageQueue, type MessageQueueListener, type Unsubscribe } from "./message-queue.js";
|
|
7
|
+
export interface ExecutionEngineOptions {
|
|
8
|
+
model?: ChatModel;
|
|
9
|
+
tools?: Agent[];
|
|
10
|
+
agents?: Agent[];
|
|
11
|
+
}
|
|
12
|
+
export declare class ExecutionEngine extends EventEmitter implements Context {
|
|
13
|
+
constructor(options?: ExecutionEngineOptions);
|
|
14
|
+
readonly messageQueue: MessageQueue;
|
|
15
|
+
model?: ChatModel;
|
|
16
|
+
tools: Agent[];
|
|
17
|
+
private agents;
|
|
18
|
+
addAgent(...agents: Agent[]): void;
|
|
19
|
+
private createMessageFromInput;
|
|
20
|
+
/**
|
|
21
|
+
* Publish a message to a topic, the engine will call the listeners of the topic
|
|
22
|
+
* @param topic topic name, or an array of topic names
|
|
23
|
+
* @param message message to publish
|
|
24
|
+
* @param from the agent who publish the message, if not provided, it will be treated as a user message
|
|
25
|
+
*/
|
|
26
|
+
publish(topic: string | string[], message: Message | string, from?: Agent): void;
|
|
27
|
+
/**
|
|
28
|
+
* Create a user agent to consistently call an agent
|
|
29
|
+
* @param agent Agent to call
|
|
30
|
+
* @returns User agent
|
|
31
|
+
*/
|
|
32
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>): UserAgent<I, O>;
|
|
33
|
+
/**
|
|
34
|
+
* Call an agent with a message
|
|
35
|
+
* @param agent Agent to call
|
|
36
|
+
* @param message Message to pass to the agent
|
|
37
|
+
* @returns the output of the agent
|
|
38
|
+
*/
|
|
39
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string): Promise<O>;
|
|
40
|
+
/**
|
|
41
|
+
* Call an agent with a message and return the output and the active agent
|
|
42
|
+
* @param agent Agent to call
|
|
43
|
+
* @param message Message to pass to the agent
|
|
44
|
+
* @param options.returnActiveAgent return the active agent
|
|
45
|
+
* @returns the output of the agent and the final active agent
|
|
46
|
+
*/
|
|
47
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options: {
|
|
48
|
+
returnActiveAgent?: true;
|
|
49
|
+
}): Promise<[O, Runnable]>;
|
|
50
|
+
/**
|
|
51
|
+
* Call an agent with a message and return the output and the active agent
|
|
52
|
+
* @param agent Agent to call
|
|
53
|
+
* @param message Message to pass to the agent
|
|
54
|
+
* @returns the output of the agent and the final active agent
|
|
55
|
+
*/
|
|
56
|
+
private _call;
|
|
57
|
+
subscribe(topic: string, listener?: undefined): Promise<MessagePayload>;
|
|
58
|
+
subscribe(topic: string, listener: MessageQueueListener): Unsubscribe;
|
|
59
|
+
subscribe(topic: string, listener?: MessageQueueListener): Unsubscribe | Promise<MessagePayload>;
|
|
60
|
+
unsubscribe(topic: string, listener: MessageQueueListener): void;
|
|
61
|
+
private callAgent;
|
|
62
|
+
shutdown(): Promise<void>;
|
|
63
|
+
private initProcessExitHandler;
|
|
64
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import EventEmitter from "node:events";
|
|
2
|
+
import { isNil } from "lodash-es";
|
|
3
|
+
import { Agent } from "../agents/agent.js";
|
|
4
|
+
import { isTransferAgentOutput, transferAgentOutputKey } from "../agents/types.js";
|
|
5
|
+
import { UserAgent } from "../agents/user-agent.js";
|
|
6
|
+
import { createMessage } from "../prompt/prompt-builder.js";
|
|
7
|
+
import { MessageQueue, } from "./message-queue.js";
|
|
8
|
+
export class ExecutionEngine extends EventEmitter {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super();
|
|
11
|
+
this.model = options?.model;
|
|
12
|
+
this.tools = options?.tools ?? [];
|
|
13
|
+
if (options?.agents?.length)
|
|
14
|
+
this.addAgent(...options.agents);
|
|
15
|
+
this.initProcessExitHandler();
|
|
16
|
+
}
|
|
17
|
+
messageQueue = new MessageQueue();
|
|
18
|
+
model;
|
|
19
|
+
tools;
|
|
20
|
+
agents = [];
|
|
21
|
+
addAgent(...agents) {
|
|
22
|
+
for (const agent of agents) {
|
|
23
|
+
this.agents.push(agent);
|
|
24
|
+
agent.attach(this);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
createMessageFromInput(message) {
|
|
28
|
+
return typeof message === "string" ? createMessage(message) : message;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Publish a message to a topic, the engine will call the listeners of the topic
|
|
32
|
+
* @param topic topic name, or an array of topic names
|
|
33
|
+
* @param message message to publish
|
|
34
|
+
* @param from the agent who publish the message, if not provided, it will be treated as a user message
|
|
35
|
+
*/
|
|
36
|
+
publish(topic, message, from) {
|
|
37
|
+
const request = {
|
|
38
|
+
role: !from || from instanceof UserAgent ? "user" : "agent",
|
|
39
|
+
source: from?.name,
|
|
40
|
+
message: this.createMessageFromInput(message),
|
|
41
|
+
};
|
|
42
|
+
this.messageQueue.publish(topic, request);
|
|
43
|
+
}
|
|
44
|
+
call(agent, message, options) {
|
|
45
|
+
if (isNil(message)) {
|
|
46
|
+
let activeAgent = agent;
|
|
47
|
+
return UserAgent.from({
|
|
48
|
+
context: this,
|
|
49
|
+
process: async (input, context) => {
|
|
50
|
+
const [output, agent] = await context.call(activeAgent, input, {
|
|
51
|
+
returnActiveAgent: true,
|
|
52
|
+
});
|
|
53
|
+
activeAgent = agent;
|
|
54
|
+
return output;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return this._call(agent, this.createMessageFromInput(message)).then((result) => options?.returnActiveAgent ? [result.output, result.agent] : result.output);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Call an agent with a message and return the output and the active agent
|
|
62
|
+
* @param agent Agent to call
|
|
63
|
+
* @param message Message to pass to the agent
|
|
64
|
+
* @returns the output of the agent and the final active agent
|
|
65
|
+
*/
|
|
66
|
+
async _call(agent, message) {
|
|
67
|
+
const { output, agent: activeAgent } = await this.callAgent(agent, message);
|
|
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
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { output, agent: activeAgent };
|
|
77
|
+
}
|
|
78
|
+
subscribe(topic, listener) {
|
|
79
|
+
return this.messageQueue.subscribe(topic, listener);
|
|
80
|
+
}
|
|
81
|
+
unsubscribe(topic, listener) {
|
|
82
|
+
this.messageQueue.unsubscribe(topic, listener);
|
|
83
|
+
}
|
|
84
|
+
async callAgent(agent, input) {
|
|
85
|
+
let activeAgent = agent;
|
|
86
|
+
let output;
|
|
87
|
+
for (;;) {
|
|
88
|
+
let result;
|
|
89
|
+
if (typeof activeAgent === "function") {
|
|
90
|
+
result = await activeAgent(input, this);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
result = await activeAgent.call(input, this);
|
|
94
|
+
}
|
|
95
|
+
if (!(result instanceof Agent))
|
|
96
|
+
output = result;
|
|
97
|
+
const transferToAgent = result instanceof Agent
|
|
98
|
+
? result
|
|
99
|
+
: isTransferAgentOutput(result)
|
|
100
|
+
? result[transferAgentOutputKey].agent
|
|
101
|
+
: undefined;
|
|
102
|
+
if (transferToAgent) {
|
|
103
|
+
activeAgent = transferToAgent;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!output)
|
|
110
|
+
throw new Error("Unexpected empty output");
|
|
111
|
+
return {
|
|
112
|
+
agent: activeAgent,
|
|
113
|
+
output,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
async shutdown() {
|
|
117
|
+
for (const tool of this.tools) {
|
|
118
|
+
await tool.shutdown();
|
|
119
|
+
}
|
|
120
|
+
for (const agent of this.agents) {
|
|
121
|
+
await agent.shutdown();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
initProcessExitHandler() {
|
|
125
|
+
const shutdownAndExit = () => this.shutdown().finally(() => process.exit(0));
|
|
126
|
+
process.on("SIGINT", shutdownAndExit);
|
|
127
|
+
process.on("exit", shutdownAndExit);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -1,46 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface ExecutionEngineOptions {
|
|
6
|
-
model?: ChatModel;
|
|
7
|
-
tools?: Agent[];
|
|
8
|
-
agents?: Agent[];
|
|
9
|
-
}
|
|
10
|
-
export interface ExecutionEngineRunOptions {
|
|
11
|
-
concurrency?: boolean;
|
|
12
|
-
}
|
|
13
|
-
export declare class ExecutionEngine extends EventEmitter implements Context {
|
|
14
|
-
constructor(options?: ExecutionEngineOptions);
|
|
15
|
-
private messageQueue;
|
|
16
|
-
model?: ChatModel;
|
|
17
|
-
tools: Agent[];
|
|
18
|
-
private agents;
|
|
19
|
-
private agentListeners;
|
|
20
|
-
addAgent(...agents: Agent[]): void;
|
|
21
|
-
private attachAgentSubscriptions;
|
|
22
|
-
publish(topic: string, message: unknown): void;
|
|
23
|
-
subscribe(topic: string, listener: (message: AgentOutput) => void): void;
|
|
24
|
-
unsubscribe(topic: string, listener: (message: AgentOutput) => void): void;
|
|
25
|
-
run(agent: Agent): Promise<UserAgent>;
|
|
26
|
-
run(input: AgentInput | string): Promise<AgentOutput>;
|
|
27
|
-
run(input: AgentInput | string, ...agents: Agent[]): Promise<AgentOutput>;
|
|
28
|
-
run(input: AgentInput | string, options: ExecutionEngineRunOptions, ...agents: Agent[]): Promise<AgentOutput>;
|
|
29
|
-
private splitOptionsAndAgents;
|
|
30
|
-
private runSequential;
|
|
31
|
-
private runParallel;
|
|
32
|
-
private publishUserInputTopic;
|
|
33
|
-
private runChatLoop;
|
|
34
|
-
private callAgent;
|
|
35
|
-
shutdown(): Promise<void>;
|
|
36
|
-
private initProcessExitHandler;
|
|
37
|
-
}
|
|
38
|
-
export declare class UserAgent<I extends AgentInput = AgentInput, O extends AgentOutput = AgentOutput> extends Agent<I, O> {
|
|
39
|
-
options: AgentOptions<I, O> & {
|
|
40
|
-
run: (input: I) => Promise<O>;
|
|
41
|
-
};
|
|
42
|
-
constructor(options: AgentOptions<I, O> & {
|
|
43
|
-
run: (input: I) => Promise<O>;
|
|
44
|
-
});
|
|
45
|
-
process(input: I): Promise<O>;
|
|
46
|
-
}
|
|
1
|
+
export * from "./context.js";
|
|
2
|
+
export * from "./execution-engine.js";
|
|
3
|
+
export * from "./message-queue.js";
|
|
4
|
+
export * from "./utils.js";
|