opc-agent 0.1.0 ā 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/CONTRIBUTING.md +75 -0
- package/README.md +105 -116
- package/README.zh-CN.md +58 -96
- package/dist/analytics/index.d.ts +31 -0
- package/dist/analytics/index.js +52 -0
- package/dist/channels/telegram.d.ts +21 -0
- package/dist/channels/telegram.js +120 -0
- package/dist/channels/websocket.d.ts +15 -0
- package/dist/channels/websocket.js +81 -0
- package/dist/cli.js +261 -27
- package/dist/core/agent.d.ts +2 -0
- package/dist/core/agent.js +3 -1
- package/dist/core/logger.d.ts +19 -0
- package/dist/core/logger.js +50 -0
- package/dist/core/room.d.ts +24 -0
- package/dist/core/room.js +97 -0
- package/dist/core/runtime.d.ts +11 -0
- package/dist/core/runtime.js +76 -0
- package/dist/core/sandbox.d.ts +28 -0
- package/dist/core/sandbox.js +118 -0
- package/dist/i18n/index.d.ts +13 -0
- package/dist/i18n/index.js +73 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.js +28 -1
- package/dist/memory/deepbrain.d.ts +40 -0
- package/dist/memory/deepbrain.js +135 -0
- package/dist/plugins/index.d.ts +47 -0
- package/dist/plugins/index.js +59 -0
- package/dist/schema/oad.d.ts +294 -36
- package/dist/schema/oad.js +22 -3
- package/dist/templates/code-reviewer.d.ts +41 -0
- package/dist/templates/code-reviewer.js +38 -0
- package/dist/templates/content-writer.d.ts +36 -0
- package/dist/templates/content-writer.js +52 -0
- package/dist/templates/hr-recruiter.d.ts +36 -0
- package/dist/templates/hr-recruiter.js +52 -0
- package/dist/templates/knowledge-base.d.ts +44 -0
- package/dist/templates/knowledge-base.js +35 -0
- package/dist/templates/project-manager.d.ts +36 -0
- package/dist/templates/project-manager.js +52 -0
- package/dist/templates/sales-assistant.d.ts +56 -0
- package/dist/templates/sales-assistant.js +79 -0
- package/dist/tools/mcp.d.ts +32 -0
- package/dist/tools/mcp.js +49 -0
- package/package.json +11 -2
- package/src/analytics/index.ts +66 -0
- package/src/channels/telegram.ts +90 -0
- package/src/channels/websocket.ts +87 -0
- package/src/cli.ts +286 -33
- package/src/core/agent.ts +4 -1
- package/src/core/logger.ts +57 -0
- package/src/core/room.ts +109 -0
- package/src/core/runtime.ts +79 -1
- package/src/core/sandbox.ts +101 -0
- package/src/i18n/index.ts +79 -0
- package/src/index.ts +19 -1
- package/src/memory/deepbrain.ts +108 -0
- package/src/plugins/index.ts +87 -0
- package/src/schema/oad.ts +24 -2
- package/src/templates/code-reviewer.ts +34 -0
- package/src/templates/content-writer.ts +58 -0
- package/src/templates/hr-recruiter.ts +58 -0
- package/src/templates/knowledge-base.ts +31 -0
- package/src/templates/project-manager.ts +58 -0
- package/src/templates/sales-assistant.ts +79 -0
- package/src/tools/mcp.ts +76 -0
- package/templates/code-reviewer/README.md +27 -0
- package/templates/code-reviewer/oad.yaml +41 -0
- package/templates/knowledge-base/README.md +28 -0
- package/templates/knowledge-base/oad.yaml +38 -0
- package/templates/sales-assistant/README.md +26 -0
- package/templates/sales-assistant/oad.yaml +43 -0
- package/tests/analytics.test.ts +50 -0
- package/tests/i18n.test.ts +41 -0
- package/tests/mcp.test.ts +54 -0
- package/tests/plugin.test.ts +74 -0
- package/tests/room.test.ts +106 -0
- package/tests/sandbox.test.ts +46 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BaseChannel } from './index';
|
|
2
|
+
/**
|
|
3
|
+
* Telegram channel ā basic webhook handler for Telegram Bot API.
|
|
4
|
+
* Set TELEGRAM_BOT_TOKEN env var or pass in config.
|
|
5
|
+
*/
|
|
6
|
+
export declare class TelegramChannel extends BaseChannel {
|
|
7
|
+
readonly type = "telegram";
|
|
8
|
+
private token;
|
|
9
|
+
private webhookUrl?;
|
|
10
|
+
private server;
|
|
11
|
+
private port;
|
|
12
|
+
constructor(options?: {
|
|
13
|
+
token?: string;
|
|
14
|
+
webhookUrl?: string;
|
|
15
|
+
port?: number;
|
|
16
|
+
});
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
stop(): Promise<void>;
|
|
19
|
+
private sendMessage;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=telegram.d.ts.map
|
|
@@ -0,0 +1,120 @@
|
|
|
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.TelegramChannel = void 0;
|
|
37
|
+
const index_1 = require("./index");
|
|
38
|
+
/**
|
|
39
|
+
* Telegram channel ā basic webhook handler for Telegram Bot API.
|
|
40
|
+
* Set TELEGRAM_BOT_TOKEN env var or pass in config.
|
|
41
|
+
*/
|
|
42
|
+
class TelegramChannel extends index_1.BaseChannel {
|
|
43
|
+
type = 'telegram';
|
|
44
|
+
token;
|
|
45
|
+
webhookUrl;
|
|
46
|
+
server = null;
|
|
47
|
+
port;
|
|
48
|
+
constructor(options = {}) {
|
|
49
|
+
super();
|
|
50
|
+
this.token = options.token ?? process.env.TELEGRAM_BOT_TOKEN ?? '';
|
|
51
|
+
this.webhookUrl = options.webhookUrl;
|
|
52
|
+
this.port = options.port ?? 3001;
|
|
53
|
+
}
|
|
54
|
+
async start() {
|
|
55
|
+
if (!this.token) {
|
|
56
|
+
console.warn('[TelegramChannel] No bot token provided. Set TELEGRAM_BOT_TOKEN or pass token in config.');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const express = (await Promise.resolve().then(() => __importStar(require('express')))).default;
|
|
60
|
+
const app = express();
|
|
61
|
+
app.use(express.json());
|
|
62
|
+
app.post(`/webhook/${this.token}`, async (req, res) => {
|
|
63
|
+
try {
|
|
64
|
+
const update = req.body;
|
|
65
|
+
if (update.message?.text && this.handler) {
|
|
66
|
+
const msg = {
|
|
67
|
+
id: `tg_${update.message.message_id}`,
|
|
68
|
+
role: 'user',
|
|
69
|
+
content: update.message.text,
|
|
70
|
+
timestamp: update.message.date * 1000,
|
|
71
|
+
metadata: {
|
|
72
|
+
sessionId: `tg_${update.message.chat.id}`,
|
|
73
|
+
chatId: update.message.chat.id,
|
|
74
|
+
userId: update.message.from?.id,
|
|
75
|
+
platform: 'telegram',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const response = await this.handler(msg);
|
|
79
|
+
await this.sendMessage(update.message.chat.id, response.content);
|
|
80
|
+
}
|
|
81
|
+
res.json({ ok: true });
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
console.error('[TelegramChannel] Error handling update:', err);
|
|
85
|
+
res.status(500).json({ error: 'Internal error' });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
app.get('/health', (_req, res) => {
|
|
89
|
+
res.json({ status: 'ok', channel: 'telegram' });
|
|
90
|
+
});
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
this.server = app.listen(this.port, () => {
|
|
93
|
+
console.log(`[TelegramChannel] Webhook server on port ${this.port}`);
|
|
94
|
+
resolve();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async stop() {
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
if (!this.server)
|
|
101
|
+
return resolve();
|
|
102
|
+
this.server.close((err) => (err ? reject(err) : resolve()));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async sendMessage(chatId, text) {
|
|
106
|
+
const url = `https://api.telegram.org/bot${this.token}/sendMessage`;
|
|
107
|
+
try {
|
|
108
|
+
await fetch(url, {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: { 'Content-Type': 'application/json' },
|
|
111
|
+
body: JSON.stringify({ chat_id: chatId, text, parse_mode: 'Markdown' }),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
console.error('[TelegramChannel] Failed to send message:', err);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.TelegramChannel = TelegramChannel;
|
|
120
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseChannel } from './index';
|
|
2
|
+
/**
|
|
3
|
+
* WebSocket channel ā real-time bidirectional communication.
|
|
4
|
+
*/
|
|
5
|
+
export declare class WebSocketChannel extends BaseChannel {
|
|
6
|
+
readonly type = "websocket";
|
|
7
|
+
private wss;
|
|
8
|
+
private port;
|
|
9
|
+
private clients;
|
|
10
|
+
constructor(port?: number);
|
|
11
|
+
start(): Promise<void>;
|
|
12
|
+
stop(): Promise<void>;
|
|
13
|
+
broadcast(content: string): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebSocketChannel = void 0;
|
|
4
|
+
const index_1 = require("./index");
|
|
5
|
+
const ws_1 = require("ws");
|
|
6
|
+
/**
|
|
7
|
+
* WebSocket channel ā real-time bidirectional communication.
|
|
8
|
+
*/
|
|
9
|
+
class WebSocketChannel extends index_1.BaseChannel {
|
|
10
|
+
type = 'websocket';
|
|
11
|
+
wss = null;
|
|
12
|
+
port;
|
|
13
|
+
clients = new Set();
|
|
14
|
+
constructor(port = 3002) {
|
|
15
|
+
super();
|
|
16
|
+
this.port = port;
|
|
17
|
+
}
|
|
18
|
+
async start() {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
this.wss = new ws_1.WebSocketServer({ port: this.port });
|
|
21
|
+
this.wss.on('connection', (ws) => {
|
|
22
|
+
this.clients.add(ws);
|
|
23
|
+
ws.on('message', async (data) => {
|
|
24
|
+
if (!this.handler)
|
|
25
|
+
return;
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(data.toString());
|
|
28
|
+
const msg = {
|
|
29
|
+
id: parsed.id ?? `ws_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
30
|
+
role: 'user',
|
|
31
|
+
content: parsed.content ?? parsed.message ?? data.toString(),
|
|
32
|
+
timestamp: Date.now(),
|
|
33
|
+
metadata: {
|
|
34
|
+
sessionId: parsed.sessionId ?? 'ws-default',
|
|
35
|
+
platform: 'websocket',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
const response = await this.handler(msg);
|
|
39
|
+
ws.send(JSON.stringify({
|
|
40
|
+
id: response.id,
|
|
41
|
+
content: response.content,
|
|
42
|
+
timestamp: response.timestamp,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
ws.send(JSON.stringify({ error: 'Invalid message format' }));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
ws.on('close', () => {
|
|
50
|
+
this.clients.delete(ws);
|
|
51
|
+
});
|
|
52
|
+
ws.send(JSON.stringify({ type: 'connected', timestamp: Date.now() }));
|
|
53
|
+
});
|
|
54
|
+
this.wss.on('listening', () => {
|
|
55
|
+
console.log(`[WebSocketChannel] Listening on port ${this.port}`);
|
|
56
|
+
resolve();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async stop() {
|
|
61
|
+
for (const client of this.clients) {
|
|
62
|
+
client.close();
|
|
63
|
+
}
|
|
64
|
+
this.clients.clear();
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
if (!this.wss)
|
|
67
|
+
return resolve();
|
|
68
|
+
this.wss.close((err) => (err ? reject(err) : resolve()));
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
broadcast(content) {
|
|
72
|
+
const msg = JSON.stringify({ type: 'broadcast', content, timestamp: Date.now() });
|
|
73
|
+
for (const client of this.clients) {
|
|
74
|
+
if (client.readyState === 1) { // OPEN
|
|
75
|
+
client.send(msg);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.WebSocketChannel = WebSocketChannel;
|
|
81
|
+
//# sourceMappingURL=websocket.js.map
|
package/dist/cli.js
CHANGED
|
@@ -38,46 +38,148 @@ const commander_1 = require("commander");
|
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const yaml = __importStar(require("js-yaml"));
|
|
41
|
+
const readline = __importStar(require("readline"));
|
|
41
42
|
const runtime_1 = require("./core/runtime");
|
|
42
43
|
const customer_service_1 = require("./templates/customer-service");
|
|
44
|
+
const sales_assistant_1 = require("./templates/sales-assistant");
|
|
45
|
+
const knowledge_base_1 = require("./templates/knowledge-base");
|
|
46
|
+
const code_reviewer_1 = require("./templates/code-reviewer");
|
|
47
|
+
const hr_recruiter_1 = require("./templates/hr-recruiter");
|
|
48
|
+
const project_manager_1 = require("./templates/project-manager");
|
|
49
|
+
const content_writer_1 = require("./templates/content-writer");
|
|
43
50
|
const customer_service_2 = require("./templates/customer-service");
|
|
51
|
+
const analytics_1 = require("./analytics");
|
|
44
52
|
const program = new commander_1.Command();
|
|
53
|
+
const color = {
|
|
54
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
55
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
56
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
57
|
+
blue: (s) => `\x1b[34m${s}\x1b[0m`,
|
|
58
|
+
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
59
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
60
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
61
|
+
};
|
|
62
|
+
const icon = {
|
|
63
|
+
success: color.green('ā'),
|
|
64
|
+
error: color.red('ā'),
|
|
65
|
+
warn: color.yellow('ā '),
|
|
66
|
+
info: color.blue('ā¹'),
|
|
67
|
+
rocket: 'š',
|
|
68
|
+
package: 'š¦',
|
|
69
|
+
search: 'š',
|
|
70
|
+
gear: 'āļø',
|
|
71
|
+
file: 'š',
|
|
72
|
+
};
|
|
73
|
+
const TEMPLATES = {
|
|
74
|
+
'customer-service': { label: 'Customer Service ā FAQ + human handoff', factory: customer_service_1.createCustomerServiceConfig },
|
|
75
|
+
'sales-assistant': { label: 'Sales Assistant ā product Q&A + lead capture', factory: sales_assistant_1.createSalesAssistantConfig },
|
|
76
|
+
'knowledge-base': { label: 'Knowledge Base ā RAG with DeepBrain', factory: knowledge_base_1.createKnowledgeBaseConfig },
|
|
77
|
+
'code-reviewer': { label: 'Code Reviewer ā bug detection + style checks', factory: code_reviewer_1.createCodeReviewerConfig },
|
|
78
|
+
'hr-recruiter': { label: 'HR Recruiter ā resume screening + interview scheduling', factory: hr_recruiter_1.createHRRecruiterConfig },
|
|
79
|
+
'project-manager': { label: 'Project Manager ā task tracking + meeting notes', factory: project_manager_1.createProjectManagerConfig },
|
|
80
|
+
'content-writer': { label: 'Content Writer ā blog posts + social media + SEO', factory: content_writer_1.createContentWriterConfig },
|
|
81
|
+
};
|
|
82
|
+
async function prompt(question, defaultValue) {
|
|
83
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
84
|
+
const suffix = defaultValue ? ` ${color.dim(`(${defaultValue})`)}` : '';
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
rl.question(`${question}${suffix}: `, (answer) => {
|
|
87
|
+
rl.close();
|
|
88
|
+
resolve(answer.trim() || defaultValue || '');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async function select(question, options) {
|
|
93
|
+
console.log(`\n${question}`);
|
|
94
|
+
options.forEach((opt, i) => {
|
|
95
|
+
console.log(` ${color.cyan(`${i + 1})`)} ${opt.label}`);
|
|
96
|
+
});
|
|
97
|
+
const answer = await prompt(`\nChoose ${color.dim('(1-' + options.length + ')')}`, '1');
|
|
98
|
+
const idx = parseInt(answer) - 1;
|
|
99
|
+
return options[Math.max(0, Math.min(idx, options.length - 1))].value;
|
|
100
|
+
}
|
|
45
101
|
program
|
|
46
102
|
.name('opc')
|
|
47
103
|
.description('OPC Agent ā Open Agent Framework for business workstations')
|
|
48
|
-
.version('0.
|
|
104
|
+
.version('0.3.0');
|
|
49
105
|
program
|
|
50
106
|
.command('init')
|
|
51
|
-
.description('Initialize a new OPC agent project')
|
|
52
|
-
.argument('[name]', 'Project name'
|
|
53
|
-
.option('-t, --template <template>', 'Template to use'
|
|
54
|
-
.
|
|
107
|
+
.description('Initialize a new OPC agent project (interactive)')
|
|
108
|
+
.argument('[name]', 'Project name')
|
|
109
|
+
.option('-t, --template <template>', 'Template to use')
|
|
110
|
+
.option('-y, --yes', 'Skip prompts, use defaults')
|
|
111
|
+
.action(async (nameArg, opts) => {
|
|
112
|
+
console.log(`\n${icon.rocket} ${color.bold('OPC Agent ā Create New Project')}\n`);
|
|
113
|
+
const name = opts.yes ? (nameArg ?? 'my-agent') : (nameArg ?? await prompt('Project name', 'my-agent'));
|
|
114
|
+
const template = opts.yes
|
|
115
|
+
? (opts.template ?? 'customer-service')
|
|
116
|
+
: (opts.template ?? await select('Select a template:', Object.entries(TEMPLATES).map(([value, { label }]) => ({ value, label }))));
|
|
55
117
|
const dir = path.resolve(name);
|
|
56
118
|
if (fs.existsSync(dir)) {
|
|
57
|
-
console.error(
|
|
119
|
+
console.error(`\n${icon.error} Directory ${color.bold(name)} already exists.`);
|
|
58
120
|
process.exit(1);
|
|
59
121
|
}
|
|
60
122
|
fs.mkdirSync(dir, { recursive: true });
|
|
61
|
-
const
|
|
123
|
+
const factory = TEMPLATES[template]?.factory ?? customer_service_1.createCustomerServiceConfig;
|
|
124
|
+
const config = factory();
|
|
62
125
|
config.metadata.name = name;
|
|
63
126
|
fs.writeFileSync(path.join(dir, 'oad.yaml'), yaml.dump(config, { lineWidth: 120 }));
|
|
64
|
-
fs.writeFileSync(path.join(dir, 'README.md'), `# ${name}\n\nCreated with OPC Agent.\n\n## Run\n\n\`\`\`bash\nopc run\n\`\`\`\n`);
|
|
65
|
-
console.log(
|
|
66
|
-
console.log(`
|
|
67
|
-
console.log(`
|
|
68
|
-
console.log(`\
|
|
127
|
+
fs.writeFileSync(path.join(dir, 'README.md'), `# ${name}\n\nCreated with OPC Agent using the \`${template}\` template.\n\n## Run\n\n\`\`\`bash\nopc run\n\`\`\`\n`);
|
|
128
|
+
console.log(`\n${icon.success} Created agent project: ${color.bold(name + '/')}`);
|
|
129
|
+
console.log(` ${icon.file} oad.yaml ā Agent definition`);
|
|
130
|
+
console.log(` ${icon.file} README.md`);
|
|
131
|
+
console.log(`\n Template: ${color.cyan(template)}`);
|
|
132
|
+
console.log(`\n${color.dim('Next:')} cd ${name} && opc run\n`);
|
|
69
133
|
});
|
|
70
134
|
program
|
|
71
135
|
.command('create')
|
|
72
136
|
.description('Create an agent from a template')
|
|
73
137
|
.argument('<name>', 'Agent name')
|
|
74
138
|
.option('-t, --template <template>', 'Template', 'customer-service')
|
|
75
|
-
.action(async (name) => {
|
|
76
|
-
const
|
|
139
|
+
.action(async (name, opts) => {
|
|
140
|
+
const factory = TEMPLATES[opts.template]?.factory ?? customer_service_1.createCustomerServiceConfig;
|
|
141
|
+
const config = factory();
|
|
77
142
|
config.metadata.name = name;
|
|
78
143
|
const outFile = `${name}-oad.yaml`;
|
|
79
144
|
fs.writeFileSync(outFile, yaml.dump(config, { lineWidth: 120 }));
|
|
80
|
-
console.log(
|
|
145
|
+
console.log(`${icon.success} Created ${color.bold(outFile)}`);
|
|
146
|
+
});
|
|
147
|
+
program
|
|
148
|
+
.command('info')
|
|
149
|
+
.description('Show agent info from OAD')
|
|
150
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
151
|
+
.action(async (opts) => {
|
|
152
|
+
try {
|
|
153
|
+
const runtime = new runtime_1.AgentRuntime();
|
|
154
|
+
const config = await runtime.loadConfig(opts.file);
|
|
155
|
+
const m = config.metadata;
|
|
156
|
+
const s = config.spec;
|
|
157
|
+
console.log(`\n${icon.gear} ${color.bold('Agent Info')}\n`);
|
|
158
|
+
console.log(` Name: ${color.cyan(m.name)}`);
|
|
159
|
+
console.log(` Version: ${m.version}`);
|
|
160
|
+
console.log(` Description: ${m.description ?? color.dim('(none)')}`);
|
|
161
|
+
console.log(` Author: ${m.author ?? color.dim('(none)')}`);
|
|
162
|
+
console.log(` License: ${m.license}`);
|
|
163
|
+
console.log(` Model: ${s.model}`);
|
|
164
|
+
console.log(` Provider: ${s.provider?.default ?? 'deepseek'}`);
|
|
165
|
+
console.log(` Channels: ${s.channels.map(c => c.type).join(', ') || color.dim('(none)')}`);
|
|
166
|
+
console.log(` Skills: ${s.skills.map(sk => sk.name).join(', ') || color.dim('(none)')}`);
|
|
167
|
+
console.log(` Trust: ${s.dtv?.trust?.level ?? 'sandbox'}`);
|
|
168
|
+
console.log(` Streaming: ${s.streaming ? 'enabled' : 'disabled'}`);
|
|
169
|
+
console.log(` Locale: ${s.locale ?? 'en'}`);
|
|
170
|
+
if (s.room) {
|
|
171
|
+
console.log(` Room: ${s.room.name}`);
|
|
172
|
+
}
|
|
173
|
+
if (m.marketplace) {
|
|
174
|
+
console.log(` Category: ${m.marketplace.category ?? color.dim('(none)')}`);
|
|
175
|
+
console.log(` Pricing: ${m.marketplace.pricing ?? 'free'}`);
|
|
176
|
+
}
|
|
177
|
+
console.log();
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
console.error(`${icon.error} Failed to read OAD:`, err instanceof Error ? err.message : err);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
81
183
|
});
|
|
82
184
|
program
|
|
83
185
|
.command('build')
|
|
@@ -87,10 +189,10 @@ program
|
|
|
87
189
|
try {
|
|
88
190
|
const runtime = new runtime_1.AgentRuntime();
|
|
89
191
|
const config = await runtime.loadConfig(opts.file);
|
|
90
|
-
console.log(
|
|
192
|
+
console.log(`${icon.success} Valid OAD: ${color.bold(config.metadata.name)} v${config.metadata.version}`);
|
|
91
193
|
}
|
|
92
194
|
catch (err) {
|
|
93
|
-
console.error(
|
|
195
|
+
console.error(`${icon.error} Invalid OAD:`, err instanceof Error ? err.message : err);
|
|
94
196
|
process.exit(1);
|
|
95
197
|
}
|
|
96
198
|
});
|
|
@@ -99,15 +201,15 @@ program
|
|
|
99
201
|
.description('Run agent in sandbox mode')
|
|
100
202
|
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
101
203
|
.action(async (opts) => {
|
|
102
|
-
console.log(
|
|
204
|
+
console.log(`\n${icon.gear} Running agent in sandbox mode...`);
|
|
103
205
|
const runtime = new runtime_1.AgentRuntime();
|
|
104
206
|
await runtime.loadConfig(opts.file);
|
|
105
207
|
const agent = await runtime.initialize();
|
|
106
208
|
runtime.registerSkill(new customer_service_2.FAQSkill());
|
|
107
209
|
runtime.registerSkill(new customer_service_2.HandoffSkill());
|
|
108
|
-
console.log(
|
|
210
|
+
console.log(`${icon.success} Agent "${color.bold(agent.name)}" initialized in sandbox.`);
|
|
109
211
|
console.log(` State: ${agent.state}`);
|
|
110
|
-
console.log(`
|
|
212
|
+
console.log(` Sending test message...`);
|
|
111
213
|
const response = await agent.handleMessage({
|
|
112
214
|
id: 'test_1',
|
|
113
215
|
role: 'user',
|
|
@@ -115,7 +217,7 @@ program
|
|
|
115
217
|
timestamp: Date.now(),
|
|
116
218
|
});
|
|
117
219
|
console.log(` Response: ${response.content}`);
|
|
118
|
-
console.log(
|
|
220
|
+
console.log(`${icon.success} Sandbox test passed.\n`);
|
|
119
221
|
});
|
|
120
222
|
program
|
|
121
223
|
.command('run')
|
|
@@ -129,18 +231,150 @@ program
|
|
|
129
231
|
runtime.registerSkill(new customer_service_2.HandoffSkill());
|
|
130
232
|
await runtime.start();
|
|
131
233
|
const agent = runtime.getAgent();
|
|
132
|
-
console.log(
|
|
234
|
+
console.log(`\n${icon.rocket} Agent "${color.bold(agent?.name ?? 'unknown')}" is running.\n`);
|
|
235
|
+
});
|
|
236
|
+
program
|
|
237
|
+
.command('dev')
|
|
238
|
+
.description('Hot-reload development mode')
|
|
239
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
240
|
+
.action(async (opts) => {
|
|
241
|
+
console.log(`\n${icon.gear} ${color.bold('Development mode')} ā watching for changes...\n`);
|
|
242
|
+
let runtime = null;
|
|
243
|
+
const startAgent = async () => {
|
|
244
|
+
try {
|
|
245
|
+
if (runtime)
|
|
246
|
+
await runtime.stop();
|
|
247
|
+
runtime = new runtime_1.AgentRuntime();
|
|
248
|
+
await runtime.loadConfig(opts.file);
|
|
249
|
+
await runtime.initialize();
|
|
250
|
+
runtime.registerSkill(new customer_service_2.FAQSkill());
|
|
251
|
+
runtime.registerSkill(new customer_service_2.HandoffSkill());
|
|
252
|
+
await runtime.start();
|
|
253
|
+
const agent = runtime.getAgent();
|
|
254
|
+
console.log(`${icon.success} Agent "${color.bold(agent?.name ?? 'unknown')}" restarted.`);
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
console.error(`${icon.error} Failed to start:`, err instanceof Error ? err.message : err);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
await startAgent();
|
|
261
|
+
const watchPaths = [opts.file, 'src'];
|
|
262
|
+
for (const watchPath of watchPaths) {
|
|
263
|
+
if (fs.existsSync(watchPath)) {
|
|
264
|
+
const isDir = fs.statSync(watchPath).isDirectory();
|
|
265
|
+
fs.watch(watchPath, { recursive: isDir }, async (_event, filename) => {
|
|
266
|
+
console.log(`\n${icon.info} ${color.dim(`Change detected: ${filename}`)} ā restarting...`);
|
|
267
|
+
await startAgent();
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
133
271
|
process.on('SIGINT', async () => {
|
|
134
|
-
console.log('
|
|
135
|
-
|
|
272
|
+
console.log(`\n${color.dim('Shutting down dev mode...')}`);
|
|
273
|
+
if (runtime)
|
|
274
|
+
await runtime.stop();
|
|
136
275
|
process.exit(0);
|
|
137
276
|
});
|
|
138
277
|
});
|
|
139
278
|
program
|
|
140
279
|
.command('publish')
|
|
141
|
-
.description('Validate and package for OPC Registry
|
|
142
|
-
.
|
|
143
|
-
|
|
280
|
+
.description('Validate and package for OPC Registry')
|
|
281
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
282
|
+
.action(async (opts) => {
|
|
283
|
+
try {
|
|
284
|
+
const runtime = new runtime_1.AgentRuntime();
|
|
285
|
+
const config = await runtime.loadConfig(opts.file);
|
|
286
|
+
const trust = config.spec.dtv?.trust?.level ?? 'sandbox';
|
|
287
|
+
console.log(`\n${icon.package} Publishing: ${color.bold(config.metadata.name)} v${config.metadata.version}`);
|
|
288
|
+
console.log(` ${icon.success} OAD validation passed`);
|
|
289
|
+
console.log(` š Trust level: ${trust}`);
|
|
290
|
+
if (trust === 'sandbox') {
|
|
291
|
+
console.log(` ${icon.warn} Trust level is 'sandbox'. Upgrade for marketplace listing.`);
|
|
292
|
+
}
|
|
293
|
+
const manifest = {
|
|
294
|
+
name: config.metadata.name,
|
|
295
|
+
version: config.metadata.version,
|
|
296
|
+
description: config.metadata.description,
|
|
297
|
+
author: config.metadata.author,
|
|
298
|
+
license: config.metadata.license,
|
|
299
|
+
trust,
|
|
300
|
+
category: config.metadata.marketplace?.category,
|
|
301
|
+
pricing: config.metadata.marketplace?.pricing ?? 'free',
|
|
302
|
+
tags: config.metadata.marketplace?.tags ?? [],
|
|
303
|
+
channels: config.spec.channels.map(c => c.type),
|
|
304
|
+
skills: config.spec.skills.map(s => s.name),
|
|
305
|
+
publishedAt: new Date().toISOString(),
|
|
306
|
+
};
|
|
307
|
+
fs.writeFileSync('opc-manifest.json', JSON.stringify(manifest, null, 2));
|
|
308
|
+
console.log(` ${icon.file} Generated opc-manifest.json`);
|
|
309
|
+
console.log(`\nš§ OPC Registry is coming soon. Manifest saved locally.\n`);
|
|
310
|
+
}
|
|
311
|
+
catch (err) {
|
|
312
|
+
console.error(`${icon.error} Publish failed:`, err instanceof Error ? err.message : err);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
program
|
|
317
|
+
.command('search')
|
|
318
|
+
.description('Search OPC Registry for agents and skills')
|
|
319
|
+
.argument('<query>', 'Search query')
|
|
320
|
+
.action(async (query) => {
|
|
321
|
+
console.log(`\n${icon.search} Searching OPC Registry for "${color.bold(query)}"...`);
|
|
322
|
+
console.log(`\nš§ OPC Registry coming soon!`);
|
|
323
|
+
console.log(` The marketplace is under development.`);
|
|
324
|
+
console.log(` Browse templates with: ${color.cyan('opc init --template <name>')}`);
|
|
325
|
+
console.log(`\n Available templates: ${Object.keys(TEMPLATES).map(t => color.cyan(t)).join(', ')}\n`);
|
|
326
|
+
});
|
|
327
|
+
// āā Tool commands āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
328
|
+
const toolCmd = program.command('tool').description('Manage MCP tools');
|
|
329
|
+
toolCmd
|
|
330
|
+
.command('list')
|
|
331
|
+
.description('List available MCP tools')
|
|
332
|
+
.action(() => {
|
|
333
|
+
console.log(`\n${icon.gear} ${color.bold('MCP Tools')}\n`);
|
|
334
|
+
console.log(` ${color.dim('No tools installed yet.')}`);
|
|
335
|
+
console.log(`\n Add tools with: ${color.cyan('opc tool add <name>')}\n`);
|
|
336
|
+
});
|
|
337
|
+
toolCmd
|
|
338
|
+
.command('add')
|
|
339
|
+
.description('Add an MCP tool from registry')
|
|
340
|
+
.argument('<name>', 'Tool name')
|
|
341
|
+
.action((name) => {
|
|
342
|
+
console.log(`\nš§ Tool registry coming soon!`);
|
|
343
|
+
console.log(` Would add tool: ${color.cyan(name)}\n`);
|
|
344
|
+
});
|
|
345
|
+
// āā Plugin commands āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
346
|
+
const pluginCmd = program.command('plugin').description('Manage plugins');
|
|
347
|
+
pluginCmd
|
|
348
|
+
.command('list')
|
|
349
|
+
.description('List installed plugins')
|
|
350
|
+
.action(() => {
|
|
351
|
+
console.log(`\n${icon.gear} ${color.bold('Installed Plugins')}\n`);
|
|
352
|
+
console.log(` ${color.dim('No plugins installed yet.')}`);
|
|
353
|
+
console.log(`\n Add plugins with: ${color.cyan('opc plugin add <name>')}\n`);
|
|
354
|
+
});
|
|
355
|
+
pluginCmd
|
|
356
|
+
.command('add')
|
|
357
|
+
.description('Add a plugin')
|
|
358
|
+
.argument('<name>', 'Plugin name')
|
|
359
|
+
.action((name) => {
|
|
360
|
+
console.log(`\nš§ Plugin registry coming soon!`);
|
|
361
|
+
console.log(` Would add plugin: ${color.cyan(name)}\n`);
|
|
362
|
+
});
|
|
363
|
+
// āā Stats command āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
364
|
+
program
|
|
365
|
+
.command('stats')
|
|
366
|
+
.description('Show agent analytics')
|
|
367
|
+
.action(() => {
|
|
368
|
+
const analytics = new analytics_1.Analytics();
|
|
369
|
+
// Show demo stats
|
|
370
|
+
const snap = analytics.getSnapshot();
|
|
371
|
+
console.log(`\n${icon.gear} ${color.bold('Agent Analytics')}\n`);
|
|
372
|
+
console.log(` Messages Processed: ${snap.messagesProcessed}`);
|
|
373
|
+
console.log(` Avg Response Time: ${snap.avgResponseTimeMs}ms`);
|
|
374
|
+
console.log(` Error Count: ${snap.errorCount}`);
|
|
375
|
+
console.log(` Token Usage: ${snap.tokenUsage.total} (in: ${snap.tokenUsage.input}, out: ${snap.tokenUsage.output})`);
|
|
376
|
+
console.log(` Uptime: ${Math.round(snap.uptime / 1000)}s`);
|
|
377
|
+
console.log(`\n ${color.dim('Run an agent to collect analytics data.')}\n`);
|
|
144
378
|
});
|
|
145
379
|
program.parse();
|
|
146
380
|
//# sourceMappingURL=cli.js.map
|
package/dist/core/agent.d.ts
CHANGED
|
@@ -8,12 +8,14 @@ export declare class BaseAgent extends EventEmitter implements IAgent {
|
|
|
8
8
|
private memory;
|
|
9
9
|
private provider;
|
|
10
10
|
private systemPrompt;
|
|
11
|
+
private historyLimit;
|
|
11
12
|
constructor(options: {
|
|
12
13
|
name: string;
|
|
13
14
|
systemPrompt?: string;
|
|
14
15
|
provider?: string;
|
|
15
16
|
model?: string;
|
|
16
17
|
memory?: MemoryStore;
|
|
18
|
+
historyLimit?: number;
|
|
17
19
|
});
|
|
18
20
|
get state(): AgentState;
|
|
19
21
|
private transition;
|
package/dist/core/agent.js
CHANGED
|
@@ -12,12 +12,14 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
12
12
|
memory;
|
|
13
13
|
provider;
|
|
14
14
|
systemPrompt;
|
|
15
|
+
historyLimit;
|
|
15
16
|
constructor(options) {
|
|
16
17
|
super();
|
|
17
18
|
this.name = options.name;
|
|
18
19
|
this.systemPrompt = options.systemPrompt ?? 'You are a helpful AI agent.';
|
|
19
20
|
this.memory = options.memory ?? new memory_1.InMemoryStore();
|
|
20
21
|
this.provider = (0, providers_1.createProvider)(options.provider ?? 'deepseek', options.model ?? 'deepseek-chat');
|
|
22
|
+
this.historyLimit = options.historyLimit ?? 50;
|
|
21
23
|
}
|
|
22
24
|
get state() {
|
|
23
25
|
return this._state;
|
|
@@ -59,7 +61,7 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
59
61
|
const context = {
|
|
60
62
|
agentName: this.name,
|
|
61
63
|
sessionId,
|
|
62
|
-
messages: await this.memory.getConversation(sessionId),
|
|
64
|
+
messages: (await this.memory.getConversation(sessionId)).slice(-this.historyLimit),
|
|
63
65
|
memory: this.memory,
|
|
64
66
|
metadata: {},
|
|
65
67
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logger with log levels.
|
|
3
|
+
*/
|
|
4
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
5
|
+
export declare class Logger {
|
|
6
|
+
private context;
|
|
7
|
+
private level;
|
|
8
|
+
constructor(context: string, level?: LogLevel);
|
|
9
|
+
private shouldLog;
|
|
10
|
+
private format;
|
|
11
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
12
|
+
info(message: string, data?: Record<string, unknown>): void;
|
|
13
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
14
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
15
|
+
setLevel(level: LogLevel): void;
|
|
16
|
+
child(context: string): Logger;
|
|
17
|
+
}
|
|
18
|
+
export declare const defaultLogger: Logger;
|
|
19
|
+
//# sourceMappingURL=logger.d.ts.map
|