opc-agent 2.0.0 → 2.0.1
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/dist/channels/email.d.ts +32 -26
- package/dist/channels/email.js +239 -62
- package/dist/channels/feishu.d.ts +21 -6
- package/dist/channels/feishu.js +225 -126
- package/dist/channels/websocket.d.ts +46 -3
- package/dist/channels/websocket.js +306 -37
- package/dist/channels/wechat.d.ts +33 -13
- package/dist/channels/wechat.js +229 -42
- package/dist/cli.js +712 -11
- package/dist/core/a2a.d.ts +17 -0
- package/dist/core/a2a.js +43 -1
- package/dist/core/agent.d.ts +16 -0
- package/dist/core/agent.js +108 -0
- package/dist/core/runtime.d.ts +6 -0
- package/dist/core/runtime.js +161 -2
- package/dist/core/sandbox.d.ts +26 -0
- package/dist/core/sandbox.js +117 -0
- package/dist/core/workflow-graph.d.ts +93 -0
- package/dist/core/workflow-graph.js +247 -0
- package/dist/doctor.d.ts +15 -0
- package/dist/doctor.js +183 -0
- package/dist/eval/index.d.ts +65 -0
- package/dist/eval/index.js +191 -0
- package/dist/index.d.ts +30 -6
- package/dist/index.js +60 -4
- package/dist/plugins/content-filter.d.ts +7 -0
- package/dist/plugins/content-filter.js +25 -0
- package/dist/plugins/index.d.ts +42 -0
- package/dist/plugins/index.js +108 -2
- package/dist/plugins/logger.d.ts +6 -0
- package/dist/plugins/logger.js +20 -0
- package/dist/plugins/rate-limiter.d.ts +7 -0
- package/dist/plugins/rate-limiter.js +35 -0
- package/dist/protocols/a2a/client.d.ts +25 -0
- package/dist/protocols/a2a/client.js +115 -0
- package/dist/protocols/a2a/index.d.ts +6 -0
- package/dist/protocols/a2a/index.js +12 -0
- package/dist/protocols/a2a/server.d.ts +41 -0
- package/dist/protocols/a2a/server.js +295 -0
- package/dist/protocols/a2a/types.d.ts +91 -0
- package/dist/protocols/a2a/types.js +15 -0
- package/dist/protocols/a2a/utils.d.ts +6 -0
- package/dist/protocols/a2a/utils.js +47 -0
- package/dist/protocols/agui/client.d.ts +10 -0
- package/dist/protocols/agui/client.js +75 -0
- package/dist/protocols/agui/index.d.ts +4 -0
- package/dist/protocols/agui/index.js +25 -0
- package/dist/protocols/agui/server.d.ts +37 -0
- package/dist/protocols/agui/server.js +191 -0
- package/dist/protocols/agui/types.d.ts +107 -0
- package/dist/protocols/agui/types.js +17 -0
- package/dist/protocols/index.d.ts +2 -0
- package/dist/protocols/index.js +19 -0
- package/dist/protocols/mcp/agent-tools.d.ts +11 -0
- package/dist/protocols/mcp/agent-tools.js +129 -0
- package/dist/protocols/mcp/index.d.ts +5 -0
- package/dist/protocols/mcp/index.js +11 -0
- package/dist/protocols/mcp/server.d.ts +31 -0
- package/dist/protocols/mcp/server.js +248 -0
- package/dist/protocols/mcp/types.d.ts +92 -0
- package/dist/protocols/mcp/types.js +17 -0
- package/dist/publish/index.d.ts +45 -0
- package/dist/publish/index.js +350 -0
- package/dist/schema/oad.d.ts +682 -65
- package/dist/schema/oad.js +36 -3
- package/dist/security/approval.d.ts +36 -0
- package/dist/security/approval.js +113 -0
- package/dist/security/index.d.ts +4 -0
- package/dist/security/index.js +8 -0
- package/dist/security/keys.d.ts +16 -0
- package/dist/security/keys.js +117 -0
- package/dist/studio/server.d.ts +63 -0
- package/dist/studio/server.js +625 -0
- package/dist/studio-ui/index.html +662 -0
- package/dist/telemetry/index.d.ts +93 -0
- package/dist/telemetry/index.js +285 -0
- package/package.json +5 -3
- package/scripts/install.ps1 +31 -0
- package/scripts/install.sh +40 -0
- package/src/channels/email.ts +351 -177
- package/src/channels/feishu.ts +349 -236
- package/src/channels/websocket.ts +399 -87
- package/src/channels/wechat.ts +329 -149
- package/src/cli.ts +783 -12
- package/src/core/a2a.ts +60 -0
- package/src/core/agent.ts +125 -0
- package/src/core/runtime.ts +127 -0
- package/src/core/sandbox.ts +143 -0
- package/src/core/workflow-graph.ts +365 -0
- package/src/doctor.ts +156 -0
- package/src/eval/index.ts +211 -0
- package/src/eval/suites/basic.json +16 -0
- package/src/eval/suites/memory.json +12 -0
- package/src/eval/suites/safety.json +14 -0
- package/src/index.ts +54 -6
- package/src/plugins/content-filter.ts +23 -0
- package/src/plugins/index.ts +133 -2
- package/src/plugins/logger.ts +18 -0
- package/src/plugins/rate-limiter.ts +38 -0
- package/src/protocols/a2a/client.ts +132 -0
- package/src/protocols/a2a/index.ts +8 -0
- package/src/protocols/a2a/server.ts +333 -0
- package/src/protocols/a2a/types.ts +88 -0
- package/src/protocols/a2a/utils.ts +50 -0
- package/src/protocols/agui/client.ts +83 -0
- package/src/protocols/agui/index.ts +4 -0
- package/src/protocols/agui/server.ts +218 -0
- package/src/protocols/agui/types.ts +153 -0
- package/src/protocols/index.ts +2 -0
- package/src/protocols/mcp/agent-tools.ts +134 -0
- package/src/protocols/mcp/index.ts +8 -0
- package/src/protocols/mcp/server.ts +262 -0
- package/src/protocols/mcp/types.ts +69 -0
- package/src/publish/index.ts +376 -0
- package/src/schema/oad.ts +39 -2
- package/src/security/approval.ts +131 -0
- package/src/security/index.ts +3 -0
- package/src/security/keys.ts +87 -0
- package/src/studio/server.ts +629 -0
- package/src/studio-ui/index.html +662 -0
- package/src/telemetry/index.ts +324 -0
- package/src/types/agent-workstation.d.ts +2 -0
- package/tests/a2a-protocol.test.ts +285 -0
- package/tests/agui-protocol.test.ts +246 -0
- package/tests/channels/discord.test.ts +79 -0
- package/tests/channels/email.test.ts +148 -0
- package/tests/channels/feishu.test.ts +123 -0
- package/tests/channels/telegram.test.ts +129 -0
- package/tests/channels/websocket.test.ts +53 -0
- package/tests/channels/wechat.test.ts +170 -0
- package/tests/chat-cli.test.ts +160 -0
- package/tests/daemon.test.ts +135 -0
- package/tests/deepbrain-wire.test.ts +234 -0
- package/tests/doctor.test.ts +38 -0
- package/tests/eval.test.ts +173 -0
- package/tests/init-role.test.ts +124 -0
- package/tests/mcp-client.test.ts +92 -0
- package/tests/mcp-server.test.ts +178 -0
- package/tests/plugin-a2a-enhanced.test.ts +230 -0
- package/tests/publish.test.ts +231 -0
- package/tests/scheduler.test.ts +200 -0
- package/tests/security-enhanced.test.ts +233 -0
- package/tests/skill-learner.test.ts +161 -0
- package/tests/studio.test.ts +229 -0
- package/tests/subagent.test.ts +63 -0
- package/tests/telemetry.test.ts +186 -0
- package/tests/tools/builtin-extended.test.ts +138 -0
- package/tests/workflow-graph.test.ts +279 -0
- package/tutorial/customer-service-agent/README.md +612 -0
- package/tutorial/customer-service-agent/SOUL.md +26 -0
- package/tutorial/customer-service-agent/agent.yaml +63 -0
- package/tutorial/customer-service-agent/package.json +19 -0
- package/tutorial/customer-service-agent/src/index.ts +69 -0
- package/tutorial/customer-service-agent/src/skills/faq.ts +27 -0
- package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -0
- package/tutorial/customer-service-agent/tsconfig.json +14 -0
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.StudioServer = void 0;
|
|
37
|
+
const http_1 = require("http");
|
|
38
|
+
const fs_1 = require("fs");
|
|
39
|
+
const path_1 = require("path");
|
|
40
|
+
const net = __importStar(require("net"));
|
|
41
|
+
const MODULE_REGISTRY = [
|
|
42
|
+
{ name: 'DeepBrain', path: 'brain', port: 4001, icon: '🧠' },
|
|
43
|
+
{ name: 'AgentKits', path: 'kits', port: 4002, icon: '📊' },
|
|
44
|
+
{ name: 'Workstation', path: 'workstation', port: 4003, icon: '👤' },
|
|
45
|
+
];
|
|
46
|
+
class StudioServer {
|
|
47
|
+
server;
|
|
48
|
+
config;
|
|
49
|
+
tracer;
|
|
50
|
+
constructor(config = {}) {
|
|
51
|
+
this.config = {
|
|
52
|
+
port: config.port || 4000,
|
|
53
|
+
agentDir: config.agentDir || process.cwd(),
|
|
54
|
+
staticDir: config.staticDir || (0, path_1.join)(__dirname, '../studio-ui'),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
setTracer(tracer) {
|
|
58
|
+
this.tracer = tracer;
|
|
59
|
+
}
|
|
60
|
+
getTracer() {
|
|
61
|
+
return this.tracer;
|
|
62
|
+
}
|
|
63
|
+
getConfig() {
|
|
64
|
+
return { ...this.config };
|
|
65
|
+
}
|
|
66
|
+
async start() {
|
|
67
|
+
this.server = (0, http_1.createServer)((req, res) => this.handleRequest(req, res));
|
|
68
|
+
this.server.listen(this.config.port);
|
|
69
|
+
console.log(`🎨 OPC Studio: http://localhost:${this.config.port}`);
|
|
70
|
+
}
|
|
71
|
+
async stop() {
|
|
72
|
+
return new Promise((resolve) => {
|
|
73
|
+
if (this.server) {
|
|
74
|
+
this.server.close(() => resolve());
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
resolve();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async handleRequest(req, res) {
|
|
82
|
+
const url = new URL(req.url || '/', `http://localhost`);
|
|
83
|
+
// Handle CORS preflight
|
|
84
|
+
if (req.method === 'OPTIONS') {
|
|
85
|
+
res.writeHead(204, {
|
|
86
|
+
'Access-Control-Allow-Origin': '*',
|
|
87
|
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
|
88
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
89
|
+
});
|
|
90
|
+
res.end();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// API routes
|
|
94
|
+
if (url.pathname.startsWith('/api/')) {
|
|
95
|
+
return this.handleAPI(req, res, url);
|
|
96
|
+
}
|
|
97
|
+
// Module proxy routes
|
|
98
|
+
for (const mod of MODULE_REGISTRY) {
|
|
99
|
+
if (url.pathname.startsWith(`/${mod.path}/`) || url.pathname === `/${mod.path}`) {
|
|
100
|
+
return this.proxyToModule(req, res, mod, url);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Static files
|
|
104
|
+
return this.serveStatic(req, res, url);
|
|
105
|
+
}
|
|
106
|
+
async handleAPI(req, res, url) {
|
|
107
|
+
const route = url.pathname.replace('/api/', '');
|
|
108
|
+
try {
|
|
109
|
+
let data;
|
|
110
|
+
switch (route) {
|
|
111
|
+
case 'modules':
|
|
112
|
+
data = await this.getModulesStatus();
|
|
113
|
+
break;
|
|
114
|
+
case 'agent/info':
|
|
115
|
+
data = await this.getAgentInfo();
|
|
116
|
+
break;
|
|
117
|
+
case 'agent/config':
|
|
118
|
+
if (req.method === 'GET')
|
|
119
|
+
data = await this.getAgentConfig();
|
|
120
|
+
else if (req.method === 'PUT')
|
|
121
|
+
data = await this.saveConfig(req);
|
|
122
|
+
break;
|
|
123
|
+
case 'agent/chat':
|
|
124
|
+
data = await this.handleChat(req);
|
|
125
|
+
break;
|
|
126
|
+
case 'memory/list':
|
|
127
|
+
data = await this.getMemoryList();
|
|
128
|
+
break;
|
|
129
|
+
case 'memory/search':
|
|
130
|
+
data = await this.searchMemory(url.searchParams.get('q') || '');
|
|
131
|
+
break;
|
|
132
|
+
case 'memory/stats':
|
|
133
|
+
data = await this.getMemoryStats();
|
|
134
|
+
break;
|
|
135
|
+
case 'skills/list':
|
|
136
|
+
data = await this.getSkills();
|
|
137
|
+
break;
|
|
138
|
+
case 'tools/list':
|
|
139
|
+
data = await this.getTools();
|
|
140
|
+
break;
|
|
141
|
+
case 'workflows/list':
|
|
142
|
+
data = await this.getWorkflows();
|
|
143
|
+
break;
|
|
144
|
+
case 'jobs/list':
|
|
145
|
+
data = await this.getJobs();
|
|
146
|
+
break;
|
|
147
|
+
case 'logs/recent':
|
|
148
|
+
data = await this.getRecentLogs();
|
|
149
|
+
break;
|
|
150
|
+
case 'analytics/overview':
|
|
151
|
+
data = await this.getAnalytics();
|
|
152
|
+
break;
|
|
153
|
+
case 'doctor/check':
|
|
154
|
+
data = await this.runDoctor();
|
|
155
|
+
break;
|
|
156
|
+
case 'channels/list':
|
|
157
|
+
data = await this.getChannels();
|
|
158
|
+
break;
|
|
159
|
+
case 'plugins/list':
|
|
160
|
+
data = await this.getPlugins();
|
|
161
|
+
break;
|
|
162
|
+
case 'security/approvals':
|
|
163
|
+
data = await this.getPendingApprovals();
|
|
164
|
+
break;
|
|
165
|
+
case 'eval/suites':
|
|
166
|
+
data = await this.getEvalSuites();
|
|
167
|
+
break;
|
|
168
|
+
case 'eval/run':
|
|
169
|
+
if (req.method === 'POST')
|
|
170
|
+
data = await this.runEvalSuite(req);
|
|
171
|
+
else {
|
|
172
|
+
res.writeHead(405);
|
|
173
|
+
res.end();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
case 'a2a/card':
|
|
178
|
+
data = this.getA2ACard();
|
|
179
|
+
break;
|
|
180
|
+
case 'a2a/tasks':
|
|
181
|
+
data = this.getA2ATasks();
|
|
182
|
+
break;
|
|
183
|
+
case 'a2a/discover':
|
|
184
|
+
if (req.method === 'POST')
|
|
185
|
+
data = await this.discoverA2AAgent(req);
|
|
186
|
+
else {
|
|
187
|
+
res.writeHead(405);
|
|
188
|
+
res.end();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
case 'protocols':
|
|
193
|
+
data = await this.getProtocols();
|
|
194
|
+
break;
|
|
195
|
+
case 'protocols/mcp':
|
|
196
|
+
data = this.getMCPServerStatus();
|
|
197
|
+
break;
|
|
198
|
+
case 'eval/reports':
|
|
199
|
+
data = await this.getEvalReports();
|
|
200
|
+
break;
|
|
201
|
+
case 'telemetry/stats':
|
|
202
|
+
data = this.tracer ? this.tracer.getStats() : { error: 'Telemetry not enabled' };
|
|
203
|
+
break;
|
|
204
|
+
case 'telemetry/traces':
|
|
205
|
+
data = this.getTelemetryTraces(url);
|
|
206
|
+
break;
|
|
207
|
+
case 'telemetry/metrics':
|
|
208
|
+
data = this.tracer ? this.tracer.getMetrics() : [];
|
|
209
|
+
break;
|
|
210
|
+
default:
|
|
211
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
212
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
res.writeHead(200, {
|
|
216
|
+
'Content-Type': 'application/json',
|
|
217
|
+
'Access-Control-Allow-Origin': '*',
|
|
218
|
+
});
|
|
219
|
+
res.end(JSON.stringify(data));
|
|
220
|
+
}
|
|
221
|
+
catch (e) {
|
|
222
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
223
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// --- API Implementations ---
|
|
227
|
+
async getAgentInfo() {
|
|
228
|
+
const oad = this.loadOAD();
|
|
229
|
+
const pkg = this.loadPackageJson();
|
|
230
|
+
return {
|
|
231
|
+
name: oad?.metadata?.name || pkg?.name || 'unknown',
|
|
232
|
+
version: oad?.metadata?.version || pkg?.version || '0.0.0',
|
|
233
|
+
description: oad?.metadata?.description || pkg?.description || '',
|
|
234
|
+
model: oad?.spec?.model || 'unknown',
|
|
235
|
+
provider: oad?.spec?.provider?.default || 'unknown',
|
|
236
|
+
channels: oad?.spec?.channels?.map((c) => c.type) || [],
|
|
237
|
+
skills: oad?.spec?.skills?.map((s) => s.name) || [],
|
|
238
|
+
status: 'running',
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
async getAgentConfig() {
|
|
242
|
+
const yamlPath = (0, path_1.join)(this.config.agentDir, 'agent.yaml');
|
|
243
|
+
if ((0, fs_1.existsSync)(yamlPath)) {
|
|
244
|
+
return { content: (0, fs_1.readFileSync)(yamlPath, 'utf-8') };
|
|
245
|
+
}
|
|
246
|
+
return { content: '', error: 'agent.yaml not found' };
|
|
247
|
+
}
|
|
248
|
+
async saveConfig(req) {
|
|
249
|
+
const body = await this.readBody(req);
|
|
250
|
+
const { content } = JSON.parse(body);
|
|
251
|
+
const yamlPath = (0, path_1.join)(this.config.agentDir, 'agent.yaml');
|
|
252
|
+
const { writeFileSync } = require('fs');
|
|
253
|
+
writeFileSync(yamlPath, content, 'utf-8');
|
|
254
|
+
return { success: true };
|
|
255
|
+
}
|
|
256
|
+
async handleChat(req) {
|
|
257
|
+
const body = await this.readBody(req);
|
|
258
|
+
const { message, sessionId } = JSON.parse(body);
|
|
259
|
+
try {
|
|
260
|
+
const { BaseAgent, InMemoryStore } = require('../index');
|
|
261
|
+
const oad = this.loadOAD();
|
|
262
|
+
const agent = new BaseAgent({
|
|
263
|
+
name: oad?.metadata?.name || 'studio-agent',
|
|
264
|
+
systemPrompt: oad?.spec?.systemPrompt || 'You are a helpful assistant.',
|
|
265
|
+
provider: oad?.spec?.provider?.default || 'ollama',
|
|
266
|
+
model: oad?.spec?.model || 'qwen2.5',
|
|
267
|
+
memory: new InMemoryStore(),
|
|
268
|
+
});
|
|
269
|
+
await agent.init();
|
|
270
|
+
const response = await agent.handleMessage({
|
|
271
|
+
id: String(Date.now()),
|
|
272
|
+
content: message,
|
|
273
|
+
sender: 'studio-user',
|
|
274
|
+
channel: 'studio',
|
|
275
|
+
sessionId: sessionId || 'studio-session',
|
|
276
|
+
timestamp: new Date(),
|
|
277
|
+
});
|
|
278
|
+
return { response: response.content };
|
|
279
|
+
}
|
|
280
|
+
catch (e) {
|
|
281
|
+
return { response: `Error: ${e.message}` };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async getMemoryList() {
|
|
285
|
+
try {
|
|
286
|
+
const { Brain } = require('deepbrain');
|
|
287
|
+
const oad = this.loadOAD();
|
|
288
|
+
const dbPath = oad?.spec?.memory?.longTerm?.database || './data/brain.db';
|
|
289
|
+
const brain = new Brain({ database: dbPath, embedding_provider: 'ollama' });
|
|
290
|
+
await brain.connect();
|
|
291
|
+
const pages = await brain.list({ limit: 50 });
|
|
292
|
+
await brain.disconnect();
|
|
293
|
+
return { pages };
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
return { pages: [], error: 'DeepBrain not available' };
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
async searchMemory(query) {
|
|
300
|
+
try {
|
|
301
|
+
const { Brain } = require('deepbrain');
|
|
302
|
+
const oad = this.loadOAD();
|
|
303
|
+
const dbPath = oad?.spec?.memory?.longTerm?.database || './data/brain.db';
|
|
304
|
+
const brain = new Brain({ database: dbPath, embedding_provider: 'ollama' });
|
|
305
|
+
await brain.connect();
|
|
306
|
+
const results = await brain.search(query);
|
|
307
|
+
await brain.disconnect();
|
|
308
|
+
return { results };
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
return { results: [], error: 'Search failed' };
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async getMemoryStats() {
|
|
315
|
+
try {
|
|
316
|
+
const { Brain } = require('deepbrain');
|
|
317
|
+
const oad = this.loadOAD();
|
|
318
|
+
const dbPath = oad?.spec?.memory?.longTerm?.database || './data/brain.db';
|
|
319
|
+
const brain = new Brain({ database: dbPath, embedding_provider: 'ollama' });
|
|
320
|
+
await brain.connect();
|
|
321
|
+
const stats = await brain.stats();
|
|
322
|
+
await brain.disconnect();
|
|
323
|
+
return stats;
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
return { pages: 0, chunks: 0, error: 'Stats unavailable' };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
async getSkills() {
|
|
330
|
+
try {
|
|
331
|
+
const { SkillLearner } = require('../index');
|
|
332
|
+
const learner = new SkillLearner('.opc/skills');
|
|
333
|
+
const skills = learner.loadSkills();
|
|
334
|
+
return { skills };
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return { skills: [] };
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async getTools() {
|
|
341
|
+
try {
|
|
342
|
+
const { getBuiltinTools } = require('../index');
|
|
343
|
+
const tools = getBuiltinTools(this.config.agentDir);
|
|
344
|
+
return { tools: tools.map((t) => ({ name: t.definition.name, description: t.definition.description })) };
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
return { tools: [] };
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
async getWorkflows() {
|
|
351
|
+
const oad = this.loadOAD();
|
|
352
|
+
return { workflows: oad?.spec?.workflows || [] };
|
|
353
|
+
}
|
|
354
|
+
async getJobs() {
|
|
355
|
+
const oad = this.loadOAD();
|
|
356
|
+
return { jobs: oad?.spec?.scheduler?.jobs || [] };
|
|
357
|
+
}
|
|
358
|
+
async getRecentLogs() {
|
|
359
|
+
const logPath = (0, path_1.join)(this.config.agentDir, '.opc', 'agent.log');
|
|
360
|
+
if ((0, fs_1.existsSync)(logPath)) {
|
|
361
|
+
const content = (0, fs_1.readFileSync)(logPath, 'utf-8');
|
|
362
|
+
const lines = content.split('\n').slice(-100);
|
|
363
|
+
return { lines };
|
|
364
|
+
}
|
|
365
|
+
return { lines: [] };
|
|
366
|
+
}
|
|
367
|
+
async getAnalytics() {
|
|
368
|
+
return {
|
|
369
|
+
totalMessages: 0,
|
|
370
|
+
totalSessions: 0,
|
|
371
|
+
avgResponseTime: 0,
|
|
372
|
+
topSkills: [],
|
|
373
|
+
note: 'Analytics tracking starts when agent is running via opc run/start',
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
async runDoctor() {
|
|
377
|
+
try {
|
|
378
|
+
const { runDoctor } = require('../doctor');
|
|
379
|
+
const results = await runDoctor();
|
|
380
|
+
return results;
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
return { error: 'Doctor not available' };
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async getChannels() {
|
|
387
|
+
const oad = this.loadOAD();
|
|
388
|
+
return { channels: oad?.spec?.channels || [] };
|
|
389
|
+
}
|
|
390
|
+
async getPlugins() {
|
|
391
|
+
const oad = this.loadOAD();
|
|
392
|
+
return { plugins: oad?.spec?.plugins || [] };
|
|
393
|
+
}
|
|
394
|
+
async getProtocols() {
|
|
395
|
+
const oad = this.loadOAD();
|
|
396
|
+
const protocols = oad?.spec?.protocols || {};
|
|
397
|
+
return {
|
|
398
|
+
protocols: [
|
|
399
|
+
{ name: 'a2a', description: 'Agent-to-Agent', enabled: !!protocols.a2a?.enabled, config: protocols.a2a || {} },
|
|
400
|
+
{ name: 'agui', description: 'AG-UI — Agent-User Interaction (SSE)', enabled: !!protocols.agui?.enabled, config: protocols.agui || {} },
|
|
401
|
+
{ name: 'mcp', description: 'MCP Server — Expose as MCP tools', enabled: !!protocols.mcp?.enabled, config: protocols.mcp || {} },
|
|
402
|
+
],
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
async getPendingApprovals() {
|
|
406
|
+
return { approvals: [] };
|
|
407
|
+
}
|
|
408
|
+
getMCPServerStatus() {
|
|
409
|
+
const oad = this.loadOAD();
|
|
410
|
+
const mcpConfig = oad?.spec?.protocols?.mcp;
|
|
411
|
+
const { agentToMCPTools } = require('../protocols/mcp/agent-tools');
|
|
412
|
+
const agentName = oad?.metadata?.name || 'opc-agent';
|
|
413
|
+
const tools = agentToMCPTools({ name: agentName });
|
|
414
|
+
return {
|
|
415
|
+
enabled: !!mcpConfig?.enabled,
|
|
416
|
+
mode: mcpConfig?.mode || 'stdio',
|
|
417
|
+
port: mcpConfig?.port || 3002,
|
|
418
|
+
tools: tools.map((t) => ({ name: t.name, description: t.description })),
|
|
419
|
+
toolCount: tools.length,
|
|
420
|
+
exposedTools: mcpConfig?.exposedTools || tools.map((t) => t.name),
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
getTelemetryTraces(url) {
|
|
424
|
+
if (!this.tracer)
|
|
425
|
+
return { traces: [] };
|
|
426
|
+
const traceId = url.searchParams.get('id');
|
|
427
|
+
if (traceId) {
|
|
428
|
+
return { spans: this.tracer.getTrace(traceId) };
|
|
429
|
+
}
|
|
430
|
+
const limit = parseInt(url.searchParams.get('limit') || '50');
|
|
431
|
+
const spans = this.tracer.getSpans({ limit });
|
|
432
|
+
// Group by traceId for trace list
|
|
433
|
+
const traceMap = new Map();
|
|
434
|
+
for (const s of spans) {
|
|
435
|
+
if (!traceMap.has(s.traceId)) {
|
|
436
|
+
traceMap.set(s.traceId, { traceId: s.traceId, rootSpan: s.name, startTime: s.startTime, spanCount: 0, status: s.status });
|
|
437
|
+
}
|
|
438
|
+
traceMap.get(s.traceId).spanCount++;
|
|
439
|
+
}
|
|
440
|
+
return { traces: Array.from(traceMap.values()) };
|
|
441
|
+
}
|
|
442
|
+
async getEvalSuites() {
|
|
443
|
+
const { AgentEvaluator } = require('../eval');
|
|
444
|
+
return { suites: AgentEvaluator.builtinSuites() };
|
|
445
|
+
}
|
|
446
|
+
async runEvalSuite(req) {
|
|
447
|
+
const body = await this.readBody(req);
|
|
448
|
+
const { suite: suiteName } = JSON.parse(body || '{}');
|
|
449
|
+
const { AgentEvaluator } = require('../eval');
|
|
450
|
+
const suite = AgentEvaluator.loadBuiltinSuite(suiteName || 'basic');
|
|
451
|
+
// Use a mock agent for studio eval (no real agent loaded)
|
|
452
|
+
const mockAgent = { chat: async (input) => `[mock response to: ${input}]` };
|
|
453
|
+
const evaluator = new AgentEvaluator(mockAgent);
|
|
454
|
+
const report = await evaluator.evalSuite(suite);
|
|
455
|
+
// Save report
|
|
456
|
+
const reportsDir = (0, path_1.join)(this.config.agentDir, '.eval-reports');
|
|
457
|
+
const reportPath = (0, path_1.join)(reportsDir, `${suiteName || 'basic'}-${Date.now()}.json`);
|
|
458
|
+
AgentEvaluator.saveReport(report, reportPath);
|
|
459
|
+
return report;
|
|
460
|
+
}
|
|
461
|
+
async getEvalReports() {
|
|
462
|
+
const reportsDir = (0, path_1.join)(this.config.agentDir, '.eval-reports');
|
|
463
|
+
if (!(0, fs_1.existsSync)(reportsDir))
|
|
464
|
+
return { reports: [] };
|
|
465
|
+
const files = require('fs').readdirSync(reportsDir).filter((f) => f.endsWith('.json'));
|
|
466
|
+
return {
|
|
467
|
+
reports: files.map((f) => {
|
|
468
|
+
try {
|
|
469
|
+
return JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(reportsDir, f), 'utf-8'));
|
|
470
|
+
}
|
|
471
|
+
catch {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
}).filter(Boolean)
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
// --- A2A Protocol ---
|
|
478
|
+
getA2ACard() {
|
|
479
|
+
try {
|
|
480
|
+
const { oadToAgentCard } = require('../protocols/a2a');
|
|
481
|
+
const yaml = require('js-yaml');
|
|
482
|
+
for (const name of ['agent.yaml', 'agent.yml']) {
|
|
483
|
+
const p = (0, path_1.join)(this.config.agentDir, name);
|
|
484
|
+
if ((0, fs_1.existsSync)(p)) {
|
|
485
|
+
const oad = yaml.load((0, fs_1.readFileSync)(p, 'utf-8'));
|
|
486
|
+
return oadToAgentCard(oad, `http://localhost:${this.config.port}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return { error: 'No agent.yaml found' };
|
|
490
|
+
}
|
|
491
|
+
catch {
|
|
492
|
+
return { error: 'Failed to generate agent card' };
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
getA2ATasks() {
|
|
496
|
+
// In-memory tasks from A2A server if running
|
|
497
|
+
return { tasks: [] };
|
|
498
|
+
}
|
|
499
|
+
async discoverA2AAgent(req) {
|
|
500
|
+
const body = await this.readBody(req);
|
|
501
|
+
const { url } = JSON.parse(body || '{}');
|
|
502
|
+
if (!url)
|
|
503
|
+
return { error: 'url required' };
|
|
504
|
+
try {
|
|
505
|
+
const { A2AClient } = require('../protocols/a2a');
|
|
506
|
+
const client = new A2AClient(url);
|
|
507
|
+
return await client.getAgentCard();
|
|
508
|
+
}
|
|
509
|
+
catch (err) {
|
|
510
|
+
return { error: err.message };
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
// --- Module Proxy & Health ---
|
|
514
|
+
proxyToModule(req, res, mod, url) {
|
|
515
|
+
const targetPath = url.pathname.slice(`/${mod.path}`.length) || '/';
|
|
516
|
+
const proxyReq = (0, http_1.request)({
|
|
517
|
+
hostname: 'localhost',
|
|
518
|
+
port: mod.port,
|
|
519
|
+
path: targetPath + (url.search || ''),
|
|
520
|
+
method: req.method,
|
|
521
|
+
headers: { ...req.headers, host: `localhost:${mod.port}` },
|
|
522
|
+
}, (proxyRes) => {
|
|
523
|
+
res.writeHead(proxyRes.statusCode || 502, proxyRes.headers);
|
|
524
|
+
proxyRes.pipe(res, { end: true });
|
|
525
|
+
});
|
|
526
|
+
proxyReq.on('error', () => {
|
|
527
|
+
res.writeHead(502, { 'Content-Type': 'text/html' });
|
|
528
|
+
res.end(`<html><body style="font-family:system-ui;padding:40px;color:#999;background:#1a1a2e;text-align:center"><h2>${mod.icon} ${mod.name}</h2><p>Module not running on port ${mod.port}</p></body></html>`);
|
|
529
|
+
});
|
|
530
|
+
req.pipe(proxyReq, { end: true });
|
|
531
|
+
}
|
|
532
|
+
checkPort(port) {
|
|
533
|
+
return new Promise((resolve) => {
|
|
534
|
+
const sock = new net.Socket();
|
|
535
|
+
sock.setTimeout(500);
|
|
536
|
+
sock.once('connect', () => { sock.destroy(); resolve(true); });
|
|
537
|
+
sock.once('error', () => { sock.destroy(); resolve(false); });
|
|
538
|
+
sock.once('timeout', () => { sock.destroy(); resolve(false); });
|
|
539
|
+
sock.connect(port, 'localhost');
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
async getModulesStatus() {
|
|
543
|
+
const modules = await Promise.all(MODULE_REGISTRY.map(async (mod) => ({
|
|
544
|
+
name: mod.name,
|
|
545
|
+
path: `/${mod.path}/`,
|
|
546
|
+
port: mod.port,
|
|
547
|
+
icon: mod.icon,
|
|
548
|
+
running: await this.checkPort(mod.port),
|
|
549
|
+
})));
|
|
550
|
+
return { modules };
|
|
551
|
+
}
|
|
552
|
+
// --- Helpers ---
|
|
553
|
+
loadOAD() {
|
|
554
|
+
try {
|
|
555
|
+
const yamlPath = (0, path_1.join)(this.config.agentDir, 'agent.yaml');
|
|
556
|
+
if (!(0, fs_1.existsSync)(yamlPath))
|
|
557
|
+
return null;
|
|
558
|
+
const content = (0, fs_1.readFileSync)(yamlPath, 'utf-8');
|
|
559
|
+
try {
|
|
560
|
+
const { loadOAD } = require('../index');
|
|
561
|
+
return loadOAD(yamlPath);
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
// Fallback: simple yaml parse
|
|
565
|
+
const yaml = require('js-yaml');
|
|
566
|
+
return yaml.load(content);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
catch {
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
loadPackageJson() {
|
|
574
|
+
try {
|
|
575
|
+
const pkgPath = (0, path_1.join)(this.config.agentDir, 'package.json');
|
|
576
|
+
if (!(0, fs_1.existsSync)(pkgPath))
|
|
577
|
+
return null;
|
|
578
|
+
return JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
579
|
+
}
|
|
580
|
+
catch {
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
serveStatic(req, res, url) {
|
|
585
|
+
let filePath = url.pathname === '/' ? '/index.html' : url.pathname;
|
|
586
|
+
const fullPath = (0, path_1.join)(this.config.staticDir, filePath);
|
|
587
|
+
if (!(0, fs_1.existsSync)(fullPath)) {
|
|
588
|
+
// SPA fallback
|
|
589
|
+
const indexPath = (0, path_1.join)(this.config.staticDir, 'index.html');
|
|
590
|
+
if ((0, fs_1.existsSync)(indexPath)) {
|
|
591
|
+
const content = (0, fs_1.readFileSync)(indexPath, 'utf-8');
|
|
592
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
593
|
+
res.end(content);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
res.writeHead(404);
|
|
597
|
+
res.end('Not found');
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
const mimeTypes = {
|
|
601
|
+
'.html': 'text/html',
|
|
602
|
+
'.css': 'text/css',
|
|
603
|
+
'.js': 'application/javascript',
|
|
604
|
+
'.json': 'application/json',
|
|
605
|
+
'.png': 'image/png',
|
|
606
|
+
'.svg': 'image/svg+xml',
|
|
607
|
+
'.ico': 'image/x-icon',
|
|
608
|
+
};
|
|
609
|
+
const ext = (0, path_1.extname)(fullPath);
|
|
610
|
+
const contentType = mimeTypes[ext] || 'application/octet-stream';
|
|
611
|
+
const content = (0, fs_1.readFileSync)(fullPath);
|
|
612
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
613
|
+
res.end(content);
|
|
614
|
+
}
|
|
615
|
+
readBody(req) {
|
|
616
|
+
return new Promise((resolve, reject) => {
|
|
617
|
+
let body = '';
|
|
618
|
+
req.on('data', (chunk) => (body += chunk));
|
|
619
|
+
req.on('end', () => resolve(body));
|
|
620
|
+
req.on('error', reject);
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
exports.StudioServer = StudioServer;
|
|
625
|
+
//# sourceMappingURL=server.js.map
|