opc-agent 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +91 -32
  3. package/dist/channels/telegram.d.ts +30 -9
  4. package/dist/channels/telegram.js +125 -33
  5. package/dist/cli.js +415 -8
  6. package/dist/core/agent.d.ts +23 -0
  7. package/dist/core/agent.js +120 -3
  8. package/dist/core/runtime.d.ts +1 -0
  9. package/dist/core/runtime.js +44 -0
  10. package/dist/core/scheduler.d.ts +52 -0
  11. package/dist/core/scheduler.js +168 -0
  12. package/dist/core/subagent.d.ts +28 -0
  13. package/dist/core/subagent.js +65 -0
  14. package/dist/daemon.d.ts +3 -0
  15. package/dist/daemon.js +134 -0
  16. package/dist/index.d.ts +7 -0
  17. package/dist/index.js +17 -1
  18. package/dist/providers/index.d.ts +5 -1
  19. package/dist/providers/index.js +16 -9
  20. package/dist/schema/oad.d.ts +179 -4
  21. package/dist/schema/oad.js +12 -1
  22. package/dist/skills/auto-learn.d.ts +28 -0
  23. package/dist/skills/auto-learn.js +257 -0
  24. package/dist/tools/builtin/datetime.d.ts +3 -0
  25. package/dist/tools/builtin/datetime.js +44 -0
  26. package/dist/tools/builtin/file.d.ts +3 -0
  27. package/dist/tools/builtin/file.js +151 -0
  28. package/dist/tools/builtin/index.d.ts +15 -0
  29. package/dist/tools/builtin/index.js +30 -0
  30. package/dist/tools/builtin/shell.d.ts +3 -0
  31. package/dist/tools/builtin/shell.js +43 -0
  32. package/dist/tools/builtin/web.d.ts +3 -0
  33. package/dist/tools/builtin/web.js +37 -0
  34. package/dist/tools/mcp-client.d.ts +24 -0
  35. package/dist/tools/mcp-client.js +119 -0
  36. package/package.json +1 -1
  37. package/src/channels/telegram.ts +212 -90
  38. package/src/cli.ts +418 -8
  39. package/src/core/agent.ts +295 -152
  40. package/src/core/runtime.ts +47 -0
  41. package/src/core/scheduler.ts +187 -0
  42. package/src/core/subagent.ts +98 -0
  43. package/src/daemon.ts +96 -0
  44. package/src/index.ts +11 -0
  45. package/src/providers/index.ts +354 -339
  46. package/src/schema/oad.ts +167 -154
  47. package/src/skills/auto-learn.ts +262 -0
  48. package/src/tools/builtin/datetime.ts +41 -0
  49. package/src/tools/builtin/file.ts +107 -0
  50. package/src/tools/builtin/index.ts +28 -0
  51. package/src/tools/builtin/shell.ts +43 -0
  52. package/src/tools/builtin/web.ts +35 -0
  53. package/src/tools/mcp-client.ts +131 -0
  54. package/tests/auto-learn.test.ts +105 -0
  55. package/tests/builtin-tools.test.ts +83 -0
  56. package/tests/cli.test.ts +46 -0
  57. package/tests/subagent.test.ts +130 -0
  58. package/tests/telegram-discord.test.ts +60 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.0] - 2026-04-18
4
+
5
+ ### Major Features
6
+ - **Interactive CLI** (`opc chat`) — Full TUI with streaming, slash commands, history
7
+ - **Daemon Mode** (`opc start/stop/status`) — Run agents as background processes
8
+ - **Cron Scheduler** — Built-in job scheduling with cron expressions
9
+ - **Autonomous Skill Learning** — Agents create and improve skills from experience
10
+ - **Sub-Agent System** — Spawn parallel sub-agents for task delegation
11
+ - **Built-in Tools** — File operations, web fetch, shell exec, datetime
12
+ - **MCP Client** — Connect to external MCP servers via JSON-RPC
13
+ - **Telegram Channel** — Dual-mode (polling + webhook) with Markdown support
14
+ - **Discord Channel** — Gateway WebSocket with auto-reconnect
15
+ - **Slack Channel** — Real Events API + chat.postMessage
16
+ - **SOUL.md + CONTEXT.md** — Agent personality and project context files
17
+ - **Analytics** — Wired into runtime for message tracking, skill usage, errors
18
+
19
+ ### Enhanced
20
+ - `/health` endpoint returns comprehensive agent info
21
+ - `opc init` generates SOUL.md, CONTEXT.md, and richer project templates
22
+ - OAD config supports scheduler, learning, and tools sections
23
+ - 204 tests passing
24
+
25
+ ### CLI Commands
26
+ init, chat, run, dev, start, stop, status, jobs, skills, info, build, test, analytics, brain, logs, score, search, deploy, publish, install, plugin, tool, workflow, migrate
27
+
3
28
  ## 1.4.0 (2026-04-18)
