opc-agent 1.3.1 → 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/CHANGELOG.md +23 -57
- package/CONTRIBUTING.md +36 -75
- 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 +137 -26
- package/dist/core/runtime.d.ts +4 -0
- package/dist/core/runtime.js +27 -0
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.js +7 -1
- package/examples/README.md +22 -0
- package/examples/basic-agent.ts +90 -0
- package/examples/brain-integration.ts +71 -0
- package/examples/multi-channel.ts +74 -0
- package/package.json +1 -1
- package/src/channels/slack.ts +67 -10
- package/src/channels/web.ts +38 -2
- package/src/cli.ts +158 -26
- package/src/core/runtime.ts +31 -0
- package/src/providers/index.ts +9 -1
- 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/dist/cli.js
CHANGED
|
@@ -118,7 +118,7 @@ async function select(question, options) {
|
|
|
118
118
|
program
|
|
119
119
|
.name('opc')
|
|
120
120
|
.description('OPC Agent - Open Agent Framework for business workstations')
|
|
121
|
-
.version('1.
|
|
121
|
+
.version('1.4.0');
|
|
122
122
|
// ── Init command ─────────────────────────────────────────────
|
|
123
123
|
program
|
|
124
124
|
.command('init')
|
|
@@ -138,6 +138,7 @@ program
|
|
|
138
138
|
process.exit(1);
|
|
139
139
|
}
|
|
140
140
|
fs.mkdirSync(dir, { recursive: true });
|
|
141
|
+
fs.mkdirSync(path.join(dir, 'src', 'skills'), { recursive: true });
|
|
141
142
|
const factory = TEMPLATES[template]?.factory ?? customer_service_1.createCustomerServiceConfig;
|
|
142
143
|
const config = factory();
|
|
143
144
|
config.metadata.name = name;
|
|
@@ -146,6 +147,93 @@ program
|
|
|
146
147
|
config.spec.channels.push({ type: 'web', port: 3000 });
|
|
147
148
|
}
|
|
148
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));
|
|
149
237
|
// .env.example
|
|
150
238
|
fs.writeFileSync(path.join(dir, '.env.example'), `# LLM API Configuration
|
|
151
239
|
OPC_LLM_API_KEY=your-api-key-here
|
|
@@ -156,9 +244,9 @@ OPC_LLM_MODEL=gpt-4o-mini
|
|
|
156
244
|
# OPC_LLM_BASE_URL=https://api.deepseek.com/v1
|
|
157
245
|
# OPC_LLM_MODEL=deepseek-chat
|
|
158
246
|
|
|
159
|
-
# For local Ollama:
|
|
247
|
+
# For local Ollama (default in agent.yaml):
|
|
160
248
|
# OPC_LLM_BASE_URL=http://localhost:11434/v1
|
|
161
|
-
# OPC_LLM_MODEL=
|
|
249
|
+
# OPC_LLM_MODEL=qwen2.5
|
|
162
250
|
`);
|
|
163
251
|
// .env (copy of example)
|
|
164
252
|
fs.writeFileSync(path.join(dir, '.env'), `OPC_LLM_API_KEY=your-api-key-here
|
|
@@ -172,20 +260,27 @@ OPC_LLM_MODEL=gpt-4o-mini
|
|
|
172
260
|
private: true,
|
|
173
261
|
scripts: {
|
|
174
262
|
start: 'opc run',
|
|
263
|
+
dev: 'opc dev',
|
|
175
264
|
chat: 'opc chat',
|
|
265
|
+
build: 'tsc',
|
|
176
266
|
},
|
|
177
267
|
dependencies: {
|
|
178
|
-
'opc-agent': '^
|
|
268
|
+
'opc-agent': '^1.3.0',
|
|
269
|
+
},
|
|
270
|
+
devDependencies: {
|
|
271
|
+
typescript: '^5.5.0',
|
|
272
|
+
tsx: '^4.0.0',
|
|
179
273
|
},
|
|
180
274
|
}, null, 2));
|
|
181
275
|
// .gitignore
|
|
182
|
-
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');
|
|
183
277
|
// Dockerfile
|
|
184
278
|
fs.writeFileSync(path.join(dir, 'Dockerfile'), `FROM node:22-alpine
|
|
185
279
|
WORKDIR /app
|
|
186
280
|
COPY package.json package-lock.json* ./
|
|
187
281
|
RUN npm ci --production 2>/dev/null || npm install --production
|
|
188
|
-
COPY oad.yaml .env* ./
|
|
282
|
+
COPY oad.yaml agent.yaml .env* ./
|
|
283
|
+
COPY src/ ./src/
|
|
189
284
|
COPY prompts/ ./prompts/ 2>/dev/null || true
|
|
190
285
|
EXPOSE 3000
|
|
191
286
|
CMD ["npx", "opc", "run"]
|
|
@@ -200,7 +295,7 @@ services:
|
|
|
200
295
|
env_file:
|
|
201
296
|
- .env
|
|
202
297
|
volumes:
|
|
203
|
-
- ./
|
|
298
|
+
- ./agent.yaml:/app/agent.yaml:ro
|
|
204
299
|
restart: unless-stopped
|
|
205
300
|
`);
|
|
206
301
|
// README.md
|
|
@@ -210,51 +305,67 @@ Created with [OPC Agent](https://github.com/Deepleaper/opc-agent) using the \`${
|
|
|
210
305
|
|
|
211
306
|
## Quick Start
|
|
212
307
|
|
|
213
|
-
1. **
|
|
308
|
+
1. **Install dependencies:**
|
|
214
309
|
\`\`\`bash
|
|
215
|
-
|
|
216
|
-
cp .env.example .env
|
|
217
|
-
# Then edit .env with your actual key
|
|
310
|
+
npm install
|
|
218
311
|
\`\`\`
|
|
219
312
|
|
|
220
|
-
2. **
|
|
313
|
+
2. **Run with Ollama (default):**
|
|
221
314
|
\`\`\`bash
|
|
222
|
-
|
|
315
|
+
# Make sure Ollama is running with qwen2.5 model
|
|
316
|
+
ollama pull qwen2.5
|
|
317
|
+
npx tsx src/index.ts
|
|
223
318
|
\`\`\`
|
|
224
319
|
|
|
225
|
-
3. **
|
|
320
|
+
3. **Or use OpenAI/other providers:**
|
|
226
321
|
\`\`\`bash
|
|
322
|
+
# Edit .env and set your API key
|
|
227
323
|
npx opc run
|
|
228
324
|
\`\`\`
|
|
229
325
|
|
|
230
326
|
4. **Open browser:** [http://localhost:3000](http://localhost:3000)
|
|
231
327
|
|
|
232
|
-
##
|
|
328
|
+
## Development
|
|
233
329
|
|
|
234
330
|
\`\`\`bash
|
|
235
|
-
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
|
|
236
347
|
\`\`\`
|
|
237
348
|
|
|
238
349
|
## Configuration
|
|
239
350
|
|
|
240
|
-
Edit \`
|
|
351
|
+
Edit \`agent.yaml\` to customize your agent's personality, skills, and behavior.
|
|
241
352
|
`);
|
|
242
353
|
console.log(`\n${icon.success} Created agent project: ${color.bold(name + '/')}`);
|
|
243
|
-
console.log(` ${icon.file}
|
|
244
|
-
console.log(` ${icon.file}
|
|
245
|
-
console.log(` ${icon.file} .
|
|
246
|
-
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`);
|
|
247
360
|
console.log(` ${icon.file} .gitignore`);
|
|
248
361
|
console.log(` ${icon.file} Dockerfile`);
|
|
249
|
-
console.log(` ${icon.file} docker-compose.yml`);
|
|
250
362
|
console.log(` ${icon.file} README.md`);
|
|
251
363
|
console.log(`\n Template: ${color.cyan(template)}`);
|
|
252
364
|
console.log(`\n${color.bold('Next steps:')}`);
|
|
253
365
|
console.log(` 1. cd ${name}`);
|
|
254
|
-
console.log(` 2.
|
|
255
|
-
console.log(` 3.
|
|
256
|
-
console.log(` 4.
|
|
257
|
-
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`);
|
|
258
369
|
});
|
|
259
370
|
// ── Chat command ─────────────────────────────────────────────
|
|
260
371
|
program
|
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
|
package/dist/core/runtime.js
CHANGED
|
@@ -9,6 +9,7 @@ const web_1 = require("../channels/web");
|
|
|
9
9
|
const telegram_1 = require("../channels/telegram");
|
|
10
10
|
const websocket_1 = require("../channels/websocket");
|
|
11
11
|
const deepbrain_1 = require("../memory/deepbrain");
|
|
12
|
+
const analytics_1 = require("../analytics");
|
|
12
13
|
const MAX_TOOL_OUTPUT = 5000;
|
|
13
14
|
const DEFAULT_HISTORY_LIMIT = 50;
|
|
14
15
|
function truncateOutput(output, maxChars = MAX_TOOL_OUTPUT) {
|
|
@@ -24,6 +25,7 @@ class AgentRuntime {
|
|
|
24
25
|
historyLimit = DEFAULT_HISTORY_LIMIT;
|
|
25
26
|
shutdownHandlers = [];
|
|
26
27
|
isShuttingDown = false;
|
|
28
|
+
analytics = new analytics_1.Analytics();
|
|
27
29
|
async loadConfig(filePath) {
|
|
28
30
|
this.config = (0, config_1.loadOAD)(filePath);
|
|
29
31
|
this.logger.info('Config loaded', { name: this.config.metadata.name });
|
|
@@ -58,6 +60,12 @@ class AgentRuntime {
|
|
|
58
60
|
const port = ch.port ?? 3000;
|
|
59
61
|
const webChannel = new web_1.WebChannel(port);
|
|
60
62
|
webChannel.setAgentName(cfg.metadata.name);
|
|
63
|
+
webChannel.setAgentVersion(cfg.metadata.version);
|
|
64
|
+
webChannel.setAnalyticsProvider(() => this.analytics.getSnapshot());
|
|
65
|
+
webChannel.setChannelNames(cfg.spec.channels.map((c) => c.type));
|
|
66
|
+
webChannel.setSkillNames(cfg.spec.skills.map((s) => s.name));
|
|
67
|
+
const memType = memCfg && typeof memCfg.longTerm === 'object' && memCfg.longTerm.provider === 'deepbrain' ? 'deepbrain' : 'in-memory';
|
|
68
|
+
webChannel.setMemoryType(memType);
|
|
61
69
|
// Wire streaming
|
|
62
70
|
webChannel.onStreamMessage(async (msg, res) => {
|
|
63
71
|
res.writeHead(200, {
|
|
@@ -66,15 +74,18 @@ class AgentRuntime {
|
|
|
66
74
|
Connection: 'keep-alive',
|
|
67
75
|
'Access-Control-Allow-Origin': '*',
|
|
68
76
|
});
|
|
77
|
+
const startTime = Date.now();
|
|
69
78
|
try {
|
|
70
79
|
for await (const chunk of this.agent.handleMessageStream(msg)) {
|
|
71
80
|
res.write(`data: ${JSON.stringify({ content: chunk })}\n\n`);
|
|
72
81
|
}
|
|
73
82
|
res.write('data: [DONE]\n\n');
|
|
83
|
+
this.analytics.recordMessage(Date.now() - startTime);
|
|
74
84
|
}
|
|
75
85
|
catch (err) {
|
|
76
86
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
77
87
|
res.write(`data: ${JSON.stringify({ error: errMsg })}\n\n`);
|
|
88
|
+
this.analytics.recordError();
|
|
78
89
|
}
|
|
79
90
|
res.end();
|
|
80
91
|
});
|
|
@@ -94,6 +105,16 @@ class AgentRuntime {
|
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
await this.agent.init();
|
|
108
|
+
// Wire analytics to agent events
|
|
109
|
+
this.agent.on('message:out', () => {
|
|
110
|
+
// responseTime is approximated; real timing is done via skill/llm events
|
|
111
|
+
});
|
|
112
|
+
this.agent.on('skill:execute', (skillName) => {
|
|
113
|
+
this.analytics.recordSkillUsage(skillName);
|
|
114
|
+
});
|
|
115
|
+
this.agent.on('error', () => {
|
|
116
|
+
this.analytics.recordError();
|
|
117
|
+
});
|
|
97
118
|
this.logger.info('Agent initialized', { name: cfg.metadata.name });
|
|
98
119
|
return this.agent;
|
|
99
120
|
}
|
|
@@ -142,6 +163,12 @@ class AgentRuntime {
|
|
|
142
163
|
getAgent() {
|
|
143
164
|
return this.agent;
|
|
144
165
|
}
|
|
166
|
+
getAnalytics() {
|
|
167
|
+
return this.analytics;
|
|
168
|
+
}
|
|
169
|
+
getConfig() {
|
|
170
|
+
return this.config;
|
|
171
|
+
}
|
|
145
172
|
}
|
|
146
173
|
exports.AgentRuntime = AgentRuntime;
|
|
147
174
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -5,5 +5,5 @@ export interface LLMProvider {
|
|
|
5
5
|
chatStream(messages: Message[], systemPrompt?: string): AsyncIterable<string>;
|
|
6
6
|
}
|
|
7
7
|
export declare function createProvider(name?: string, model?: string, baseUrl?: string, apiKey?: string): LLMProvider;
|
|
8
|
-
export declare const SUPPORTED_PROVIDERS: readonly ["openai", "deepseek", "qwen", "gemini", "dashscope", "zhipu", "moonshot"];
|
|
8
|
+
export declare const SUPPORTED_PROVIDERS: readonly ["openai", "ollama", "deepseek", "qwen", "gemini", "dashscope", "zhipu", "moonshot"];
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/providers/index.js
CHANGED
|
@@ -315,6 +315,12 @@ function isGeminiNative() {
|
|
|
315
315
|
}
|
|
316
316
|
function createProvider(name = 'openai', model, baseUrl, apiKey) {
|
|
317
317
|
const finalModel = model || process.env.OPC_LLM_MODEL || 'gpt-4o-mini';
|
|
318
|
+
// Auto-detect ollama: use localhost:11434/v1 and dummy apiKey
|
|
319
|
+
if (name === 'ollama') {
|
|
320
|
+
const ollamaBase = baseUrl || process.env.OPC_LLM_BASE_URL || 'http://localhost:11434/v1';
|
|
321
|
+
const ollamaKey = apiKey || process.env.OPC_LLM_API_KEY || 'ollama';
|
|
322
|
+
return new OpenAICompatibleProvider('ollama', finalModel, ollamaBase, ollamaKey);
|
|
323
|
+
}
|
|
318
324
|
const finalKey = apiKey || getApiKey();
|
|
319
325
|
const finalBaseUrl = baseUrl || getBaseUrl();
|
|
320
326
|
// Auto-detect Gemini native when key is new format or base URL points to googleapis
|
|
@@ -331,5 +337,5 @@ function createProvider(name = 'openai', model, baseUrl, apiKey) {
|
|
|
331
337
|
}
|
|
332
338
|
return new OpenAICompatibleProvider(resolvedName, finalModel, baseUrl, apiKey);
|
|
333
339
|
}
|
|
334
|
-
exports.SUPPORTED_PROVIDERS = ['openai', 'deepseek', 'qwen', 'gemini', 'dashscope', 'zhipu', 'moonshot'];
|
|
340
|
+
exports.SUPPORTED_PROVIDERS = ['openai', 'ollama', 'deepseek', 'qwen', 'gemini', 'dashscope', 'zhipu', 'moonshot'];
|
|
335
341
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# OPC Agent Examples
|
|
2
|
+
|
|
3
|
+
## Run Examples
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Basic agent with skills
|
|
7
|
+
npx tsx examples/basic-agent.ts
|
|
8
|
+
|
|
9
|
+
# Multi-channel setup (Web + Telegram)
|
|
10
|
+
npx tsx examples/multi-channel.ts
|
|
11
|
+
|
|
12
|
+
# DeepBrain memory integration
|
|
13
|
+
npx tsx examples/brain-integration.ts
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## What Each Example Shows
|
|
17
|
+
|
|
18
|
+
| Example | Concepts |
|
|
19
|
+
|---------|----------|
|
|
20
|
+
| `basic-agent.ts` | `BaseAgent`, `AgentRuntime`, `BaseSkill`, message handling |
|
|
21
|
+
| `multi-channel.ts` | `WebChannel`, `TelegramChannel`, multi-channel config |
|
|
22
|
+
| `brain-integration.ts` | `DeepBrainMemoryStore`, `InMemoryStore`, memory backends |
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPC Agent Example: Basic Agent
|
|
3
|
+
*
|
|
4
|
+
* Create a simple agent with OAD config, register a skill, handle a message.
|
|
5
|
+
*
|
|
6
|
+
* Run: npx tsx examples/basic-agent.ts
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
BaseAgent,
|
|
11
|
+
AgentRuntime,
|
|
12
|
+
BaseSkill,
|
|
13
|
+
InMemoryStore,
|
|
14
|
+
type Message,
|
|
15
|
+
type AgentContext,
|
|
16
|
+
type SkillResult,
|
|
17
|
+
} from 'opc-agent';
|
|
18
|
+
|
|
19
|
+
// Define a custom skill
|
|
20
|
+
class GreeterSkill extends BaseSkill {
|
|
21
|
+
name = 'greeter';
|
|
22
|
+
description = 'Responds to greetings';
|
|
23
|
+
|
|
24
|
+
canHandle(message: Message): boolean {
|
|
25
|
+
const text = message.content.toLowerCase();
|
|
26
|
+
return text.includes('hello') || text.includes('hi') || text.includes('hey');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async execute(message: Message, context: AgentContext): Promise<SkillResult> {
|
|
30
|
+
return {
|
|
31
|
+
content: `Hello! I'm ${context.agent?.name || 'Agent'}. How can I help you today?`,
|
|
32
|
+
confidence: 1.0,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function main() {
|
|
38
|
+
console.log('🤖 OPC Agent — Basic Agent Demo\n');
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
// Create agent with OAD-style config
|
|
42
|
+
const agent = new BaseAgent({
|
|
43
|
+
name: 'demo-agent',
|
|
44
|
+
description: 'A simple demo agent',
|
|
45
|
+
version: '1.0.0',
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Set up memory store
|
|
49
|
+
const memory = new InMemoryStore();
|
|
50
|
+
|
|
51
|
+
// Create runtime
|
|
52
|
+
const runtime = new AgentRuntime(agent, {
|
|
53
|
+
memory,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Register skill
|
|
57
|
+
const greeter = new GreeterSkill();
|
|
58
|
+
runtime.registerSkill(greeter);
|
|
59
|
+
|
|
60
|
+
console.log(`✅ Agent "${agent.name}" created with ${1} skill\n`);
|
|
61
|
+
|
|
62
|
+
// Simulate messages
|
|
63
|
+
const testMessages: Message[] = [
|
|
64
|
+
{ role: 'user', content: 'Hello there!' },
|
|
65
|
+
{ role: 'user', content: 'What can you do?' },
|
|
66
|
+
{ role: 'user', content: 'Hey, nice to meet you' },
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
for (const msg of testMessages) {
|
|
70
|
+
console.log(`📨 User: ${msg.content}`);
|
|
71
|
+
const response = await runtime.handleMessage(msg);
|
|
72
|
+
console.log(`🤖 Agent: ${response?.content || '(no response)'}\n`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log('✅ Done! OPC Agent supports:');
|
|
76
|
+
console.log(' • OAD config (YAML/JSON agent definition)');
|
|
77
|
+
console.log(' • Skill registration & routing');
|
|
78
|
+
console.log(' • Multi-channel (Web, Telegram, Slack, etc.)');
|
|
79
|
+
console.log(' • Memory stores (InMemory, DeepBrain)\n');
|
|
80
|
+
console.log('Next: npx tsx examples/multi-channel.ts');
|
|
81
|
+
} catch (e: any) {
|
|
82
|
+
console.error(`❌ Error: ${e.message}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
main().catch(e => {
|
|
88
|
+
console.error(`\n❌ Error: ${e.message}\n`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPC Agent Example: DeepBrain Memory Integration
|
|
3
|
+
*
|
|
4
|
+
* Shows how to use DeepBrainMemoryStore for persistent agent memory.
|
|
5
|
+
* Requires a running DeepBrain instance (or falls back to InMemory).
|
|
6
|
+
*
|
|
7
|
+
* Run: npx tsx examples/brain-integration.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
BaseAgent,
|
|
12
|
+
AgentRuntime,
|
|
13
|
+
InMemoryStore,
|
|
14
|
+
DeepBrainMemoryStore,
|
|
15
|
+
} from 'opc-agent';
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
console.log('🧠 OPC Agent — DeepBrain Memory Integration\n');
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const agent = new BaseAgent({
|
|
22
|
+
name: 'brain-agent',
|
|
23
|
+
description: 'Agent with DeepBrain-powered memory',
|
|
24
|
+
version: '1.0.0',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Try DeepBrain first, fall back to InMemory
|
|
28
|
+
let memory;
|
|
29
|
+
let memoryType: string;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
memory = new DeepBrainMemoryStore({
|
|
33
|
+
brainUrl: process.env.DEEPBRAIN_URL || 'http://localhost:3333',
|
|
34
|
+
agentId: 'brain-agent',
|
|
35
|
+
});
|
|
36
|
+
memoryType = 'DeepBrain';
|
|
37
|
+
console.log('✅ Using DeepBrain memory store');
|
|
38
|
+
} catch {
|
|
39
|
+
memory = new InMemoryStore();
|
|
40
|
+
memoryType = 'InMemory';
|
|
41
|
+
console.log('⚠️ DeepBrain unavailable, using InMemory fallback');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const runtime = new AgentRuntime(agent, { memory });
|
|
45
|
+
|
|
46
|
+
console.log(`\n📦 Memory store: ${memoryType}`);
|
|
47
|
+
console.log('\nDeepBrain vs InMemory:');
|
|
48
|
+
console.log(' ┌─────────────────┬────────────┬──────────────┐');
|
|
49
|
+
console.log(' │ Feature │ InMemory │ DeepBrain │');
|
|
50
|
+
console.log(' ├─────────────────┼────────────┼──────────────┤');
|
|
51
|
+
console.log(' │ Persistence │ ❌ (RAM) │ ✅ (SQLite) │');
|
|
52
|
+
console.log(' │ Semantic search │ ❌ │ ✅ │');
|
|
53
|
+
console.log(' │ Evolve │ ❌ │ ✅ │');
|
|
54
|
+
console.log(' │ Multi-agent │ ❌ │ ✅ │');
|
|
55
|
+
console.log(' │ Zero config │ ✅ │ ✅ │');
|
|
56
|
+
console.log(' └─────────────────┴────────────┴──────────────┘\n');
|
|
57
|
+
|
|
58
|
+
console.log('✅ Done! To use DeepBrain:');
|
|
59
|
+
console.log(' npm install deepbrain');
|
|
60
|
+
console.log(' deepbrain serve # starts on :3333');
|
|
61
|
+
console.log(' DEEPBRAIN_URL=http://localhost:3333 npx tsx examples/brain-integration.ts\n');
|
|
62
|
+
} catch (e: any) {
|
|
63
|
+
console.error(`❌ Error: ${e.message}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
main().catch(e => {
|
|
69
|
+
console.error(`\n❌ Error: ${e.message}\n`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPC Agent Example: Multi-Channel Setup
|
|
3
|
+
*
|
|
4
|
+
* Shows how to configure Web + Telegram channels for an agent.
|
|
5
|
+
* Note: This is a configuration demo — actual channel connections
|
|
6
|
+
* require valid tokens/endpoints.
|
|
7
|
+
*
|
|
8
|
+
* Run: npx tsx examples/multi-channel.ts
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
BaseAgent,
|
|
13
|
+
AgentRuntime,
|
|
14
|
+
WebChannel,
|
|
15
|
+
TelegramChannel,
|
|
16
|
+
InMemoryStore,
|
|
17
|
+
} from 'opc-agent';
|
|
18
|
+
|
|
19
|
+
async function main() {
|
|
20
|
+
console.log('🌐 OPC Agent — Multi-Channel Demo\n');
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const agent = new BaseAgent({
|
|
24
|
+
name: 'multi-channel-agent',
|
|
25
|
+
description: 'Agent that works across multiple channels',
|
|
26
|
+
version: '1.0.0',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const memory = new InMemoryStore();
|
|
30
|
+
const runtime = new AgentRuntime(agent, { memory });
|
|
31
|
+
|
|
32
|
+
// Channel 1: Web (HTTP endpoint)
|
|
33
|
+
const webChannel = new WebChannel({
|
|
34
|
+
port: 3000,
|
|
35
|
+
path: '/chat',
|
|
36
|
+
});
|
|
37
|
+
console.log('📡 Web channel configured: http://localhost:3000/chat');
|
|
38
|
+
|
|
39
|
+
// Channel 2: Telegram (requires BOT_TOKEN)
|
|
40
|
+
const telegramToken = process.env.TELEGRAM_BOT_TOKEN;
|
|
41
|
+
if (telegramToken) {
|
|
42
|
+
const telegramChannel = new TelegramChannel({
|
|
43
|
+
token: telegramToken,
|
|
44
|
+
});
|
|
45
|
+
runtime.addChannel(telegramChannel);
|
|
46
|
+
console.log('📱 Telegram channel configured');
|
|
47
|
+
} else {
|
|
48
|
+
console.log('📱 Telegram: skipped (set TELEGRAM_BOT_TOKEN to enable)');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Register web channel
|
|
52
|
+
runtime.addChannel(webChannel);
|
|
53
|
+
|
|
54
|
+
console.log('\n✅ Agent configured with channels:');
|
|
55
|
+
console.log(' • Web: HTTP REST endpoint');
|
|
56
|
+
console.log(' • Telegram: Bot API (optional)');
|
|
57
|
+
console.log('\nAvailable channels in OPC Agent:');
|
|
58
|
+
console.log(' WebChannel, TelegramChannel, WebSocketChannel,');
|
|
59
|
+
console.log(' SlackChannel, DiscordChannel, FeishuChannel,');
|
|
60
|
+
console.log(' EmailChannel, WeChatChannel, VoiceChannel,');
|
|
61
|
+
console.log(' WebhookChannel\n');
|
|
62
|
+
|
|
63
|
+
// In production you would call: await runtime.start();
|
|
64
|
+
console.log('💡 To start: await runtime.start()');
|
|
65
|
+
} catch (e: any) {
|
|
66
|
+
console.error(`❌ Error: ${e.message}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main().catch(e => {
|
|
72
|
+
console.error(`\n❌ Error: ${e.message}\n`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|