opc-agent 1.3.2 → 1.4.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 +23 -63
- package/CONTRIBUTING.md +21 -60
- package/README.md +235 -358
- package/README.zh-CN.md +415 -415
- package/dist/channels/slack.js +93 -10
- package/dist/channels/web.d.ts +10 -0
- package/dist/channels/web.js +33 -2
- package/dist/cli.js +255 -60
- package/dist/core/runtime.d.ts +4 -0
- package/dist/core/runtime.js +27 -0
- package/dist/deploy/hermes.js +22 -22
- package/dist/deploy/openclaw.js +31 -40
- package/dist/index.d.ts +3 -10
- package/dist/index.js +6 -15
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.js +7 -1
- package/dist/schema/oad.d.ts +1 -2
- 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/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 +90 -90
- 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 +282 -58
- package/src/core/a2a.ts +143 -143
- package/src/core/agent.ts +152 -152
- 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 +183 -152
- package/src/core/sandbox.ts +101 -101
- package/src/core/security.ts +171 -171
- 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/deploy/hermes.ts +156 -156
- package/src/deploy/openclaw.ts +190 -200
- package/src/i18n/index.ts +216 -216
- package/src/index.ts +3 -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 +9 -1
- package/src/schema/oad.ts +154 -155
- 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/calculator.ts +73 -73
- package/src/tools/datetime.ts +149 -149
- package/src/tools/json-transform.ts +187 -187
- 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/channel.test.ts +39 -39
- 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/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/dist/channels/slack.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.SlackChannel = void 0;
|
|
4
37
|
const index_1 = require("./index");
|
|
@@ -37,9 +70,51 @@ class SlackChannel extends index_1.BaseChannel {
|
|
|
37
70
|
}
|
|
38
71
|
/** Start Events API HTTP server */
|
|
39
72
|
async startEventsAPI() {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
73
|
+
const http = await Promise.resolve().then(() => __importStar(require('http')));
|
|
74
|
+
const port = this.config.port ?? 3001;
|
|
75
|
+
const server = http.createServer(async (req, res) => {
|
|
76
|
+
if (req.method !== 'POST') {
|
|
77
|
+
res.writeHead(404);
|
|
78
|
+
res.end();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const chunks = [];
|
|
82
|
+
for await (const chunk of req)
|
|
83
|
+
chunks.push(chunk);
|
|
84
|
+
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
85
|
+
// URL verification challenge
|
|
86
|
+
if (body.type === 'url_verification') {
|
|
87
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
88
|
+
res.end(JSON.stringify({ challenge: body.challenge }));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Event callback
|
|
92
|
+
if (body.type === 'event_callback' && body.event) {
|
|
93
|
+
const event = body.event;
|
|
94
|
+
if (event.type === 'message' || event.type === 'app_mention') {
|
|
95
|
+
// Don't block the HTTP response
|
|
96
|
+
this.handleMessage(event).catch(() => { });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Slash commands (form-urlencoded, but we handle JSON for simplicity)
|
|
100
|
+
if (req.url === '/slack/commands' && body.command) {
|
|
101
|
+
const reply = await this.handleSlashCommand({
|
|
102
|
+
command: body.command,
|
|
103
|
+
text: body.text ?? '',
|
|
104
|
+
userId: body.user_id,
|
|
105
|
+
channelId: body.channel_id,
|
|
106
|
+
triggerId: body.trigger_id,
|
|
107
|
+
});
|
|
108
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
109
|
+
res.end(JSON.stringify({ response_type: 'ephemeral', text: reply }));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
res.writeHead(200);
|
|
113
|
+
res.end('ok');
|
|
114
|
+
});
|
|
115
|
+
server.listen(port, () => {
|
|
116
|
+
console.log(`[SlackChannel] Events API listening on port ${port}`);
|
|
117
|
+
});
|
|
43
118
|
}
|
|
44
119
|
/** Handle incoming Slack message */
|
|
45
120
|
async handleMessage(event) {
|
|
@@ -94,13 +169,21 @@ class SlackChannel extends index_1.BaseChannel {
|
|
|
94
169
|
}
|
|
95
170
|
/** Send a message to a Slack channel */
|
|
96
171
|
async sendMessage(channel, text, threadTs) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
172
|
+
const body = { channel, text };
|
|
173
|
+
if (threadTs)
|
|
174
|
+
body.thread_ts = threadTs;
|
|
175
|
+
const res = await fetch('https://slack.com/api/chat.postMessage', {
|
|
176
|
+
method: 'POST',
|
|
177
|
+
headers: {
|
|
178
|
+
'Authorization': `Bearer ${this.config.botToken}`,
|
|
179
|
+
'Content-Type': 'application/json',
|
|
180
|
+
},
|
|
181
|
+
body: JSON.stringify(body),
|
|
182
|
+
});
|
|
183
|
+
const data = await res.json();
|
|
184
|
+
if (!data.ok) {
|
|
185
|
+
console.error(`[SlackChannel] chat.postMessage failed: ${data.error}`);
|
|
186
|
+
}
|
|
104
187
|
}
|
|
105
188
|
}
|
|
106
189
|
exports.SlackChannel = SlackChannel;
|
package/dist/channels/web.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export declare class WebChannel extends BaseChannel {
|
|
|
9
9
|
private port;
|
|
10
10
|
private streamHandler;
|
|
11
11
|
private agentName;
|
|
12
|
+
private agentVersion;
|
|
13
|
+
private memoryType;
|
|
14
|
+
private skillNames;
|
|
15
|
+
private channelNames;
|
|
16
|
+
private analyticsProvider;
|
|
12
17
|
private currentProvider;
|
|
13
18
|
private stats;
|
|
14
19
|
private eventHandlers;
|
|
@@ -23,6 +28,11 @@ export declare class WebChannel extends BaseChannel {
|
|
|
23
28
|
trackSession(): void;
|
|
24
29
|
constructor(port?: number, authConfig?: AuthConfig);
|
|
25
30
|
setAgentName(name: string): void;
|
|
31
|
+
setAgentVersion(version: string): void;
|
|
32
|
+
setMemoryType(type: string): void;
|
|
33
|
+
setSkillNames(names: string[]): void;
|
|
34
|
+
setChannelNames(names: string[]): void;
|
|
35
|
+
setAnalyticsProvider(fn: () => any): void;
|
|
26
36
|
onStreamMessage(handler: (msg: Message, res: Response) => Promise<void>): void;
|
|
27
37
|
private setupRoutes;
|
|
28
38
|
start(): Promise<void>;
|
package/dist/channels/web.js
CHANGED
|
@@ -286,6 +286,11 @@ class WebChannel extends index_1.BaseChannel {
|
|
|
286
286
|
port;
|
|
287
287
|
streamHandler = null;
|
|
288
288
|
agentName = 'OPC Agent';
|
|
289
|
+
agentVersion = '1.0.0';
|
|
290
|
+
memoryType = 'in-memory';
|
|
291
|
+
skillNames = [];
|
|
292
|
+
channelNames = ['web'];
|
|
293
|
+
analyticsProvider = null;
|
|
289
294
|
currentProvider = 'openai';
|
|
290
295
|
stats = { sessions: 0, messages: 0, totalResponseMs: 0, tokenUsage: 0, knowledgeFiles: 0, startedAt: Date.now(), errors: 0 };
|
|
291
296
|
eventHandlers = new Map();
|
|
@@ -326,6 +331,21 @@ class WebChannel extends index_1.BaseChannel {
|
|
|
326
331
|
setAgentName(name) {
|
|
327
332
|
this.agentName = name;
|
|
328
333
|
}
|
|
334
|
+
setAgentVersion(version) {
|
|
335
|
+
this.agentVersion = version;
|
|
336
|
+
}
|
|
337
|
+
setMemoryType(type) {
|
|
338
|
+
this.memoryType = type;
|
|
339
|
+
}
|
|
340
|
+
setSkillNames(names) {
|
|
341
|
+
this.skillNames = names;
|
|
342
|
+
}
|
|
343
|
+
setChannelNames(names) {
|
|
344
|
+
this.channelNames = names;
|
|
345
|
+
}
|
|
346
|
+
setAnalyticsProvider(fn) {
|
|
347
|
+
this.analyticsProvider = fn;
|
|
348
|
+
}
|
|
329
349
|
onStreamMessage(handler) {
|
|
330
350
|
this.streamHandler = handler;
|
|
331
351
|
}
|
|
@@ -334,7 +354,17 @@ class WebChannel extends index_1.BaseChannel {
|
|
|
334
354
|
res.type('html').send(CHAT_HTML);
|
|
335
355
|
});
|
|
336
356
|
this.app.get('/health', (_req, res) => {
|
|
337
|
-
res.json({
|
|
357
|
+
res.json({
|
|
358
|
+
status: 'ok',
|
|
359
|
+
agent: this.agentName,
|
|
360
|
+
version: this.agentVersion,
|
|
361
|
+
uptime: Date.now() - this.stats.startedAt,
|
|
362
|
+
memory: this.memoryType,
|
|
363
|
+
skills: this.skillNames,
|
|
364
|
+
channels: this.channelNames,
|
|
365
|
+
analytics: this.analyticsProvider ? this.analyticsProvider() : null,
|
|
366
|
+
timestamp: Date.now(),
|
|
367
|
+
});
|
|
338
368
|
});
|
|
339
369
|
this.app.get('/api/info', (_req, res) => {
|
|
340
370
|
res.json({ name: this.agentName });
|
|
@@ -408,7 +438,8 @@ class WebChannel extends index_1.BaseChannel {
|
|
|
408
438
|
res.type('html').send(DASHBOARD_HTML);
|
|
409
439
|
});
|
|
410
440
|
this.app.get('/api/dashboard', (_req, res) => {
|
|
411
|
-
|
|
441
|
+
const analytics = this.analyticsProvider ? this.analyticsProvider() : null;
|
|
442
|
+
res.json({ ...this.stats, analytics });
|
|
412
443
|
});
|
|
413
444
|
// --- Knowledge Base Upload ---
|
|
414
445
|
this.app.post('/api/kb/upload', async (req, res) => {
|
package/dist/cli.js
CHANGED
|
@@ -61,7 +61,6 @@ const workflow_1 = require("./core/workflow");
|
|
|
61
61
|
const versioning_1 = require("./core/versioning");
|
|
62
62
|
const providers_1 = require("./providers");
|
|
63
63
|
const knowledge_1 = require("./core/knowledge");
|
|
64
|
-
const marketplace_1 = require("./marketplace");
|
|
65
64
|
const program = new commander_1.Command();
|
|
66
65
|
const color = {
|
|
67
66
|
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
@@ -119,7 +118,7 @@ async function select(question, options) {
|
|
|
119
118
|
program
|
|
120
119
|
.name('opc')
|
|
121
120
|
.description('OPC Agent - Open Agent Framework for business workstations')
|
|
122
|
-
.version('1.
|
|
121
|
+
.version('1.4.0');
|
|
123
122
|
// ── Init command ─────────────────────────────────────────────
|
|
124
123
|
program
|
|
125
124
|
.command('init')
|
|
@@ -139,6 +138,7 @@ program
|
|
|
139
138
|
process.exit(1);
|
|
140
139
|
}
|
|
141
140
|
fs.mkdirSync(dir, { recursive: true });
|
|
141
|
+
fs.mkdirSync(path.join(dir, 'src', 'skills'), { recursive: true });
|
|
142
142
|
const factory = TEMPLATES[template]?.factory ?? customer_service_1.createCustomerServiceConfig;
|
|
143
143
|
const config = factory();
|
|
144
144
|
config.metadata.name = name;
|
|
@@ -147,6 +147,93 @@ program
|
|
|
147
147
|
config.spec.channels.push({ type: 'web', port: 3000 });
|
|
148
148
|
}
|
|
149
149
|
fs.writeFileSync(path.join(dir, 'oad.yaml'), yaml.dump(config, { lineWidth: 120 }));
|
|
150
|
+
// agent.yaml — standalone OAD config for runtime usage
|
|
151
|
+
fs.writeFileSync(path.join(dir, 'agent.yaml'), `apiVersion: opc/v1
|
|
152
|
+
kind: Agent
|
|
153
|
+
metadata:
|
|
154
|
+
name: ${name}
|
|
155
|
+
version: 1.0.0
|
|
156
|
+
description: My AI Agent
|
|
157
|
+
spec:
|
|
158
|
+
model: qwen2.5
|
|
159
|
+
provider:
|
|
160
|
+
default: ollama
|
|
161
|
+
systemPrompt: |
|
|
162
|
+
You are a helpful AI assistant named ${name}.
|
|
163
|
+
Be concise, helpful, and friendly.
|
|
164
|
+
channels:
|
|
165
|
+
- type: web
|
|
166
|
+
port: 3000
|
|
167
|
+
memory:
|
|
168
|
+
shortTerm: true
|
|
169
|
+
longTerm:
|
|
170
|
+
provider: deepbrain
|
|
171
|
+
skills:
|
|
172
|
+
- name: echo
|
|
173
|
+
description: Echo test skill
|
|
174
|
+
`);
|
|
175
|
+
// src/index.ts — entry point
|
|
176
|
+
fs.writeFileSync(path.join(dir, 'src', 'index.ts'), `import { AgentRuntime } from 'opc-agent';
|
|
177
|
+
import { EchoSkill } from './skills/echo';
|
|
178
|
+
|
|
179
|
+
async function main() {
|
|
180
|
+
const runtime = new AgentRuntime();
|
|
181
|
+
|
|
182
|
+
// Load OAD config
|
|
183
|
+
await runtime.loadConfig('./agent.yaml');
|
|
184
|
+
|
|
185
|
+
// Initialize agent with channels, memory, etc.
|
|
186
|
+
const agent = await runtime.initialize();
|
|
187
|
+
|
|
188
|
+
// Register custom skills
|
|
189
|
+
runtime.registerSkill(new EchoSkill());
|
|
190
|
+
|
|
191
|
+
// Start serving
|
|
192
|
+
await runtime.start();
|
|
193
|
+
|
|
194
|
+
console.log('🤖 Agent is running!');
|
|
195
|
+
console.log(' Web UI: http://localhost:3000');
|
|
196
|
+
console.log(' Press Ctrl+C to stop');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
main().catch(console.error);
|
|
200
|
+
`);
|
|
201
|
+
// src/skills/echo.ts — example skill
|
|
202
|
+
fs.writeFileSync(path.join(dir, 'src', 'skills', 'echo.ts'), `import { BaseSkill } from 'opc-agent';
|
|
203
|
+
import type { AgentContext, Message, SkillResult } from 'opc-agent';
|
|
204
|
+
|
|
205
|
+
export class EchoSkill extends BaseSkill {
|
|
206
|
+
name = 'echo';
|
|
207
|
+
description = 'Echo back the message (test skill)';
|
|
208
|
+
|
|
209
|
+
async execute(context: AgentContext, message: Message): Promise<SkillResult> {
|
|
210
|
+
if (message.content.toLowerCase().startsWith('/echo ')) {
|
|
211
|
+
const text = message.content.slice(6);
|
|
212
|
+
return this.match(\`🔊 Echo: \${text}\`);
|
|
213
|
+
}
|
|
214
|
+
return this.noMatch();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
`);
|
|
218
|
+
// tsconfig.json
|
|
219
|
+
fs.writeFileSync(path.join(dir, 'tsconfig.json'), JSON.stringify({
|
|
220
|
+
compilerOptions: {
|
|
221
|
+
target: 'ES2022',
|
|
222
|
+
module: 'commonjs',
|
|
223
|
+
lib: ['ES2022'],
|
|
224
|
+
outDir: 'dist',
|
|
225
|
+
rootDir: 'src',
|
|
226
|
+
strict: true,
|
|
227
|
+
esModuleInterop: true,
|
|
228
|
+
skipLibCheck: true,
|
|
229
|
+
forceConsistentCasingInFileNames: true,
|
|
230
|
+
resolveJsonModule: true,
|
|
231
|
+
declaration: true,
|
|
232
|
+
sourceMap: true,
|
|
233
|
+
},
|
|
234
|
+
include: ['src/**/*'],
|
|
235
|
+
exclude: ['node_modules', 'dist'],
|
|
236
|
+
}, null, 2));
|
|
150
237
|
// .env.example
|
|
151
238
|
fs.writeFileSync(path.join(dir, '.env.example'), `# LLM API Configuration
|
|
152
239
|
OPC_LLM_API_KEY=your-api-key-here
|
|
@@ -157,9 +244,9 @@ OPC_LLM_MODEL=gpt-4o-mini
|
|
|
157
244
|
# OPC_LLM_BASE_URL=https://api.deepseek.com/v1
|
|
158
245
|
# OPC_LLM_MODEL=deepseek-chat
|
|
159
246
|
|
|
160
|
-
# For local Ollama:
|
|
247
|
+
# For local Ollama (default in agent.yaml):
|
|
161
248
|
# OPC_LLM_BASE_URL=http://localhost:11434/v1
|
|
162
|
-
# OPC_LLM_MODEL=
|
|
249
|
+
# OPC_LLM_MODEL=qwen2.5
|
|
163
250
|
`);
|
|
164
251
|
// .env (copy of example)
|
|
165
252
|
fs.writeFileSync(path.join(dir, '.env'), `OPC_LLM_API_KEY=your-api-key-here
|
|
@@ -173,20 +260,27 @@ OPC_LLM_MODEL=gpt-4o-mini
|
|
|
173
260
|
private: true,
|
|
174
261
|
scripts: {
|
|
175
262
|
start: 'opc run',
|
|
263
|
+
dev: 'opc dev',
|
|
176
264
|
chat: 'opc chat',
|
|
265
|
+
build: 'tsc',
|
|
177
266
|
},
|
|
178
267
|
dependencies: {
|
|
179
|
-
'opc-agent': '^
|
|
268
|
+
'opc-agent': '^1.3.0',
|
|
269
|
+
},
|
|
270
|
+
devDependencies: {
|
|
271
|
+
typescript: '^5.5.0',
|
|
272
|
+
tsx: '^4.0.0',
|
|
180
273
|
},
|
|
181
274
|
}, null, 2));
|
|
182
275
|
// .gitignore
|
|
183
|
-
fs.writeFileSync(path.join(dir, '.gitignore'), 'node_modules\n.env\n.opc-knowledge.json\ndata/\n');
|
|
276
|
+
fs.writeFileSync(path.join(dir, '.gitignore'), 'node_modules\ndist\n.env\n.opc-knowledge.json\ndata/\n');
|
|
184
277
|
// Dockerfile
|
|
185
278
|
fs.writeFileSync(path.join(dir, 'Dockerfile'), `FROM node:22-alpine
|
|
186
279
|
WORKDIR /app
|
|
187
280
|
COPY package.json package-lock.json* ./
|
|
188
281
|
RUN npm ci --production 2>/dev/null || npm install --production
|
|
189
|
-
COPY oad.yaml .env* ./
|
|
282
|
+
COPY oad.yaml agent.yaml .env* ./
|
|
283
|
+
COPY src/ ./src/
|
|
190
284
|
COPY prompts/ ./prompts/ 2>/dev/null || true
|
|
191
285
|
EXPOSE 3000
|
|
192
286
|
CMD ["npx", "opc", "run"]
|
|
@@ -201,7 +295,7 @@ services:
|
|
|
201
295
|
env_file:
|
|
202
296
|
- .env
|
|
203
297
|
volumes:
|
|
204
|
-
- ./
|
|
298
|
+
- ./agent.yaml:/app/agent.yaml:ro
|
|
205
299
|
restart: unless-stopped
|
|
206
300
|
`);
|
|
207
301
|
// README.md
|
|
@@ -211,51 +305,67 @@ Created with [OPC Agent](https://github.com/Deepleaper/opc-agent) using the \`${
|
|
|
211
305
|
|
|
212
306
|
## Quick Start
|
|
213
307
|
|
|
214
|
-
1. **
|
|
308
|
+
1. **Install dependencies:**
|
|
215
309
|
\`\`\`bash
|
|
216
|
-
|
|
217
|
-
cp .env.example .env
|
|
218
|
-
# Then edit .env with your actual key
|
|
310
|
+
npm install
|
|
219
311
|
\`\`\`
|
|
220
312
|
|
|
221
|
-
2. **
|
|
313
|
+
2. **Run with Ollama (default):**
|
|
222
314
|
\`\`\`bash
|
|
223
|
-
|
|
315
|
+
# Make sure Ollama is running with qwen2.5 model
|
|
316
|
+
ollama pull qwen2.5
|
|
317
|
+
npx tsx src/index.ts
|
|
224
318
|
\`\`\`
|
|
225
319
|
|
|
226
|
-
3. **
|
|
320
|
+
3. **Or use OpenAI/other providers:**
|
|
227
321
|
\`\`\`bash
|
|
322
|
+
# Edit .env and set your API key
|
|
228
323
|
npx opc run
|
|
229
324
|
\`\`\`
|
|
230
325
|
|
|
231
326
|
4. **Open browser:** [http://localhost:3000](http://localhost:3000)
|
|
232
327
|
|
|
233
|
-
##
|
|
328
|
+
## Development
|
|
234
329
|
|
|
235
330
|
\`\`\`bash
|
|
236
|
-
npx opc
|
|
331
|
+
npx opc dev # Hot-reload mode
|
|
332
|
+
npx opc chat # CLI chat
|
|
333
|
+
\`\`\`
|
|
334
|
+
|
|
335
|
+
## Project Structure
|
|
336
|
+
|
|
337
|
+
\`\`\`
|
|
338
|
+
${name}/
|
|
339
|
+
├── agent.yaml # OAD agent config (used by src/index.ts)
|
|
340
|
+
├── oad.yaml # OAD config (used by opc CLI)
|
|
341
|
+
├── src/
|
|
342
|
+
│ ├── index.ts # Entry point
|
|
343
|
+
│ └── skills/
|
|
344
|
+
│ └── echo.ts # Example skill
|
|
345
|
+
├── package.json
|
|
346
|
+
└── tsconfig.json
|
|
237
347
|
\`\`\`
|
|
238
348
|
|
|
239
349
|
## Configuration
|
|
240
350
|
|
|
241
|
-
Edit \`
|
|
351
|
+
Edit \`agent.yaml\` to customize your agent's personality, skills, and behavior.
|
|
242
352
|
`);
|
|
243
353
|
console.log(`\n${icon.success} Created agent project: ${color.bold(name + '/')}`);
|
|
244
|
-
console.log(` ${icon.file}
|
|
245
|
-
console.log(` ${icon.file}
|
|
246
|
-
console.log(` ${icon.file} .
|
|
247
|
-
console.log(` ${icon.file} .
|
|
354
|
+
console.log(` ${icon.file} agent.yaml - Agent definition (OAD)`);
|
|
355
|
+
console.log(` ${icon.file} src/index.ts - Entry point`);
|
|
356
|
+
console.log(` ${icon.file} src/skills/echo.ts - Example skill`);
|
|
357
|
+
console.log(` ${icon.file} package.json - Dependencies`);
|
|
358
|
+
console.log(` ${icon.file} tsconfig.json - TypeScript config`);
|
|
359
|
+
console.log(` ${icon.file} .env.example - Environment template`);
|
|
248
360
|
console.log(` ${icon.file} .gitignore`);
|
|
249
361
|
console.log(` ${icon.file} Dockerfile`);
|
|
250
|
-
console.log(` ${icon.file} docker-compose.yml`);
|
|
251
362
|
console.log(` ${icon.file} README.md`);
|
|
252
363
|
console.log(`\n Template: ${color.cyan(template)}`);
|
|
253
364
|
console.log(`\n${color.bold('Next steps:')}`);
|
|
254
365
|
console.log(` 1. cd ${name}`);
|
|
255
|
-
console.log(` 2.
|
|
256
|
-
console.log(` 3.
|
|
257
|
-
console.log(` 4.
|
|
258
|
-
console.log(` 5. Open http://localhost:3000\n`);
|
|
366
|
+
console.log(` 2. npm install`);
|
|
367
|
+
console.log(` 3. npx tsx src/index.ts ${color.dim('# or: npx opc run')}`);
|
|
368
|
+
console.log(` 4. Open http://localhost:3000\n`);
|
|
259
369
|
});
|
|
260
370
|
// ── Chat command ─────────────────────────────────────────────
|
|
261
371
|
program
|
|
@@ -684,51 +794,23 @@ kbCmd.command('clear').action(() => {
|
|
|
684
794
|
kb.clear();
|
|
685
795
|
console.log(`${icon.success} Knowledge base cleared.`);
|
|
686
796
|
});
|
|
687
|
-
// 📦
|
|
797
|
+
// 📦 Package commands ───────────────────────────────────
|
|
688
798
|
program
|
|
689
799
|
.command('publish')
|
|
690
800
|
.description('Package agent for distribution')
|
|
691
801
|
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
692
802
|
.option('-o, --output <dir>', 'Output directory', '.')
|
|
693
803
|
.option('--include-kb', 'Include knowledge base')
|
|
694
|
-
.action(async (
|
|
695
|
-
|
|
696
|
-
console.log(`\n${icon.package} Packaging agent...\n`);
|
|
697
|
-
const result = await (0, marketplace_1.publishAgent)({
|
|
698
|
-
oadPath: opts.file,
|
|
699
|
-
outputDir: opts.output,
|
|
700
|
-
includeKnowledge: opts.includeKb,
|
|
701
|
-
});
|
|
702
|
-
console.log(`${icon.success} Published: ${color.bold(result.archivePath)}`);
|
|
703
|
-
console.log(` Name: ${result.manifest.name}`);
|
|
704
|
-
console.log(` Version: ${result.manifest.version}`);
|
|
705
|
-
console.log(` Files: ${result.manifest.files.length}`);
|
|
706
|
-
console.log();
|
|
707
|
-
}
|
|
708
|
-
catch (err) {
|
|
709
|
-
console.error(`${icon.error} Publish failed:`, err instanceof Error ? err.message : err);
|
|
710
|
-
process.exit(1);
|
|
711
|
-
}
|
|
804
|
+
.action(async () => {
|
|
805
|
+
console.log(`\n${icon.package} Agent packaging coming soon.\n`);
|
|
712
806
|
});
|
|
713
807
|
program
|
|
714
808
|
.command('install')
|
|
715
809
|
.description('Install agent from package')
|
|
716
810
|
.argument('<source>', 'Package file path or URL')
|
|
717
811
|
.option('-d, --dir <dir>', 'Install directory')
|
|
718
|
-
.action(async (
|
|
719
|
-
|
|
720
|
-
console.log(`\n${icon.package} Installing agent from ${color.bold(source)}...\n`);
|
|
721
|
-
const result = await (0, marketplace_1.installAgent)({ source, targetDir: opts.dir });
|
|
722
|
-
console.log(`${icon.success} Installed: ${color.bold(result.manifest.name)} v${result.manifest.version}`);
|
|
723
|
-
console.log(` Directory: ${result.dir}`);
|
|
724
|
-
console.log(`\n${color.bold('Next steps:')}`);
|
|
725
|
-
console.log(` cd ${result.dir}`);
|
|
726
|
-
console.log(` opc run\n`);
|
|
727
|
-
}
|
|
728
|
-
catch (err) {
|
|
729
|
-
console.error(`${icon.error} Install failed:`, err instanceof Error ? err.message : err);
|
|
730
|
-
process.exit(1);
|
|
731
|
-
}
|
|
812
|
+
.action(async () => {
|
|
813
|
+
console.log(`\n${icon.package} Agent install coming soon.\n`);
|
|
732
814
|
});
|
|
733
815
|
// 🔌 Plugin commands ────────────────────────────────────────
|
|
734
816
|
const pluginCmd = program.command('plugin').description('Manage plugins');
|
|
@@ -838,5 +920,118 @@ program
|
|
|
838
920
|
process.exit(1);
|
|
839
921
|
}
|
|
840
922
|
});
|
|
923
|
+
// ── Brain command ────────────────────────────────────────────
|
|
924
|
+
program
|
|
925
|
+
.command('brain')
|
|
926
|
+
.description('Show agent memory/brain status from DeepBrain')
|
|
927
|
+
.option('--url <url>', 'DeepBrain server URL', 'http://localhost:3333')
|
|
928
|
+
.action(async (opts) => {
|
|
929
|
+
console.log(`\n${icon.gear} ${color.bold('DeepBrain Status')} — ${color.dim(opts.url)}\n`);
|
|
930
|
+
try {
|
|
931
|
+
const res = await fetch(`${opts.url}/api/stats`);
|
|
932
|
+
if (!res.ok)
|
|
933
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
934
|
+
const stats = (await res.json());
|
|
935
|
+
const rows = [
|
|
936
|
+
['Total Pages', String(stats.totalPages ?? stats.pages ?? '-')],
|
|
937
|
+
['Total Chunks', String(stats.totalChunks ?? stats.chunks ?? '-')],
|
|
938
|
+
['Memory Tiers', String(stats.memoryTiers ?? stats.tiers ?? '-')],
|
|
939
|
+
['Index Size', stats.indexSize ?? '-'],
|
|
940
|
+
['Last Updated', stats.lastUpdated ?? stats.updatedAt ?? '-'],
|
|
941
|
+
];
|
|
942
|
+
const maxKey = Math.max(...rows.map(([k]) => k.length));
|
|
943
|
+
for (const [key, val] of rows) {
|
|
944
|
+
console.log(` ${color.cyan(key.padEnd(maxKey))} ${val}`);
|
|
945
|
+
}
|
|
946
|
+
console.log();
|
|
947
|
+
}
|
|
948
|
+
catch (err) {
|
|
949
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
950
|
+
if (msg.includes('ECONNREFUSED') || msg.includes('fetch failed')) {
|
|
951
|
+
console.log(` ${icon.warn} Cannot connect to DeepBrain at ${opts.url}`);
|
|
952
|
+
console.log(` ${color.dim('Is the server running? Start with: deepbrain serve')}\n`);
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
console.error(` ${icon.error} ${msg}\n`);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
// ── Logs command ─────────────────────────────────────────────
|
|
960
|
+
program
|
|
961
|
+
.command('logs')
|
|
962
|
+
.description('Show recent agent traces')
|
|
963
|
+
.option('-n, --limit <n>', 'Number of spans to show', '20')
|
|
964
|
+
.option('-f, --follow', 'Keep watching for new spans')
|
|
965
|
+
.action(async (opts) => {
|
|
966
|
+
const { TraceCollector } = await Promise.resolve().then(() => __importStar(require('./traces')));
|
|
967
|
+
const collector = new TraceCollector();
|
|
968
|
+
const limit = parseInt(opts.limit) || 20;
|
|
969
|
+
const printSpans = (spans) => {
|
|
970
|
+
const slice = spans.slice(-limit);
|
|
971
|
+
if (slice.length === 0) {
|
|
972
|
+
console.log(` ${icon.info} No traces yet. Interact with the agent to generate traces.`);
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
for (const span of slice) {
|
|
976
|
+
const duration = span.endTime
|
|
977
|
+
? `${span.endTime.getTime() - span.startTime.getTime()}ms`
|
|
978
|
+
: 'ongoing';
|
|
979
|
+
const statusIcon = span.status === 'ok' ? icon.success : span.status === 'error' ? icon.error : color.dim('○');
|
|
980
|
+
const time = span.startTime.toLocaleTimeString();
|
|
981
|
+
console.log(` ${statusIcon} ${color.dim(time)} ${color.bold(span.name)} ${color.dim(duration)}`);
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
console.log(`\n${icon.gear} ${color.bold('Agent Traces')}\n`);
|
|
985
|
+
const spans = collector.getBufferedSpans();
|
|
986
|
+
printSpans(spans);
|
|
987
|
+
if (opts.follow) {
|
|
988
|
+
console.log(`\n ${color.dim('Watching for new traces... (Ctrl+C to stop)')}\n`);
|
|
989
|
+
let lastCount = spans.length;
|
|
990
|
+
const interval = setInterval(() => {
|
|
991
|
+
const current = collector.getBufferedSpans();
|
|
992
|
+
if (current.length > lastCount) {
|
|
993
|
+
const newSpans = current.slice(lastCount);
|
|
994
|
+
printSpans(newSpans);
|
|
995
|
+
lastCount = current.length;
|
|
996
|
+
}
|
|
997
|
+
}, 1000);
|
|
998
|
+
process.on('SIGINT', () => { clearInterval(interval); process.exit(0); });
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
console.log();
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
// ── Score command ────────────────────────────────────────────
|
|
1005
|
+
program
|
|
1006
|
+
.command('score')
|
|
1007
|
+
.description('Show agent performance score')
|
|
1008
|
+
.action(async () => {
|
|
1009
|
+
console.log(`\n${icon.gear} ${color.bold('Agent Performance Score')}\n`);
|
|
1010
|
+
try {
|
|
1011
|
+
const engine = new analytics_engine_1.AnalyticsEngine('.');
|
|
1012
|
+
const stats = engine.getStats();
|
|
1013
|
+
if (!stats || stats.totalMessages === 0) {
|
|
1014
|
+
console.log(` ${icon.info} No score data yet. Run the agent first.\n`);
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
const errorRate = stats.totalMessages > 0 ? (stats.totalErrors / stats.totalMessages) : 0;
|
|
1018
|
+
const rows = [
|
|
1019
|
+
['Total Messages', String(stats.totalMessages)],
|
|
1020
|
+
['Total LLM Calls', String(stats.totalLLMCalls)],
|
|
1021
|
+
['Total Tool Uses', String(stats.totalToolUses)],
|
|
1022
|
+
['Avg Response Time', `${stats.avgResponseTimeMs}ms`],
|
|
1023
|
+
['Error Rate', `${(errorRate * 100).toFixed(1)}%`],
|
|
1024
|
+
['Token Usage', `${stats.totalTokens.total} tokens (in: ${stats.totalTokens.input}, out: ${stats.totalTokens.output})`],
|
|
1025
|
+
];
|
|
1026
|
+
const maxKey = Math.max(...rows.map(([k]) => k.length));
|
|
1027
|
+
for (const [key, val] of rows) {
|
|
1028
|
+
console.log(` ${color.cyan(key.padEnd(maxKey))} ${val}`);
|
|
1029
|
+
}
|
|
1030
|
+
console.log();
|
|
1031
|
+
}
|
|
1032
|
+
catch {
|
|
1033
|
+
console.log(` ${icon.info} No score data yet. Run the agent first.\n`);
|
|
1034
|
+
}
|
|
1035
|
+
});
|
|
841
1036
|
program.parse();
|
|
842
1037
|
//# sourceMappingURL=cli.js.map
|
package/dist/core/runtime.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseAgent } from './agent';
|
|
2
|
+
import { Analytics } from '../analytics';
|
|
2
3
|
import type { OADDocument } from '../schema/oad';
|
|
3
4
|
import type { ISkill } from './types';
|
|
4
5
|
export declare function truncateOutput(output: string, maxChars?: number): string;
|
|
@@ -9,6 +10,7 @@ export declare class AgentRuntime {
|
|
|
9
10
|
private historyLimit;
|
|
10
11
|
private shutdownHandlers;
|
|
11
12
|
private isShuttingDown;
|
|
13
|
+
private analytics;
|
|
12
14
|
loadConfig(filePath: string): Promise<OADDocument>;
|
|
13
15
|
setHistoryLimit(limit: number): void;
|
|
14
16
|
initialize(config?: OADDocument): Promise<BaseAgent>;
|
|
@@ -18,5 +20,7 @@ export declare class AgentRuntime {
|
|
|
18
20
|
private setupGracefulShutdown;
|
|
19
21
|
registerSkill(skill: ISkill): void;
|
|
20
22
|
getAgent(): BaseAgent | null;
|
|
23
|
+
getAnalytics(): Analytics;
|
|
24
|
+
getConfig(): OADDocument | null;
|
|
21
25
|
}
|
|
22
26
|
//# sourceMappingURL=runtime.d.ts.map
|