4
29
  - feat: wire Analytics into AgentRuntime (message timing, skill usage, error tracking)
5
30
  - feat: expose analytics snapshot on /health and /api/dashboard endpoints
package/README.md CHANGED
@@ -6,8 +6,9 @@
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/opc-agent)](https://www.npmjs.com/package/opc-agent)
8
8
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
9
- [![Tests](https://img.shields.io/badge/Tests-163_passing-green)]()
9
+ [![Tests](https://img.shields.io/badge/Tests-204_passing-green)]()
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue)](https://www.typescriptlang.org/)
11
+ [![Version](https://img.shields.io/badge/version-2.0.0-brightgreen)]()
11
12
 
12
13
  [快速开始](#快速开始) · [CLI 命令](#cli-命令) · [渠道](#11-个渠道) · [English](#english)
13
14
 
@@ -20,38 +21,76 @@
20
21
  > **不只是 Harness,是比 Harness 高一维的 Agent OS。**
21
22
  > 从创建到运行到监控,一个工具搞定 Agent 全生命周期。
22
23
 
23
- ## 🎯 和 Harness 框架的区别
24
-
25
- | | LangChain | CrewAI | AutoGen | **OPC Agent** |
26
- |---|---|---|---|---|
27
- | 创建 | 写代码 | 写代码 | 写代码 | **`opc init` 一键** |
28
- | 配置 | Python/代码 | Python | Python | **YAML 声明式** |
29
- | 测试 | 自己搭 | 无 | 无 | **内置测试框架** |
30
- | 渠道 | 自己接 | 无 | 无 | **11 渠道开箱即用** |
31
- | 监控 | 自己搭 | 无 | 无 | **Traces + Score** |
32
- | 记忆 | 自己管 | 简单 | 简单 | **DeepBrain 集成** |
24
+ ## 🎯 和竞品的区别
25
+
26
+ | | LangChain | CrewAI | AutoGen | Hermes Agent | **OPC Agent** |
27
+ |---|---|---|---|---|---|
28
+ | 创建 | 写代码 | 写代码 | 写代码 | CLI | **`opc init` 一键** |
29
+ | 配置 | Python/代码 | Python | Python | YAML | **YAML 声明式** |
30
+ | 测试 | 自己搭 | 无 | 无 | 基础 | **内置测试框架** |
31
+ | 渠道 | 自己接 | 无 | 无 | 有限 | **11 渠道开箱即用** |
32
+ | 监控 | 自己搭 | 无 | 无 | 基础 | **Traces + Score** |
33
+ | 记忆 | 自己管 | 简单 | 简单 | 无 | **DeepBrain 集成** |
34
+ | 守护进程 | 无 | 无 | 无 | 无 | **`opc start/stop/status`** |
35
+ | 定时任务 | 无 | 无 | 无 | 无 | **内置 Cron 调度** |
36
+ | 技能学习 | 无 | 无 | 无 | 无 | **自主技能习得** |
37
+ | 子 Agent | 无 | 有 | 有 | 无 | **并行子 Agent 系统** |
38
+ | MCP | 无 | 无 | 无 | 无 | **MCP Client 集成** |
33
39
 
34
40
  **框架管"怎么跑",Agent OS 管"全过程"。**
35
41
 
36
42
  ## 快速开始
37
43
 
38
44
  ```bash
39
- npm install -g opc-agent
45
+ # 最快方式(无需全局安装)
46
+ npx opc-agent init my-agent
47
+ cd my-agent
48
+ npm install
49
+ opc chat
40
50
 
41
- # 创建
51
+ # 或全局安装
52
+ npm install -g opc-agent
42
53
  opc init my-agent
43
54
  cd my-agent
44
-
45
- # 开发
46
55
  opc dev
56
+ ```
57
+
58
+ ## 🆕 v2.0.0 新特性
47
59
 
48
- # 测试
49
- opc test
60
+ ### 🖥️ 交互式 CLI (`opc chat`)
61
+ 全功能 TUI:流式输出、斜杠命令、历史记录,直接在终端和 Agent 对话。
50
62
 
51
- # 运行
52
- opc run
63
+ ### 🔄 守护进程模式
64
+ ```bash
65
+ opc start # 后台启动 Agent
66
+ opc status # 查看运行状态
67
+ opc stop # 停止 Agent
68
+ ```
69
+
70
+ ### ⏰ Cron 调度器
71
+ OAD 配置中声明定时任务,Agent 自动按计划执行:
72
+ ```yaml
73
+ scheduler:
74
+ jobs:
75
+ - cron: "0 9 * * *"
76
+ task: daily-report
53
77
  ```
54
78
 
79
+ ### 🧠 自主技能学习
80
+ Agent 从经验中自动创建和改进技能,越用越强。
81
+
82
+ ### 🤖 子 Agent 系统
83
+ 并行派生子 Agent 处理复杂任务,支持任务委派和结果汇总。
84
+
85
+ ### 🔧 内置工具
86
+ 文件操作、Web 抓取、Shell 执行、日期时间 — 开箱即用,无需额外配置。
87
+
88
+ ### 🔌 MCP Client
89
+ 通过 JSON-RPC 连接外部 MCP 服务器,扩展 Agent 能力边界。
90
+
91
+ ### 📄 SOUL.md + CONTEXT.md
92
+ 用 Markdown 定义 Agent 人格和项目上下文,人性化配置。
93
+
55
94
  ## OAD 声明式配置
56
95
 
57
96
  不用写代码,用 YAML 定义 Agent:
@@ -87,12 +126,29 @@ memory:
87
126
 
88
127
  ```bash
89
128
  opc init <name> # 创建新 Agent
129
+ opc chat # 交互式对话(TUI)
90
130
  opc dev # 开发模式(热重载)
91
- opc test # 运行测试
92
131
  opc run # 生产运行
93
- opc logs [-f] # 查看 Traces 日志
132
+ opc start # 守护进程启动
133
+ opc stop # 停止守护进程
134
+ opc status # 查看运行状态
135
+ opc jobs # 查看定时任务
136
+ opc skills # 查看已学技能
137
+ opc info # Agent 信息
138
+ opc build # 构建
139
+ opc test # 运行测试
140
+ opc analytics # 数据分析
94
141
  opc brain [--url ...] # 查看记忆状态
142
+ opc logs [-f] # 查看 Traces 日志
95
143
  opc score # 查看性能评分
144
+ opc search <query> # 搜索
145
+ opc deploy # 部署
146
+ opc publish # 发布
147
+ opc install <skill> # 安装技能
148
+ opc plugin <name> # 管理插件
149
+ opc tool <name> # 管理工具
150
+ opc workflow <name> # 工作流
151
+ opc migrate # 迁移
96
152
  ```
97
153
 
98
154
  ## 11 个渠道
@@ -184,20 +240,17 @@ Apache-2.0
184
240
  ## Quick Start
185
241
 
186
242
  ```bash
187
- npm install -g opc-agent
243
+ # Fastest way (no global install)
244
+ npx opc-agent init my-agent
245
+ cd my-agent
246
+ npm install
247
+ opc chat
188
248
 
189
- # Create
249
+ # Or install globally
250
+ npm install -g opc-agent
190
251
  opc init my-agent
191
252
  cd my-agent
192
-
193
- # Develop
194
253
  opc dev
195
-
196
- # Test
197
- opc test
198
-
199
- # Run
200
- opc run
201
254
  ```
202
255
 
203
256
  ## OAD Declarative Configuration
@@ -267,7 +320,7 @@ One codebase, deploy to any channel:
267
320
  |----------|----------|
268
321
  | 📋 **Configuration** | OAD declarative definition, YAML config |
269
322
  | 📡 **Channels** | 11 channels, unified access |
270
- | 🧪 **Testing** | Built-in test framework, 163 tests |
323
+ | 🧪 **Testing** | Built-in test framework, 204 tests |
271
324
  | 🔌 **Plugins** | Extensible skills and tools system |
272
325
  | 📊 **Monitoring** | Traces behavior collection, Score rating |
273
326
  | 🧠 **Memory** | DeepBrain integration, auto-learning |
@@ -304,3 +357,9 @@ One codebase, deploy to any channel:
304
357
  ## License
305
358
 
306
359
  Apache-2.0
360
+ thub.com/Deepleaper/agentkits) | OpenRouter with Memory | Model call layer |
361
+ | [agent-workstation](https://github.com/Deepleaper/agent-workstation) | Virtual Role Templates | `opc init --template` |
362
+
363
+ ## License
364
+
365
+ Apache-2.0
@@ -1,21 +1,42 @@
1
1
  import { BaseChannel } from './index';
2
2
  /**
3
- * Telegram channel — basic webhook handler for Telegram Bot API.
4
- * Set TELEGRAM_BOT_TOKEN env var or pass in config.
3
+ * Telegram channel — supports both long-polling and webhook modes.
4
+ *
5
+ * Config:
6
+ * token: bot token (or TELEGRAM_BOT_TOKEN env var)
7
+ * mode: 'polling' | 'webhook' (default: 'polling')
8
+ * webhookUrl: required for webhook mode
9
+ * port: webhook server port (default: 3001)
10
+ *
11
+ * Polling mode requires no public URL — ideal for dev/local.
12
+ * Webhook mode is more efficient for production.
5
13
  */
14
+ export interface TelegramChannelConfig {
15
+ token?: string;
16
+ mode?: 'polling' | 'webhook';
17
+ webhookUrl?: string;
18
+ port?: number;
19
+ }
6
20
  export declare class TelegramChannel extends BaseChannel {
7
21
  readonly type = "telegram";
8
22
  private token;
23
+ private mode;
9
24
  private webhookUrl?;
10
- private server;
11
25
  private port;
12
- constructor(options?: {
13
- token?: string;
14
- webhookUrl?: string;
15
- port?: number;
16
- });
26
+ private offset;
27
+ private polling;
28
+ private server;
29
+ constructor(config?: TelegramChannelConfig);
17
30
  start(): Promise<void>;
18
31
  stop(): Promise<void>;
19
- private sendMessage;
32
+ private startPolling;
33
+ private poll;
34
+ private getUpdates;
35
+ private startWebhook;
36
+ private stopWebhook;
37
+ private processUpdate;
38
+ sendMessage(chatId: number | string, text: string): Promise<void>;
39
+ private apiCall;
40
+ private splitText;
20
41
  }
21
42
  //# sourceMappingURL=telegram.d.ts.map
@@ -35,58 +35,105 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.TelegramChannel = void 0;
37
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
38
  class TelegramChannel extends index_1.BaseChannel {
43
39
  type = 'telegram';
44
40
  token;
41
+ mode;
45
42
  webhookUrl;
46
- server = null;
47
43
  port;
48
- constructor(options = {}) {
44
+ // Polling state
45
+ offset = 0;
46
+ polling = false;
47
+ // Webhook state
48
+ server = null;
49
+ constructor(config = {}) {
49
50
  super();
50
- this.token = options.token ?? process.env.TELEGRAM_BOT_TOKEN ?? '';
51
- this.webhookUrl = options.webhookUrl;
52
- this.port = options.port ?? 3001;
51
+ this.token = config.token ?? process.env.TELEGRAM_BOT_TOKEN ?? '';
52
+ this.mode = config.mode ?? 'polling';
53
+ this.webhookUrl = config.webhookUrl;
54
+ this.port = config.port ?? 3001;
53
55
  }
54
56
  async start() {
55
57
  if (!this.token) {
56
58
  console.warn('[TelegramChannel] No bot token provided. Set TELEGRAM_BOT_TOKEN or pass token in config.');
57
59
  return;
58
60
  }
61
+ if (this.mode === 'webhook') {
62
+ await this.startWebhook();
63
+ }
64
+ else {
65
+ await this.startPolling();
66
+ }
67
+ }
68
+ async stop() {
69
+ if (this.mode === 'webhook') {
70
+ await this.stopWebhook();
71
+ }
72
+ else {
73
+ this.polling = false;
74
+ }
75
+ }
76
+ // ─── Polling Mode ────────────────────────────────────────
77
+ async startPolling() {
78
+ // Delete any existing webhook so polling works
79
+ await this.apiCall('deleteWebhook');
80
+ console.log(`[TelegramChannel] Started long-polling mode`);
81
+ this.polling = true;
82
+ this.poll();
83
+ }
84
+ async poll() {
85
+ while (this.polling) {
86
+ try {
87
+ const updates = await this.getUpdates();
88
+ for (const update of updates) {
89
+ await this.processUpdate(update);
90
+ }
91
+ }
92
+ catch (err) {
93
+ console.error('[TelegramChannel] Polling error:', err);
94
+ // Back off on error
95
+ if (this.polling) {
96
+ await new Promise((r) => setTimeout(r, 5000));
97
+ }
98
+ }
99
+ }
100
+ }
101
+ async getUpdates() {
102
+ const url = `https://api.telegram.org/bot${this.token}/getUpdates?offset=${this.offset}&timeout=30&allowed_updates=["message"]`;
103
+ const controller = new AbortController();
104
+ const timeout = setTimeout(() => controller.abort(), 40000); // 30s long-poll + 10s buffer
105
+ try {
106
+ const res = await fetch(url, { signal: controller.signal });
107
+ const data = (await res.json());
108
+ if (data.ok && data.result.length > 0) {
109
+ this.offset = data.result[data.result.length - 1].update_id + 1;
110
+ }
111
+ return data.result || [];
112
+ }
113
+ finally {
114
+ clearTimeout(timeout);
115
+ }
116
+ }
117
+ // ─── Webhook Mode ────────────────────────────────────────
118
+ async startWebhook() {
119
+ if (this.webhookUrl) {
120
+ await this.apiCall('setWebhook', { url: `${this.webhookUrl}/webhook/${this.token}` });
121
+ }
59
122
  const express = (await Promise.resolve().then(() => __importStar(require('express')))).default;
60
123
  const app = express();
61
124
  app.use(express.json());
62
125
  app.post(`/webhook/${this.token}`, async (req, res) => {
63
126
  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
- }
127
+ await this.processUpdate(req.body);
81
128
  res.json({ ok: true });
82
129
  }
83
130
  catch (err) {
84
- console.error('[TelegramChannel] Error handling update:', err);
131
+ console.error('[TelegramChannel] Webhook error:', err);
85
132
  res.status(500).json({ error: 'Internal error' });
86
133
  }
87
134
  });
88
135
  app.get('/health', (_req, res) => {
89
- res.json({ status: 'ok', channel: 'telegram' });
136
+ res.json({ status: 'ok', channel: 'telegram', mode: 'webhook' });
90
137
  });
91
138
  return new Promise((resolve) => {
92
139
  this.server = app.listen(this.port, () => {
@@ -95,25 +142,70 @@ class TelegramChannel extends index_1.BaseChannel {
95
142
  });
96
143
  });
97
144
  }
98
- async stop() {
145
+ async stopWebhook() {
99
146
  return new Promise((resolve, reject) => {
100
147
  if (!this.server)
101
148
  return resolve();
102
149
  this.server.close((err) => (err ? reject(err) : resolve()));
103
150
  });
104
151
  }
152
+ // ─── Shared ──────────────────────────────────────────────
153
+ async processUpdate(update) {
154
+ const message = update.message || update.edited_message;
155
+ if (!message?.text || !this.handler)
156
+ return;
157
+ const msg = {
158
+ id: `tg_${message.message_id}`,
159
+ role: 'user',
160
+ content: message.text,
161
+ timestamp: message.date * 1000,
162
+ metadata: {
163
+ sessionId: `tg_${message.chat.id}`,
164
+ chatId: message.chat.id,
165
+ userId: message.from?.id,
166
+ username: message.from?.username,
167
+ firstName: message.from?.first_name,
168
+ platform: 'telegram',
169
+ chatType: message.chat.type,
170
+ },
171
+ };
172
+ const response = await this.handler(msg);
173
+ await this.sendMessage(message.chat.id, response.content);
174
+ }
105
175
  async sendMessage(chatId, text) {
106
- const url = `https://api.telegram.org/bot${this.token}/sendMessage`;
176
+ // Telegram max message length is 4096
177
+ const chunks = this.splitText(text, 4096);
178
+ for (const chunk of chunks) {
179
+ await this.apiCall('sendMessage', {
180
+ chat_id: chatId,
181
+ text: chunk,
182
+ parse_mode: 'Markdown',
183
+ });
184
+ }
185
+ }
186
+ async apiCall(method, body) {
187
+ const url = `https://api.telegram.org/bot${this.token}/${method}`;
107
188
  try {
108
- await fetch(url, {
189
+ const res = await fetch(url, {
109
190
  method: 'POST',
110
191
  headers: { 'Content-Type': 'application/json' },
111
- body: JSON.stringify({ chat_id: chatId, text, parse_mode: 'Markdown' }),
192
+ body: body ? JSON.stringify(body) : undefined,
112
193
  });
194
+ return await res.json();
113
195
  }
114
196
  catch (err) {
115
- console.error('[TelegramChannel] Failed to send message:', err);
197
+ console.error(`[TelegramChannel] API call ${method} failed:`, err);
198
+ throw err;
199
+ }
200
+ }
201
+ splitText(text, maxLen) {
202
+ if (text.length <= maxLen)
203
+ return [text];
204
+ const parts = [];
205
+ for (let i = 0; i < text.length; i += maxLen) {
206
+ parts.push(text.slice(i, i + maxLen));
116
207
  }
208
+ return parts;
117
209
  }
118
210
  }
119
211
  exports.TelegramChannel = TelegramChannel;