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.
Files changed (186) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +14 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  4. package/.github/workflows/ci.yml +24 -0
  5. package/CHANGELOG.md +23 -63
  6. package/CONTRIBUTING.md +21 -60
  7. package/README.md +235 -358
  8. package/README.zh-CN.md +415 -415
  9. package/dist/channels/slack.js +93 -10
  10. package/dist/channels/web.d.ts +10 -0
  11. package/dist/channels/web.js +33 -2
  12. package/dist/cli.js +255 -60
  13. package/dist/core/runtime.d.ts +4 -0
  14. package/dist/core/runtime.js +27 -0
  15. package/dist/deploy/hermes.js +22 -22
  16. package/dist/deploy/openclaw.js +31 -40
  17. package/dist/index.d.ts +3 -10
  18. package/dist/index.js +6 -15
  19. package/dist/providers/index.d.ts +1 -1
  20. package/dist/providers/index.js +7 -1
  21. package/dist/schema/oad.d.ts +1 -2
  22. package/dist/templates/code-reviewer.d.ts +0 -8
  23. package/dist/templates/code-reviewer.js +5 -9
  24. package/dist/templates/customer-service.d.ts +0 -8
  25. package/dist/templates/customer-service.js +2 -6
  26. package/dist/templates/data-analyst.d.ts +0 -8
  27. package/dist/templates/data-analyst.js +5 -9
  28. package/dist/templates/knowledge-base.d.ts +0 -8
  29. package/dist/templates/knowledge-base.js +2 -6
  30. package/dist/templates/sales-assistant.d.ts +0 -8
  31. package/dist/templates/sales-assistant.js +4 -8
  32. package/dist/templates/teacher.d.ts +0 -8
  33. package/dist/templates/teacher.js +6 -10
  34. package/dist/traces/index.d.ts +49 -0
  35. package/dist/traces/index.js +102 -0
  36. package/docs/.vitepress/config.ts +103 -103
  37. package/docs/api/cli.md +48 -48
  38. package/docs/api/oad-schema.md +64 -64
  39. package/docs/api/sdk.md +80 -80
  40. package/docs/guide/concepts.md +51 -51
  41. package/docs/guide/configuration.md +79 -79
  42. package/docs/guide/deployment.md +42 -42
  43. package/docs/guide/getting-started.md +44 -44
  44. package/docs/guide/templates.md +28 -28
  45. package/docs/guide/testing.md +84 -84
  46. package/docs/index.md +27 -27
  47. package/docs/zh/api/cli.md +54 -54
  48. package/docs/zh/api/oad-schema.md +87 -87
  49. package/docs/zh/api/sdk.md +102 -102
  50. package/docs/zh/guide/concepts.md +104 -104
  51. package/docs/zh/guide/configuration.md +135 -135
  52. package/docs/zh/guide/deployment.md +81 -81
  53. package/docs/zh/guide/getting-started.md +82 -82
  54. package/docs/zh/guide/templates.md +84 -84
  55. package/docs/zh/guide/testing.md +88 -88
  56. package/docs/zh/index.md +27 -27
  57. package/examples/README.md +22 -0
  58. package/examples/basic-agent.ts +90 -0
  59. package/examples/brain-integration.ts +71 -0
  60. package/examples/customer-service-demo/README.md +90 -90
  61. package/examples/customer-service-demo/oad.yaml +107 -107
  62. package/examples/multi-channel.ts +74 -0
  63. package/package.json +1 -1
  64. package/src/analytics/index.ts +66 -66
  65. package/src/channels/discord.ts +192 -192
  66. package/src/channels/email.ts +177 -177
  67. package/src/channels/feishu.ts +236 -236
  68. package/src/channels/index.ts +15 -15
  69. package/src/channels/slack.ts +217 -160
  70. package/src/channels/telegram.ts +90 -90
  71. package/src/channels/voice.ts +106 -106
  72. package/src/channels/web.ts +38 -2
  73. package/src/channels/webhook.ts +199 -199
  74. package/src/channels/websocket.ts +87 -87
  75. package/src/channels/wechat.ts +149 -149
  76. package/src/cli.ts +282 -58
  77. package/src/core/a2a.ts +143 -143
  78. package/src/core/agent.ts +152 -152
  79. package/src/core/analytics-engine.ts +186 -186
  80. package/src/core/auth.ts +57 -57
  81. package/src/core/cache.ts +141 -141
  82. package/src/core/compose.ts +77 -77
  83. package/src/core/config.ts +14 -14
  84. package/src/core/errors.ts +148 -148
  85. package/src/core/hitl.ts +138 -138
  86. package/src/core/logger.ts +57 -57
  87. package/src/core/orchestrator.ts +215 -215
  88. package/src/core/performance.ts +187 -187
  89. package/src/core/rate-limiter.ts +128 -128
  90. package/src/core/room.ts +109 -109
  91. package/src/core/runtime.ts +183 -152
  92. package/src/core/sandbox.ts +101 -101
  93. package/src/core/security.ts +171 -171
  94. package/src/core/types.ts +68 -68
  95. package/src/core/versioning.ts +106 -106
  96. package/src/core/watch.ts +178 -178
  97. package/src/core/workflow.ts +235 -235
  98. package/src/deploy/hermes.ts +156 -156
  99. package/src/deploy/openclaw.ts +190 -200
  100. package/src/i18n/index.ts +216 -216
  101. package/src/index.ts +3 -10
  102. package/src/memory/deepbrain.ts +108 -108
  103. package/src/memory/index.ts +34 -34
  104. package/src/plugins/index.ts +208 -208
  105. package/src/providers/index.ts +9 -1
  106. package/src/schema/oad.ts +154 -155
  107. package/src/skills/base.ts +16 -16
  108. package/src/skills/document.ts +100 -100
  109. package/src/skills/http.ts +35 -35
  110. package/src/skills/index.ts +27 -27
  111. package/src/skills/scheduler.ts +80 -80
  112. package/src/skills/webhook-trigger.ts +59 -59
  113. package/src/templates/code-reviewer.ts +30 -34
  114. package/src/templates/customer-service.ts +76 -80
  115. package/src/templates/data-analyst.ts +66 -70
  116. package/src/templates/executive-assistant.ts +71 -71
  117. package/src/templates/financial-advisor.ts +60 -60
  118. package/src/templates/knowledge-base.ts +27 -31
  119. package/src/templates/legal-assistant.ts +71 -71
  120. package/src/templates/sales-assistant.ts +75 -79
  121. package/src/templates/teacher.ts +75 -79
  122. package/src/testing/index.ts +181 -181
  123. package/src/tools/calculator.ts +73 -73
  124. package/src/tools/datetime.ts +149 -149
  125. package/src/tools/json-transform.ts +187 -187
  126. package/src/tools/mcp.ts +76 -76
  127. package/src/tools/text-analysis.ts +116 -116
  128. package/src/traces/index.ts +132 -0
  129. package/templates/Dockerfile +15 -15
  130. package/templates/code-reviewer/README.md +27 -27
  131. package/templates/code-reviewer/oad.yaml +41 -41
  132. package/templates/customer-service/README.md +22 -22
  133. package/templates/customer-service/oad.yaml +36 -36
  134. package/templates/docker-compose.yml +21 -21
  135. package/templates/ecommerce-assistant/README.md +45 -45
  136. package/templates/ecommerce-assistant/oad.yaml +47 -47
  137. package/templates/knowledge-base/README.md +28 -28
  138. package/templates/knowledge-base/oad.yaml +38 -38
  139. package/templates/sales-assistant/README.md +26 -26
  140. package/templates/sales-assistant/oad.yaml +43 -43
  141. package/templates/tech-support/README.md +43 -43
  142. package/templates/tech-support/oad.yaml +45 -45
  143. package/test-agent/Dockerfile +9 -0
  144. package/test-agent/README.md +50 -0
  145. package/test-agent/agent.yaml +23 -0
  146. package/test-agent/docker-compose.yml +11 -0
  147. package/test-agent/oad.yaml +31 -0
  148. package/test-agent/package-lock.json +1492 -0
  149. package/test-agent/package.json +18 -0
  150. package/test-agent/src/index.ts +24 -0
  151. package/test-agent/src/skills/echo.ts +15 -0
  152. package/test-agent/tsconfig.json +25 -0
  153. package/tests/a2a.test.ts +66 -66
  154. package/tests/agent.test.ts +72 -72
  155. package/tests/analytics.test.ts +50 -50
  156. package/tests/channel.test.ts +39 -39
  157. package/tests/e2e.test.ts +134 -134
  158. package/tests/errors.test.ts +83 -83
  159. package/tests/hitl.test.ts +71 -71
  160. package/tests/i18n.test.ts +41 -41
  161. package/tests/mcp.test.ts +54 -54
  162. package/tests/oad.test.ts +68 -68
  163. package/tests/performance.test.ts +115 -115
  164. package/tests/plugin.test.ts +74 -74
  165. package/tests/room.test.ts +106 -106
  166. package/tests/runtime.test.ts +42 -42
  167. package/tests/sandbox.test.ts +46 -46
  168. package/tests/security.test.ts +60 -60
  169. package/tests/templates.test.ts +77 -77
  170. package/tests/v070.test.ts +76 -76
  171. package/tests/versioning.test.ts +75 -75
  172. package/tests/voice.test.ts +61 -61
  173. package/tests/webhook.test.ts +29 -29
  174. package/tests/workflow.test.ts +143 -143
  175. package/tsconfig.json +19 -19
  176. package/vitest.config.ts +9 -9
  177. package/dist/core/dashboard.d.ts +0 -35
  178. package/dist/core/dashboard.js +0 -157
  179. package/dist/core/priority.d.ts +0 -52
  180. package/dist/core/priority.js +0 -102
  181. package/src/core/dashboard.ts +0 -219
  182. package/src/core/priority.ts +0 -140
  183. package/src/dtv/data.ts +0 -29
  184. package/src/dtv/trust.ts +0 -43
  185. package/src/dtv/value.ts +0 -47
  186. package/src/marketplace/index.ts +0 -223
