opc-agent 1.3.2 → 2.0.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/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +14 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +13 -0
- package/.github/workflows/ci.yml +24 -0
- package/CHANGELOG.md +48 -63
- package/CONTRIBUTING.md +21 -60
- package/README.md +284 -348
- package/README.zh-CN.md +415 -415
- package/dist/channels/slack.js +93 -10
- package/dist/channels/telegram.d.ts +30 -9
- package/dist/channels/telegram.js +125 -33
- package/dist/channels/web.d.ts +10 -0
- package/dist/channels/web.js +33 -2
- package/dist/cli.js +667 -65
- package/dist/core/agent.d.ts +23 -0
- package/dist/core/agent.js +120 -3
- package/dist/core/runtime.d.ts +5 -0
- package/dist/core/runtime.js +71 -0
- package/dist/core/scheduler.d.ts +52 -0
- package/dist/core/scheduler.js +168 -0
- package/dist/core/subagent.d.ts +28 -0
- package/dist/core/subagent.js +65 -0
- package/dist/daemon.d.ts +3 -0
- package/dist/daemon.js +134 -0
- package/dist/deploy/hermes.js +22 -22
- package/dist/deploy/openclaw.js +31 -40
- package/dist/index.d.ts +10 -10
- package/dist/index.js +22 -15
- package/dist/providers/index.d.ts +6 -2
- package/dist/providers/index.js +22 -9
- package/dist/schema/oad.d.ts +180 -6
- package/dist/schema/oad.js +12 -1
- package/dist/skills/auto-learn.d.ts +28 -0
- package/dist/skills/auto-learn.js +257 -0
- package/dist/templates/code-reviewer.d.ts +0 -8
- package/dist/templates/code-reviewer.js +5 -9
- package/dist/templates/customer-service.d.ts +0 -8
- package/dist/templates/customer-service.js +2 -6
- package/dist/templates/data-analyst.d.ts +0 -8
- package/dist/templates/data-analyst.js +5 -9
- package/dist/templates/knowledge-base.d.ts +0 -8
- package/dist/templates/knowledge-base.js +2 -6
- package/dist/templates/sales-assistant.d.ts +0 -8
- package/dist/templates/sales-assistant.js +4 -8
- package/dist/templates/teacher.d.ts +0 -8
- package/dist/templates/teacher.js +6 -10
- package/dist/tools/builtin/datetime.d.ts +3 -0
- package/dist/tools/builtin/datetime.js +44 -0
- package/dist/tools/builtin/file.d.ts +3 -0
- package/dist/tools/builtin/file.js +151 -0
- package/dist/tools/builtin/index.d.ts +15 -0
- package/dist/tools/builtin/index.js +30 -0
- package/dist/tools/builtin/shell.d.ts +3 -0
- package/dist/tools/builtin/shell.js +43 -0
- package/dist/tools/builtin/web.d.ts +3 -0
- package/dist/tools/builtin/web.js +37 -0
- package/dist/tools/mcp-client.d.ts +24 -0
- package/dist/tools/mcp-client.js +119 -0
- package/dist/traces/index.d.ts +49 -0
- package/dist/traces/index.js +102 -0
- package/docs/.vitepress/config.ts +103 -103
- package/docs/api/cli.md +48 -48
- package/docs/api/oad-schema.md +64 -64
- package/docs/api/sdk.md +80 -80
- package/docs/guide/concepts.md +51 -51
- package/docs/guide/configuration.md +79 -79
- package/docs/guide/deployment.md +42 -42
- package/docs/guide/getting-started.md +44 -44
- package/docs/guide/templates.md +28 -28
- package/docs/guide/testing.md +84 -84
- package/docs/index.md +27 -27
- package/docs/zh/api/cli.md +54 -54
- package/docs/zh/api/oad-schema.md +87 -87
- package/docs/zh/api/sdk.md +102 -102
- package/docs/zh/guide/concepts.md +104 -104
- package/docs/zh/guide/configuration.md +135 -135
- package/docs/zh/guide/deployment.md +81 -81
- package/docs/zh/guide/getting-started.md +82 -82
- package/docs/zh/guide/templates.md +84 -84
- package/docs/zh/guide/testing.md +88 -88
- package/docs/zh/index.md +27 -27
- package/examples/README.md +22 -0
- package/examples/basic-agent.ts +90 -0
- package/examples/brain-integration.ts +71 -0
- package/examples/customer-service-demo/README.md +90 -90
- package/examples/customer-service-demo/oad.yaml +107 -107
- package/examples/multi-channel.ts +74 -0
- package/package.json +1 -1
- package/src/analytics/index.ts +66 -66
- package/src/channels/discord.ts +192 -192
- package/src/channels/email.ts +177 -177
- package/src/channels/feishu.ts +236 -236
- package/src/channels/index.ts +15 -15
- package/src/channels/slack.ts +217 -160
- package/src/channels/telegram.ts +155 -33
- package/src/channels/voice.ts +106 -106
- package/src/channels/web.ts +38 -2
- package/src/channels/webhook.ts +199 -199
- package/src/channels/websocket.ts +87 -87
- package/src/channels/wechat.ts +149 -149
- package/src/cli.ts +697 -63
- package/src/core/a2a.ts +143 -143
- package/src/core/agent.ts +146 -3
- package/src/core/analytics-engine.ts +186 -186
- package/src/core/auth.ts +57 -57
- package/src/core/cache.ts +141 -141
- package/src/core/compose.ts +77 -77
- package/src/core/config.ts +14 -14
- package/src/core/errors.ts +148 -148
- package/src/core/hitl.ts +138 -138
- package/src/core/logger.ts +57 -57
- package/src/core/orchestrator.ts +215 -215
- package/src/core/performance.ts +187 -187
- package/src/core/rate-limiter.ts +128 -128
- package/src/core/room.ts +109 -109
- package/src/core/runtime.ts +230 -152
- package/src/core/sandbox.ts +101 -101
- package/src/core/scheduler.ts +187 -0
- package/src/core/security.ts +171 -171
- package/src/core/subagent.ts +98 -0
- package/src/core/types.ts +68 -68
- package/src/core/versioning.ts +106 -106
- package/src/core/watch.ts +178 -178
- package/src/core/workflow.ts +235 -235
- package/src/daemon.ts +96 -0
- package/src/deploy/hermes.ts +156 -156
- package/src/deploy/openclaw.ts +190 -200
- package/src/i18n/index.ts +216 -216
- package/src/index.ts +14 -10
- package/src/memory/deepbrain.ts +108 -108
- package/src/memory/index.ts +34 -34
- package/src/plugins/index.ts +208 -208
- package/src/providers/index.ts +354 -331
- package/src/schema/oad.ts +14 -2
- package/src/skills/auto-learn.ts +262 -0
- package/src/skills/base.ts +16 -16
- package/src/skills/document.ts +100 -100
- package/src/skills/http.ts +35 -35
- package/src/skills/index.ts +27 -27
- package/src/skills/scheduler.ts +80 -80
- package/src/skills/webhook-trigger.ts +59 -59
- package/src/templates/code-reviewer.ts +30 -34
- package/src/templates/customer-service.ts +76 -80
- package/src/templates/data-analyst.ts +66 -70
- package/src/templates/executive-assistant.ts +71 -71
- package/src/templates/financial-advisor.ts +60 -60
- package/src/templates/knowledge-base.ts +27 -31
- package/src/templates/legal-assistant.ts +71 -71
- package/src/templates/sales-assistant.ts +75 -79
- package/src/templates/teacher.ts +75 -79
- package/src/testing/index.ts +181 -181
- package/src/tools/builtin/datetime.ts +41 -0
- package/src/tools/builtin/file.ts +107 -0
- package/src/tools/builtin/index.ts +28 -0
- package/src/tools/builtin/shell.ts +43 -0
- package/src/tools/builtin/web.ts +35 -0
- package/src/tools/calculator.ts +73 -73
- package/src/tools/datetime.ts +149 -149
- package/src/tools/json-transform.ts +187 -187
- package/src/tools/mcp-client.ts +131 -0
- package/src/tools/mcp.ts +76 -76
- package/src/tools/text-analysis.ts +116 -116
- package/src/traces/index.ts +132 -0
- package/templates/Dockerfile +15 -15
- package/templates/code-reviewer/README.md +27 -27
- package/templates/code-reviewer/oad.yaml +41 -41
- package/templates/customer-service/README.md +22 -22
- package/templates/customer-service/oad.yaml +36 -36
- package/templates/docker-compose.yml +21 -21
- package/templates/ecommerce-assistant/README.md +45 -45
- package/templates/ecommerce-assistant/oad.yaml +47 -47
- package/templates/knowledge-base/README.md +28 -28
- package/templates/knowledge-base/oad.yaml +38 -38
- package/templates/sales-assistant/README.md +26 -26
- package/templates/sales-assistant/oad.yaml +43 -43
- package/templates/tech-support/README.md +43 -43
- package/templates/tech-support/oad.yaml +45 -45
- package/test-agent/Dockerfile +9 -0
- package/test-agent/README.md +50 -0
- package/test-agent/agent.yaml +23 -0
- package/test-agent/docker-compose.yml +11 -0
- package/test-agent/oad.yaml +31 -0
- package/test-agent/package-lock.json +1492 -0
- package/test-agent/package.json +18 -0
- package/test-agent/src/index.ts +24 -0
- package/test-agent/src/skills/echo.ts +15 -0
- package/test-agent/tsconfig.json +25 -0
- package/tests/a2a.test.ts +66 -66
- package/tests/agent.test.ts +72 -72
- package/tests/analytics.test.ts +50 -50
- package/tests/auto-learn.test.ts +105 -0
- package/tests/builtin-tools.test.ts +83 -0
- package/tests/channel.test.ts +39 -39
- package/tests/cli.test.ts +46 -0
- package/tests/e2e.test.ts +134 -134
- package/tests/errors.test.ts +83 -83
- package/tests/hitl.test.ts +71 -71
- package/tests/i18n.test.ts +41 -41
- package/tests/mcp.test.ts +54 -54
- package/tests/oad.test.ts +68 -68
- package/tests/performance.test.ts +115 -115
- package/tests/plugin.test.ts +74 -74
- package/tests/room.test.ts +106 -106
- package/tests/runtime.test.ts +42 -42
- package/tests/sandbox.test.ts +46 -46
- package/tests/security.test.ts +60 -60
- package/tests/subagent.test.ts +130 -0
- package/tests/telegram-discord.test.ts +60 -0
- package/tests/templates.test.ts +77 -77
- package/tests/v070.test.ts +76 -76
- package/tests/versioning.test.ts +75 -75
- package/tests/voice.test.ts +61 -61
- package/tests/webhook.test.ts +29 -29
- package/tests/workflow.test.ts +143 -143
- package/tsconfig.json +19 -19
- package/vitest.config.ts +9 -9
- package/dist/core/dashboard.d.ts +0 -35
- package/dist/core/dashboard.js +0 -157
- package/dist/core/priority.d.ts +0 -52
- package/dist/core/priority.js +0 -102
- package/src/core/dashboard.ts +0 -219
- package/src/core/priority.ts +0 -140
- package/src/dtv/data.ts +0 -29
- package/src/dtv/trust.ts +0 -43
- package/src/dtv/value.ts +0 -47
- package/src/marketplace/index.ts +0 -223
package/src/core/a2a.ts
CHANGED
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import { Room } from './room';
|
|
3
|
-
import type { Message, IAgent } from './types';
|
|
4
|
-
import { Logger } from './logger';
|
|
5
|
-
|
|
6
|
-
// ── A2A Types ───────────────────────────────────────────────
|
|
7
|
-
|
|
8
|
-
export interface AgentCapability {
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
inputSchema?: Record<string, unknown>;
|
|
12
|
-
outputSchema?: Record<string, unknown>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface AgentRegistration {
|
|
16
|
-
agentName: string;
|
|
17
|
-
capabilities: AgentCapability[];
|
|
18
|
-
endpoint?: string;
|
|
19
|
-
metadata?: Record<string, unknown>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface A2ARequest {
|
|
23
|
-
id: string;
|
|
24
|
-
from: string;
|
|
25
|
-
to: string;
|
|
26
|
-
capability: string;
|
|
27
|
-
payload: string;
|
|
28
|
-
timestamp: number;
|
|
29
|
-
timeout?: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface A2AResponse {
|
|
33
|
-
requestId: string;
|
|
34
|
-
from: string;
|
|
35
|
-
status: 'success' | 'error' | 'timeout';
|
|
36
|
-
payload?: string;
|
|
37
|
-
error?: string;
|
|
38
|
-
timestamp: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ── Agent Registry ──────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
export class AgentRegistry extends EventEmitter {
|
|
44
|
-
private registrations: Map<string, AgentRegistration> = new Map();
|
|
45
|
-
private agents: Map<string, IAgent> = new Map();
|
|
46
|
-
private room: Room;
|
|
47
|
-
private logger = new Logger('a2a');
|
|
48
|
-
|
|
49
|
-
constructor(room?: Room) {
|
|
50
|
-
super();
|
|
51
|
-
this.room = room ?? new Room('a2a-default');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
register(agent: IAgent, capabilities: AgentCapability[]): void {
|
|
55
|
-
const reg: AgentRegistration = { agentName: agent.name, capabilities };
|
|
56
|
-
this.registrations.set(agent.name, reg);
|
|
57
|
-
this.agents.set(agent.name, agent);
|
|
58
|
-
this.room.addAgent(agent);
|
|
59
|
-
this.logger.info('Agent registered', { name: agent.name, capabilities: capabilities.map(c => c.name) });
|
|
60
|
-
this.emit('agent:registered', reg);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
unregister(name: string): void {
|
|
64
|
-
this.registrations.delete(name);
|
|
65
|
-
this.agents.delete(name);
|
|
66
|
-
this.room.removeAgent(name);
|
|
67
|
-
this.emit('agent:unregistered', name);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
discover(capability?: string): AgentRegistration[] {
|
|
71
|
-
const all = Array.from(this.registrations.values());
|
|
72
|
-
if (!capability) return all;
|
|
73
|
-
return all.filter(r => r.capabilities.some(c => c.name === capability));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
getAgent(name: string): IAgent | undefined {
|
|
77
|
-
return this.agents.get(name);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async request(req: A2ARequest): Promise<A2AResponse> {
|
|
81
|
-
const agent = this.agents.get(req.to);
|
|
82
|
-
if (!agent) {
|
|
83
|
-
return {
|
|
84
|
-
requestId: req.id,
|
|
85
|
-
from: req.to,
|
|
86
|
-
status: 'error',
|
|
87
|
-
error: `Agent "${req.to}" not found`,
|
|
88
|
-
timestamp: Date.now(),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const message: Message = {
|
|
93
|
-
id: req.id,
|
|
94
|
-
role: 'user',
|
|
95
|
-
content: req.payload,
|
|
96
|
-
timestamp: req.timestamp,
|
|
97
|
-
metadata: { a2a: true, from: req.from, capability: req.capability },
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
this.emit('request', req);
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
const timeoutMs = req.timeout ?? 30000;
|
|
104
|
-
const response = await Promise.race([
|
|
105
|
-
agent.handleMessage(message),
|
|
106
|
-
new Promise<never>((_, reject) =>
|
|
107
|
-
setTimeout(() => reject(new Error('A2A request timeout')), timeoutMs),
|
|
108
|
-
),
|
|
109
|
-
]);
|
|
110
|
-
|
|
111
|
-
const res: A2AResponse = {
|
|
112
|
-
requestId: req.id,
|
|
113
|
-
from: req.to,
|
|
114
|
-
status: 'success',
|
|
115
|
-
payload: response.content,
|
|
116
|
-
timestamp: Date.now(),
|
|
117
|
-
};
|
|
118
|
-
this.emit('response', res);
|
|
119
|
-
return res;
|
|
120
|
-
} catch (err) {
|
|
121
|
-
const res: A2AResponse = {
|
|
122
|
-
requestId: req.id,
|
|
123
|
-
from: req.to,
|
|
124
|
-
status: (err as Error).message.includes('timeout') ? 'timeout' : 'error',
|
|
125
|
-
error: (err as Error).message,
|
|
126
|
-
timestamp: Date.now(),
|
|
127
|
-
};
|
|
128
|
-
this.emit('response', res);
|
|
129
|
-
return res;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async call(from: string, to: string, capability: string, payload: string): Promise<A2AResponse> {
|
|
134
|
-
return this.request({
|
|
135
|
-
id: `a2a_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
136
|
-
from,
|
|
137
|
-
to,
|
|
138
|
-
capability,
|
|
139
|
-
payload,
|
|
140
|
-
timestamp: Date.now(),
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Room } from './room';
|
|
3
|
+
import type { Message, IAgent } from './types';
|
|
4
|
+
import { Logger } from './logger';
|
|
5
|
+
|
|
6
|
+
// ── A2A Types ───────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
export interface AgentCapability {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
inputSchema?: Record<string, unknown>;
|
|
12
|
+
outputSchema?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AgentRegistration {
|
|
16
|
+
agentName: string;
|
|
17
|
+
capabilities: AgentCapability[];
|
|
18
|
+
endpoint?: string;
|
|
19
|
+
metadata?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface A2ARequest {
|
|
23
|
+
id: string;
|
|
24
|
+
from: string;
|
|
25
|
+
to: string;
|
|
26
|
+
capability: string;
|
|
27
|
+
payload: string;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface A2AResponse {
|
|
33
|
+
requestId: string;
|
|
34
|
+
from: string;
|
|
35
|
+
status: 'success' | 'error' | 'timeout';
|
|
36
|
+
payload?: string;
|
|
37
|
+
error?: string;
|
|
38
|
+
timestamp: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── Agent Registry ──────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
export class AgentRegistry extends EventEmitter {
|
|
44
|
+
private registrations: Map<string, AgentRegistration> = new Map();
|
|
45
|
+
private agents: Map<string, IAgent> = new Map();
|
|
46
|
+
private room: Room;
|
|
47
|
+
private logger = new Logger('a2a');
|
|
48
|
+
|
|
49
|
+
constructor(room?: Room) {
|
|
50
|
+
super();
|
|
51
|
+
this.room = room ?? new Room('a2a-default');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
register(agent: IAgent, capabilities: AgentCapability[]): void {
|
|
55
|
+
const reg: AgentRegistration = { agentName: agent.name, capabilities };
|
|
56
|
+
this.registrations.set(agent.name, reg);
|
|
57
|
+
this.agents.set(agent.name, agent);
|
|
58
|
+
this.room.addAgent(agent);
|
|
59
|
+
this.logger.info('Agent registered', { name: agent.name, capabilities: capabilities.map(c => c.name) });
|
|
60
|
+
this.emit('agent:registered', reg);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
unregister(name: string): void {
|
|
64
|
+
this.registrations.delete(name);
|
|
65
|
+
this.agents.delete(name);
|
|
66
|
+
this.room.removeAgent(name);
|
|
67
|
+
this.emit('agent:unregistered', name);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
discover(capability?: string): AgentRegistration[] {
|
|
71
|
+
const all = Array.from(this.registrations.values());
|
|
72
|
+
if (!capability) return all;
|
|
73
|
+
return all.filter(r => r.capabilities.some(c => c.name === capability));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getAgent(name: string): IAgent | undefined {
|
|
77
|
+
return this.agents.get(name);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async request(req: A2ARequest): Promise<A2AResponse> {
|
|
81
|
+
const agent = this.agents.get(req.to);
|
|
82
|
+
if (!agent) {
|
|
83
|
+
return {
|
|
84
|
+
requestId: req.id,
|
|
85
|
+
from: req.to,
|
|
86
|
+
status: 'error',
|
|
87
|
+
error: `Agent "${req.to}" not found`,
|
|
88
|
+
timestamp: Date.now(),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const message: Message = {
|
|
93
|
+
id: req.id,
|
|
94
|
+
role: 'user',
|
|
95
|
+
content: req.payload,
|
|
96
|
+
timestamp: req.timestamp,
|
|
97
|
+
metadata: { a2a: true, from: req.from, capability: req.capability },
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
this.emit('request', req);
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const timeoutMs = req.timeout ?? 30000;
|
|
104
|
+
const response = await Promise.race([
|
|
105
|
+
agent.handleMessage(message),
|
|
106
|
+
new Promise<never>((_, reject) =>
|
|
107
|
+
setTimeout(() => reject(new Error('A2A request timeout')), timeoutMs),
|
|
108
|
+
),
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
const res: A2AResponse = {
|
|
112
|
+
requestId: req.id,
|
|
113
|
+
from: req.to,
|
|
114
|
+
status: 'success',
|
|
115
|
+
payload: response.content,
|
|
116
|
+
timestamp: Date.now(),
|
|
117
|
+
};
|
|
118
|
+
this.emit('response', res);
|
|
119
|
+
return res;
|
|
120
|
+
} catch (err) {
|
|
121
|
+
const res: A2AResponse = {
|
|
122
|
+
requestId: req.id,
|
|
123
|
+
from: req.to,
|
|
124
|
+
status: (err as Error).message.includes('timeout') ? 'timeout' : 'error',
|
|
125
|
+
error: (err as Error).message,
|
|
126
|
+
timestamp: Date.now(),
|
|
127
|
+
};
|
|
128
|
+
this.emit('response', res);
|
|
129
|
+
return res;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async call(from: string, to: string, capability: string, payload: string): Promise<A2AResponse> {
|
|
134
|
+
return this.request({
|
|
135
|
+
id: `a2a_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
136
|
+
from,
|
|
137
|
+
to,
|
|
138
|
+
capability,
|
|
139
|
+
payload,
|
|
140
|
+
timestamp: Date.now(),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
package/src/core/agent.ts
CHANGED
|
@@ -2,6 +2,10 @@ import { EventEmitter } from 'events';
|
|
|
2
2
|
import type { AgentState, IAgent, IChannel, ISkill, Message, MemoryStore, AgentContext } from './types';
|
|
3
3
|
import { InMemoryStore } from '../memory';
|
|
4
4
|
import { createProvider, type LLMProvider } from '../providers';
|
|
5
|
+
import { SkillLearner } from '../skills/auto-learn';
|
|
6
|
+
import type { MCPTool } from '../tools/mcp';
|
|
7
|
+
import { MCPToolRegistry } from '../tools/mcp';
|
|
8
|
+
import { SubAgentManager, type SubAgentConfig, type SubAgentResult } from './subagent';
|
|
5
9
|
|
|
6
10
|
export class BaseAgent extends EventEmitter implements IAgent {
|
|
7
11
|
readonly name: string;
|
|
@@ -12,6 +16,11 @@ export class BaseAgent extends EventEmitter implements IAgent {
|
|
|
12
16
|
private _provider: LLMProvider;
|
|
13
17
|
private systemPrompt: string;
|
|
14
18
|
private historyLimit: number;
|
|
19
|
+
private toolRegistry: MCPToolRegistry = new MCPToolRegistry();
|
|
20
|
+
private maxToolRounds: number;
|
|
21
|
+
private skillLearner?: SkillLearner;
|
|
22
|
+
private autoLearnConfig: { enabled: boolean; minConversationLength: number; improveOnUse: boolean };
|
|
23
|
+
private _subAgentManager?: SubAgentManager;
|
|
15
24
|
|
|
16
25
|
constructor(options: {
|
|
17
26
|
name: string;
|
|
@@ -20,6 +29,13 @@ export class BaseAgent extends EventEmitter implements IAgent {
|
|
|
20
29
|
model?: string;
|
|
21
30
|
memory?: MemoryStore;
|
|
22
31
|
historyLimit?: number;
|
|
32
|
+
skillsDir?: string;
|
|
33
|
+
learning?: {
|
|
34
|
+
autoSkillCreation?: boolean;
|
|
35
|
+
minConversationLength?: number;
|
|
36
|
+
improveOnUse?: boolean;
|
|
37
|
+
};
|
|
38
|
+
maxToolRounds?: number;
|
|
23
39
|
}) {
|
|
24
40
|
super();
|
|
25
41
|
this.name = options.name;
|
|
@@ -27,6 +43,15 @@ export class BaseAgent extends EventEmitter implements IAgent {
|
|
|
27
43
|
this.memory = options.memory ?? new InMemoryStore();
|
|
28
44
|
this._provider = createProvider(options.provider ?? 'openai', options.model);
|
|
29
45
|
this.historyLimit = options.historyLimit ?? 50;
|
|
46
|
+
this.maxToolRounds = options.maxToolRounds ?? 10;
|
|
47
|
+
this.autoLearnConfig = {
|
|
48
|
+
enabled: options.learning?.autoSkillCreation !== false,
|
|
49
|
+
minConversationLength: options.learning?.minConversationLength ?? 3,
|
|
50
|
+
improveOnUse: options.learning?.improveOnUse !== false,
|
|
51
|
+
};
|
|
52
|
+
if (options.skillsDir) {
|
|
53
|
+
this.skillLearner = new SkillLearner(options.skillsDir);
|
|
54
|
+
}
|
|
30
55
|
}
|
|
31
56
|
|
|
32
57
|
get state(): AgentState {
|
|
@@ -45,6 +70,18 @@ export class BaseAgent extends EventEmitter implements IAgent {
|
|
|
45
70
|
return this.memory;
|
|
46
71
|
}
|
|
47
72
|
|
|
73
|
+
getSkillLearner(): SkillLearner | undefined {
|
|
74
|
+
return this.skillLearner;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getToolRegistry(): MCPToolRegistry {
|
|
78
|
+
return this.toolRegistry;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
registerTool(tool: MCPTool): void {
|
|
82
|
+
this.toolRegistry.register(tool);
|
|
83
|
+
}
|
|
84
|
+
|
|
48
85
|
private transition(to: AgentState): void {
|
|
49
86
|
const from = this._state;
|
|
50
87
|
this._state = to;
|
|
@@ -52,6 +89,9 @@ export class BaseAgent extends EventEmitter implements IAgent {
|
|
|
52
89
|
}
|
|
53
90
|
|
|
54
91
|
async init(): Promise<void> {
|
|
92
|
+
if (this.skillLearner) {
|
|
93
|
+
await this.skillLearner.loadLearnedSkills();
|
|
94
|
+
}
|
|
55
95
|
this.transition('ready');
|
|
56
96
|
}
|
|
57
97
|
|
|
@@ -85,6 +125,21 @@ export class BaseAgent extends EventEmitter implements IAgent {
|
|
|
85
125
|
return this.channels;
|
|
86
126
|
}
|
|
87
127
|
|
|
128
|
+
private getSubAgentManager(): SubAgentManager {
|
|
129
|
+
if (!this._subAgentManager) {
|
|
130
|
+
this._subAgentManager = new SubAgentManager();
|
|
131
|
+
}
|
|
132
|
+
return this._subAgentManager;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async spawnSubAgent(config: SubAgentConfig): Promise<SubAgentResult> {
|
|
136
|
+
return this.getSubAgentManager().spawn(config, this._provider);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async spawnParallel(configs: SubAgentConfig[]): Promise<SubAgentResult[]> {
|
|
140
|
+
return this.getSubAgentManager().spawnParallel(configs, this._provider);
|
|
141
|
+
}
|
|
142
|
+
|
|
88
143
|
async handleMessage(message: Message): Promise<Message> {
|
|
89
144
|
this.emit('message:in', message);
|
|
90
145
|
|
|
@@ -115,14 +170,102 @@ export class BaseAgent extends EventEmitter implements IAgent {
|
|
|
115
170
|
}
|
|
116
171
|
}
|
|
117
172
|
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
const
|
|
173
|
+
// Check if a learned skill matches — prepend instructions to system prompt
|
|
174
|
+
let effectiveSystemPrompt = this.systemPrompt;
|
|
175
|
+
const matchedSkill = this.skillLearner?.matchSkill(message.content);
|
|
176
|
+
if (matchedSkill) {
|
|
177
|
+
matchedSkill.usageCount++;
|
|
178
|
+
matchedSkill.lastUsed = new Date();
|
|
179
|
+
effectiveSystemPrompt = `[Learned Skill: ${matchedSkill.name}]\n${matchedSkill.instructions}\n\n${this.systemPrompt}`;
|
|
180
|
+
this.emit('skill:matched', matchedSkill);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Fall back to LLM with tool use loop
|
|
184
|
+
const tools = this.toolRegistry.list();
|
|
185
|
+
const llmMessages = [...context.messages];
|
|
186
|
+
let finalResponse = '';
|
|
187
|
+
|
|
188
|
+
for (let round = 0; round <= this.maxToolRounds; round++) {
|
|
189
|
+
const llmResponse = await this._provider.chat(
|
|
190
|
+
llmMessages,
|
|
191
|
+
effectiveSystemPrompt,
|
|
192
|
+
{ tools: tools.length > 0 ? tools : undefined },
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const toolCall = this.parseToolCall(llmResponse);
|
|
196
|
+
if (!toolCall || tools.length === 0 || round === this.maxToolRounds) {
|
|
197
|
+
finalResponse = llmResponse;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Execute tool
|
|
202
|
+
const toolResult = await this.toolRegistry.execute(toolCall.name, toolCall.arguments, context);
|
|
203
|
+
this.emit('tool:execute', toolCall.name, toolResult);
|
|
204
|
+
|
|
205
|
+
// Add tool call and result to messages for next round
|
|
206
|
+
llmMessages.push({
|
|
207
|
+
id: `tool_call_${Date.now()}`,
|
|
208
|
+
role: 'assistant',
|
|
209
|
+
content: llmResponse,
|
|
210
|
+
timestamp: Date.now(),
|
|
211
|
+
});
|
|
212
|
+
llmMessages.push({
|
|
213
|
+
id: `tool_result_${Date.now()}`,
|
|
214
|
+
role: 'user',
|
|
215
|
+
content: `[Tool Result for ${toolCall.name}]: ${toolResult.content}`,
|
|
216
|
+
timestamp: Date.now(),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const response = this.createResponse(finalResponse, message);
|
|
121
221
|
await this.memory.addMessage(sessionId, response);
|
|
122
222
|
this.emit('message:out', response);
|
|
223
|
+
|
|
224
|
+
// After response, check if we should learn a skill
|
|
225
|
+
if (
|
|
226
|
+
this.skillLearner &&
|
|
227
|
+
this.autoLearnConfig.enabled &&
|
|
228
|
+
context.messages.length >= this.autoLearnConfig.minConversationLength
|
|
229
|
+
) {
|
|
230
|
+
this.skillLearner
|
|
231
|
+
.analyzeForSkillCreation(context.messages, this._provider)
|
|
232
|
+
.then(async (learnedSkill) => {
|
|
233
|
+
if (learnedSkill) {
|
|
234
|
+
await this.skillLearner!.saveSkill(learnedSkill);
|
|
235
|
+
this.emit('skill:learned', learnedSkill);
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
.catch(() => {});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Improve matched skill after use
|
|
242
|
+
if (matchedSkill && this.skillLearner && this.autoLearnConfig.improveOnUse) {
|
|
243
|
+
this.skillLearner
|
|
244
|
+
.improveSkill(matchedSkill, context.messages, this._provider)
|
|
245
|
+
.then(() => this.skillLearner!.saveSkill(matchedSkill))
|
|
246
|
+
.catch(() => {});
|
|
247
|
+
}
|
|
248
|
+
|
|
123
249
|
return response;
|
|
124
250
|
}
|
|
125
251
|
|
|
252
|
+
private parseToolCall(response: string): { name: string; arguments: Record<string, unknown> } | null {
|
|
253
|
+
try {
|
|
254
|
+
const parsed = JSON.parse(response);
|
|
255
|
+
if (parsed.tool_call) return parsed.tool_call;
|
|
256
|
+
if (parsed.name && parsed.arguments !== undefined) return parsed;
|
|
257
|
+
} catch { /* not JSON */ }
|
|
258
|
+
|
|
259
|
+
const match = response.match(/<tool_call>\s*(\{[\s\S]*?\})\s*<\/tool_call>/);
|
|
260
|
+
if (match) {
|
|
261
|
+
try {
|
|
262
|
+
const parsed = JSON.parse(match[1]);
|
|
263
|
+
if (parsed.name) return parsed;
|
|
264
|
+
} catch { /* not valid JSON */ }
|
|
265
|
+
}
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
|
|
126
269
|
async *handleMessageStream(message: Message): AsyncIterable<string> {
|
|
127
270
|
const sessionId = (message.metadata?.sessionId as string) ?? 'default';
|
|
128
271
|
await this.memory.addMessage(sessionId, message);
|