@@ -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
- // TODO: Implement with express or http
41
- // const port = this.config.port ?? 3001;
42
- // Listen for POST /slack/events and /slack/commands
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
- // TODO: Implement with @slack/web-api
98
- // const { WebClient } = await import('@slack/web-api');
99
- // const client = new WebClient(this.config.botToken);
100
- // await client.chat.postMessage({ channel, text, thread_ts: threadTs });
101
- void channel;
102
- void text;
103
- void threadTs;
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;
@@ -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>;
@@ -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({ status: 'ok', timestamp: Date.now() });
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
- res.json(this.stats);
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.0.0');
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=llama3
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': '^0.5.0',
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
- - ./oad.yaml:/app/oad.yaml:ro
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. **Set your API key:**
308
+ 1. **Install dependencies:**
215
309
  \`\`\`bash
216
- # Edit .env and add your API key
217
- cp .env.example .env
218
- # Then edit .env with your actual key
310
+ npm install
219
311
  \`\`\`
220
312
 
221
- 2. **Install dependencies:**
313
+ 2. **Run with Ollama (default):**
222
314
  \`\`\`bash
223
- npm install
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. **Start the web server:**
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
- ## CLI Chat
328
+ ## Development
234
329
 
235
330
  \`\`\`bash
236
- npx opc chat
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 \`oad.yaml\` to customize your agent's personality, skills, and behavior.
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} oad.yaml - Agent definition`);
245
- console.log(` ${icon.file} package.json - Dependencies`);
246
- console.log(` ${icon.file} .env.example - Environment template`);
247
- console.log(` ${icon.file} .env - Environment config (edit this!)`);
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. Edit .env — set your OPC_LLM_API_KEY`);
256
- console.log(` 3. npm install`);
257
- console.log(` 4. npx opc run`);
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
- // 📦 Marketplace commands ───────────────────────────────────
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 (opts) => {
695
- try {
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 (source, opts) => {
719
- try {
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
@@ -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